shithub: pki

ref: a7d243ef71a1b27166c158ba148da2363402f328
dir: /pki.c/

View raw version
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <mp.h>
#include <libsec.h>

#include "pki.h"

CertTab *roottab;
Thumbprint *thumbtab;

static u32int
strhash(char *s)
{
	u32int h;

	h = 33;
	for(; *s; s++)
		h = h*33 + *s;
	return h;
}

CertTab*
mktab(CertTab *up, int nent)
{
	CertTab *tab;
	Issuer **ent;

	tab = malloc(sizeof(CertTab));
	ent = mallocz(nent*sizeof(Issuer*), 1);
	if(tab == nil || ent == nil){
		free(ent);
		free(tab);
		return nil;
	}
	tab->up = up;
	tab->ent = ent;
	tab->nent = nent;
	return tab;
}

static void
freetab(CertTab *tab)
{
	free(tab->ent);
	free(tab);
}

static Issuer*
ctabget(CertTab *tab, char *name)
{
	Issuer *ci;
	u32int h;

	h = strhash(name) % tab->nent;
	for(ci = tab->ent[h]; ci != nil; ci = ci->next)
		if(strcmp(ci->name, name) == 0)
			return ci;
	if(tab->up != nil)
		return ctabget(tab->up, name);
	return nil;
}

int
addcert(CertTab *tab, CertX509 *crt, int isroot)
{
	Issuer *ci;
	CertEnt *c;
	u32int h;

	ci = nil;
	if((c = mallocz(sizeof(CertEnt), 1)) == nil)
		goto Error;
	h = strhash(crt->subject) % tab->nent;
	c->c = crt;
	for(ci = tab->ent[h]; ci != nil; ci = ci->next)
		if(strcmp(ci->name, c->c->subject) == 0)
			goto Found;
	if((ci = mallocz(sizeof(Issuer), 1)) == nil)
		goto Error;
	if((ci->name = strdup(c->c->subject)) == nil)
		goto Error;
	ci->next = tab->ent[h];
	tab->ent[h] = ci;
Found:
	c->isroot = isroot;
	c->next = ci->certs;
	ci->certs = c;
	return 0;
Error:
	free(ci);
	free(c);
	return -1;
}

static int
expired(CertX509 *crt)
{
	vlong now;

	now = time(nil);
	return now < crt->validity_start || now > crt->validity_end;
}

static int
vfsig(CertX509 *crt, CertX509 *vrf)
{
	char *r;

	r = X509verify(crt, vrf);
	if(r == nil || okThumbprint(crt->digest, crt->digestlen, thumbtab))
		return 0;
	werrstr("%s", r);
	return -1;
}

static int
matchesname(CertX509 *crt, CertX509 *vrf)
{
	USED(crt, vrf);
	return 1;
}

static int
vfconstraints(CertX509 *crt, CertX509 *vrf)
{
	if(expired(crt)){
		werrstr("certificate revoked");
		return -1;
	}
	if(!matchesname(crt, vrf)){
		werrstr("name constraint failure");
		return -1;
	}
	return 0;
}

int
vfcert(CertTab *tab, CertX509 *crt)
{
	CertEnt *ce;
	Issuer *ci;

	if((ci = ctabget(tab, crt->spkidigest)) == nil)
		return -1;
	for(ce = ci->certs; ce != nil; ce = ce->next){
		if(vfsig(crt, ce->c) != 0)
			continue;
		if(vfconstraints(crt, ce->c) != 0)
			continue;
		if(!ce->isroot && vfcert(tab, ce->c) == -1)
			continue;
		return 0;
	}
	return -1;
}

void
loadroots(char *path)
{
	PEMChain *pc, *e;
	CertX509 *c;

	if((pc = readcertchain(path)) == nil)
		sysfatal("load pem chain: %r");
	for(e = pc; e != nil; e = e->next){
		if((c = X509decode(e->pem, e->pemlen)) == nil)
			sysfatal("decode cert: %r");
		addcert(roottab, c, 1);
	}
}

void
loadthumbs(char *path)
{
	if((thumbtab = initThumbprints(path, nil, "x509")) == nil)
		sysfatal("load thumbprints: %r");
}