shithub: pki

ref: 22a5a98241a10902152b66dde3cb3d9682c83b21
dir: /libsec.diff/

View raw version
diff 5a39d5532beb8f49ef0cbd0a260d7248787952f9 uncommitted
--- a/sys/include/libsec.h
+++ b/sys/include/libsec.h
@@ -1,11 +1,6 @@
 #pragma	lib	"libsec.a"
 #pragma	src	"/sys/src/libsec"
 
-
-#ifndef _MPINT
-typedef struct mpint mpint;
-#endif
-
 /*
  * AES definitions
  */
@@ -318,6 +313,7 @@
 typedef struct RSApub RSApub;
 typedef struct RSApriv RSApriv;
 typedef struct PEMChain PEMChain;
+typedef struct CertX509 CertX509;
 
 /* public/encryption key */
 struct RSApub
@@ -347,6 +343,22 @@
 	int	pemlen;
 };
 
+struct CertX509 {
+	int	serial;
+	char*	issuer;
+	vlong	validity_start;
+	vlong	validity_end;
+	char*	subject;
+	int	publickey_alg;
+	void*	publickey;
+	int	signature_alg;
+	void*	signature;
+	int	curve;
+	void*	ext;
+	uchar	digest[SHA2_512dlen];
+	int	digestlen;
+};
+
 RSApriv*	rsagen(int nlen, int elen, int rounds);
 RSApriv*	rsafill(mpint *n, mpint *e, mpint *d, mpint *p, mpint *q);
 mpint*		rsaencrypt(RSApub *k, mpint *in, mpint *out);
@@ -356,6 +368,9 @@
 RSApriv*	rsaprivalloc(void);
 void		rsaprivfree(RSApriv*);
 RSApub*		rsaprivtopub(RSApriv*);
+char*		X509verify(CertX509*, CertX509*);
+CertX509*	X509decode(uchar*, int);
+void		X509free(CertX509*);
 RSApub*		X509toRSApub(uchar*, int, char*, int);
 RSApub*		X509reqtoRSApub(uchar*, int, char*, int);
 RSApub*		asn1toRSApub(uchar*, int);
@@ -476,6 +491,8 @@
 	uchar	*sessionID;
 	uchar	*psk;
 	int	certlen;
+	uchar	**certchain;
+	int	*certchainlen;
 	int	sessionIDlen;
 	int	psklen;
 	int	(*trace)(char*fmt, ...);
--- a/sys/src/libsec/port/x509.c
+++ b/sys/src/libsec/port/x509.c
@@ -128,7 +128,7 @@
 static int	is_octetstring(Elem* pe, Bytes** poctets);
 static int	is_oid(Elem* pe, Ints** poid);
 static int	is_string(Elem* pe, char** pstring);
-static int	is_time(Elem* pe, char** ptime);
+static int	parse_time(Elem* pe, vlong* ptime);
 static int	decode(uchar* a, int alen, Elem* pelem);
 static int	encode(Elem e, Bytes** pbytes);
 static int	oid_lookup(Ints* o, Ints** tab);
@@ -1277,15 +1277,24 @@
 }
 
 static int
-is_time(Elem* pe, char** ptime)
+parse_time(Elem* pe, vlong* ptime)
 {
-	if(pe->tag.class == Universal
-	   && (pe->tag.num == UTCTime || pe->tag.num == GeneralizedTime)
-	   && pe->val.tag == VString) {
-		*ptime = pe->val.u.stringval;
-		return 1;
+	char *e, *fmt;
+	Tm t;
+
+	if(pe->tag.class != Universal)
+		return 0;
+	if(pe->val.tag != VString)
+		return 0;
+	switch(pe->tag.num){
+	case UTCTime:		fmt = "YYMMDDhhmmss?Z";	break;
+	case GeneralizedTime:	fmt = "YYYYMMDDhhmmss?Z";	break;
+	default:		return 0;		break;
 	}
-	return 0;
+	if(tmparse(&t, fmt, pe->val.u.stringval, nil, &e) == nil)
+		return 0;
+	*ptime = tmnorm(&t);
+	return 1;
 }
 
 
@@ -1581,20 +1590,6 @@
  *           revocationDate UTCTime}
  */
 
-typedef struct CertX509 {
-	int	serial;
-	char*	issuer;
-	char*	validity_start;
-	char*	validity_end;
-	char*	subject;
-	int	publickey_alg;
-	Bits*	publickey;
-	int	signature_alg;
-	Bits*	signature;
-	int	curve;
-	Bytes*	ext;
-} CertX509;
-
 /* Algorithm object-ids */
 enum {
 	ALG_rsaEncryption,
@@ -1730,14 +1725,12 @@
 
 static void appendaltnames(char *name, int nname, Bytes *ext, int req);
 
-static void
-freecert(CertX509* c)
+void
+X509free(CertX509* c)
 {
 	if(c == nil)
 		return;
 	free(c->issuer);
-	free(c->validity_start);
-	free(c->validity_end);
 	free(c->subject);
 	freebits(c->publickey);
 	freebits(c->signature);
@@ -1791,7 +1784,7 @@
 		el = el->tl;
 	}
 	if(i > 0) {
-		ans = (char*)emalloc(plen);
+		ans = emalloc(plen);
 		*ans = '\0';
 		while(--i >= 0) {
 			s = parts[i];
@@ -1833,154 +1826,6 @@
 	return oid_lookup(oid, namedcurves_oid_tab);
 }
 
-static CertX509*
-decode_cert(uchar *buf, int len)
-{
-	int ok = 0;
-	int n;
-	Elem  ecert;
-	Elem* ecertinfo;
-	Elem* esigalg;
-	Elem* esig;
-	Elem* eserial;
-	Elem* eissuer;
-	Elem* evalidity;
-	Elem* esubj;
-	Elem* epubkey;
-	Elist* el;
-	Elist* elcert = nil;
-	Elist* elcertinfo = nil;
-	Elist* elvalidity = nil;
-	Elist* elpubkey = nil;
-	Bits* bits = nil;
-	Bytes* b;
-	Elem* e;
-	CertX509* c = nil;
-
-	if(decode(buf, len, &ecert) != ASN_OK)
-		goto errret;
-
-	c = (CertX509*)emalloc(sizeof(CertX509));
-	c->serial = -1;
-	c->issuer = nil;
-	c->validity_start = nil;
-	c->validity_end = nil;
-	c->subject = nil;
-	c->publickey_alg = -1;
-	c->publickey = nil;
-	c->signature_alg = -1;
-	c->signature = nil;
-	c->ext = nil;
-
-	/* Certificate */
- 	if(!is_seq(&ecert, &elcert) || elistlen(elcert) !=3)
-		goto errret;
- 	ecertinfo = &elcert->hd;
- 	el = elcert->tl;
- 	esigalg = &el->hd;
-	c->signature_alg = parse_alg(esigalg);
- 	el = el->tl;
- 	esig = &el->hd;
-
-	/* Certificate Info */
-	if(!is_seq(ecertinfo, &elcertinfo))
-		goto errret;
-	n = elistlen(elcertinfo);
-  	if(n < 6)
-		goto errret;
-	eserial =&elcertinfo->hd;
- 	el = elcertinfo->tl;
- 	/* check for optional version, marked by explicit context tag 0 */
-	if(eserial->tag.class == Context && eserial->tag.num == 0) {
- 		eserial = &el->hd;
- 		if(n < 7)
- 			goto errret;
- 		el = el->tl;
- 	}
-
-	if(parse_alg(&el->hd) != c->signature_alg)
-		goto errret;
- 	el = el->tl;
- 	eissuer = &el->hd;
- 	el = el->tl;
- 	evalidity = &el->hd;
- 	el = el->tl;
- 	esubj = &el->hd;
- 	el = el->tl;
- 	epubkey = &el->hd;
-	if(el->tl != nil
-	&& el->tl->hd.tag.class == Context
-	&& el->tl->hd.tag.num == 3
-	&& el->tl->hd.val.tag == VOctets){
-		c->ext = el->tl->hd.val.u.octetsval;
-		el->tl->hd.val.u.octetsval = nil;	/* transfer ownership */
-	}
-	if(!is_int(eserial, &c->serial)) {
-		if(!is_bigint(eserial, &b))
-			goto errret;
-		c->serial = -1;	/* else we have to change cert struct */
-  	}
-	c->issuer = parse_name(eissuer);
-	if(c->issuer == nil)
-		goto errret;
-	/* Validity */
-  	if(!is_seq(evalidity, &elvalidity))
-		goto errret;
-	if(elistlen(elvalidity) != 2)
-		goto errret;
-	e = &elvalidity->hd;
-	if(!is_time(e, &c->validity_start))
-		goto errret;
-	e->val.u.stringval = nil;	/* string ownership transfer */
-	e = &elvalidity->tl->hd;
- 	if(!is_time(e, &c->validity_end))
-		goto errret;
-	e->val.u.stringval = nil;	/* string ownership transfer */
-
-	/* resume CertificateInfo */
- 	c->subject = parse_name(esubj);
-	if(c->subject == nil)
-		goto errret;
-
-	/* SubjectPublicKeyInfo */
-	if(!is_seq(epubkey, &elpubkey))
-		goto errret;
-	if(elistlen(elpubkey) != 2)
-		goto errret;
-
-	c->publickey_alg = parse_alg(&elpubkey->hd);
-	if(c->publickey_alg < 0)
-		goto errret;
-	c->curve = -1;
-	if(c->publickey_alg == ALG_ecPublicKey){
-		c->curve = parse_curve(&elpubkey->hd);
-		if(c->curve < 0)
-			goto errret;
-	}
-	elpubkey = elpubkey->tl;
-	if(!is_bitstring(&elpubkey->hd, &bits))
-		goto errret;
-	elpubkey->hd.val.u.bitstringval = nil;	/* transfer ownership */
-	c->publickey = bits;
-
-	/*resume Certificate */
-	if(c->signature_alg < 0)
-		goto errret;
-	if(!is_bitstring(esig, &bits))
-		goto errret;
-	esig->val.u.bitstringval = nil;	/* transfer ownership */
-	c->signature = bits;
-	ok = 1;
-
-errret:
-	freevalfields(&ecert.val);	/* recurses through lists, too */
-	if(!ok){
-		freecert(c);
-		c = nil;
-	}
-	return c;
-}
-
 /*
  *	RSAPublickKey ::= SEQUENCE {
  *		modulus INTEGER,
@@ -2187,6 +2032,156 @@
 
 static char Ebadsig[] = "bad signature";
 
+CertX509*
+X509decode(uchar *buf, int len)
+{
+	int ok = 0;
+	int n;
+	Elem  ecert;
+	Elem* ecertinfo;
+	Elem* esigalg;
+	Elem* esig;
+	Elem* eserial;
+	Elem* eissuer;
+	Elem* evalidity;
+	Elem* esubj;
+	Elem* epubkey;
+	Elist* el;
+	Elist* elcert = nil;
+	Elist* elcertinfo = nil;
+	Elist* elvalidity = nil;
+	Elist* elpubkey = nil;
+	Bits* bits = nil;
+	Bytes* b;
+	Elem* e;
+	CertX509* c = nil;
+
+	if(decode(buf, len, &ecert) != ASN_OK)
+		goto errret;
+
+	c = (CertX509*)emalloc(sizeof(CertX509));
+	c->serial = -1;
+	c->issuer = nil;
+	c->validity_start = -1;
+	c->validity_end = -1;
+	c->subject = nil;
+	c->altsubject = nil;
+	c->publickey_alg = -1;
+	c->publickey = nil;
+	c->signature_alg = -1;
+	c->signature = nil;
+	c->ext = nil;
+
+	/* Certificate */
+ 	if(!is_seq(&ecert, &elcert) || elistlen(elcert) !=3)
+		goto errret;
+ 	ecertinfo = &elcert->hd;
+ 	el = elcert->tl;
+ 	esigalg = &el->hd;
+	c->signature_alg = parse_alg(esigalg);
+ 	el = el->tl;
+ 	esig = &el->hd;
+
+	/* Certificate Info */
+	if(!is_seq(ecertinfo, &elcertinfo))
+		goto errret;
+	n = elistlen(elcertinfo);
+  	if(n < 6)
+		goto errret;
+	eserial =&elcertinfo->hd;
+ 	el = elcertinfo->tl;
+ 	/* check for optional version, marked by explicit context tag 0 */
+	if(eserial->tag.class == Context && eserial->tag.num == 0) {
+ 		eserial = &el->hd;
+ 		if(n < 7)
+ 			goto errret;
+ 		el = el->tl;
+ 	}
+
+	if(parse_alg(&el->hd) != c->signature_alg)
+		goto errret;
+ 	el = el->tl;
+ 	eissuer = &el->hd;
+ 	el = el->tl;
+ 	evalidity = &el->hd;
+ 	el = el->tl;
+ 	esubj = &el->hd;
+ 	el = el->tl;
+ 	epubkey = &el->hd;
+	if(el->tl != nil
+	&& el->tl->hd.tag.class == Context
+	&& el->tl->hd.tag.num == 3
+	&& el->tl->hd.val.tag == VOctets){
+		c->ext = el->tl->hd.val.u.octetsval;
+		el->tl->hd.val.u.octetsval = nil;	/* transfer ownership */
+	}
+	if(!is_int(eserial, &c->serial)) {
+		if(!is_bigint(eserial, &b))
+			goto errret;
+		c->serial = -1;	/* else we have to change cert struct */
+  	}
+	c->issuer = parse_name(eissuer);
+	if(c->issuer == nil)
+		goto errret;
+	/* Validity */
+  	if(!is_seq(evalidity, &elvalidity))
+		goto errret;
+	if(elistlen(elvalidity) != 2)
+		goto errret;
+	e = &elvalidity->hd;
+	if(!parse_time(e, &c->validity_start))
+		goto errret;
+	e = &elvalidity->tl->hd;
+ 	if(!parse_time(e, &c->validity_end))
+		goto errret;
+
+	/* resume CertificateInfo */
+ 	c->subject = parse_name(esubj);
+	if(c->subject == nil)
+		goto errret;
+
+	/* SubjectPublicKeyInfo */
+	if(!is_seq(epubkey, &elpubkey))
+		goto errret;
+	if(elistlen(elpubkey) != 2)
+		goto errret;
+
+	c->publickey_alg = parse_alg(&elpubkey->hd);
+	if(c->publickey_alg < 0)
+		goto errret;
+	c->curve = -1;
+	if(c->publickey_alg == ALG_ecPublicKey){
+		c->curve = parse_curve(&elpubkey->hd);
+		if(c->curve < 0)
+			goto errret;
+	}
+	elpubkey = elpubkey->tl;
+	if(!is_bitstring(&elpubkey->hd, &bits))
+		goto errret;
+	elpubkey->hd.val.u.bitstringval = nil;	/* transfer ownership */
+	c->publickey = bits;
+
+	/*resume Certificate */
+	if(c->signature_alg < 0)
+		goto errret;
+	if(!is_bitstring(esig, &bits))
+		goto errret;
+	esig->val.u.bitstringval = nil;	/* transfer ownership */
+	c->signature = bits;
+	c->digestlen = digest_certinfo(buf, len, digestalg[c->signature_alg], c->digest);
+	if(c->digestlen < 0)
+		goto errret;
+	ok = 1;
+
+errret:
+	freevalfields(&ecert.val);	/* recurses through lists, too */
+	if(!ok){
+		X509free(c);
+		c = nil;
+	}
+	return c;
+}
+
 char*
 X509rsaverifydigest(uchar *sig, int siglen, uchar *edigest, int edigestlen, RSApub *pk)
 {
@@ -2288,8 +2283,9 @@
 {
 	CertX509 *c;
 	ECpub *pub;
+	Bits *pk;
 
-	c = decode_cert(cert, ncert);
+	c = X509decode(cert, ncert);
 	if(c == nil)
 		return nil;
 	copysubject(name, nname, c->subject);
@@ -2297,11 +2293,12 @@
 	pub = nil;
 	if(c->publickey_alg == ALG_ecPublicKey){
 		ecdominit(dom, namedcurves[c->curve]);
-		pub = ecdecodepub(dom, c->publickey->data, c->publickey->len);
+		pk = c->publickey;
+		pub = ecdecodepub(dom, pk->data, pk->len);
 		if(pub == nil)
 			ecdomfree(dom);
 	}
-	freecert(c);
+	X509free(c);
 	return pub;
 }
 
@@ -2309,20 +2306,22 @@
 X509ecdsaverify(uchar *cert, int ncert, ECdomain *dom, ECpub *pk)
 {
 	char *e;
+	Bits *sig;
 	CertX509 *c;
 	int digestlen;
 	uchar digest[MAXdlen];
 
-	c = decode_cert(cert, ncert);
+	c = X509decode(cert, ncert);
 	if(c == nil)
 		return "cannot decode cert";
 	digestlen = digest_certinfo(cert, ncert, digestalg[c->signature_alg], digest);
 	if(digestlen <= 0){
-		freecert(c);
+		X509free(c);
 		return "cannot decode certinfo";
 	}
-	e = X509ecdsaverifydigest(c->signature->data, c->signature->len, digest, digestlen, dom, pk);
-	freecert(c);
+	sig = c->signature;
+	e = X509ecdsaverifydigest(sig->data, sig->len, digest, digestlen, dom, pk);
+	X509free(c);
 	return e;
 }
 
@@ -2331,40 +2330,71 @@
 {
 	CertX509 *c;
 	RSApub *pub;
+	Bits *pk;
 
-	c = decode_cert(cert, ncert);
+	c = X509decode(cert, ncert);
 	if(c == nil)
 		return nil;
 	copysubject(name, nname, c->subject);
 	appendaltnames(name, nname, c->ext, 0);
 	pub = nil;
+	pk = c->publickey;
 	if(c->publickey_alg == ALG_rsaEncryption)
-		pub = asn1toRSApub(c->publickey->data, c->publickey->len);
-	freecert(c);
+		pub = asn1toRSApub(pk->data, pk->len);
+	X509free(c);
 	return pub;
 }
 
-char*
+char*	
 X509rsaverify(uchar *cert, int ncert, RSApub *pk)
 {
 	char *e;
+	Bits *sig;
 	CertX509 *c;
 	int digestlen;
 	uchar digest[MAXdlen];
 
-	c = decode_cert(cert, ncert);
+	c = X509decode(cert, ncert);
 	if(c == nil)
 		return "cannot decode cert";
 	digestlen = digest_certinfo(cert, ncert, digestalg[c->signature_alg], digest);
 	if(digestlen <= 0){
-		freecert(c);
+		X509free(c);
 		return "cannot decode certinfo";
 	}
-	e = X509rsaverifydigest(c->signature->data, c->signature->len, digest, digestlen, pk);
-	freecert(c);
+	sig = c->signature;
+	e = X509rsaverifydigest(sig->data, sig->len, digest, digestlen, pk);
+	X509free(c);
 	return e;
 }
 
+char*
+X509verify(CertX509 *crt, CertX509 *vrf)
+{
+	RSApub *rsapub;
+	ECpub *ecpub;
+	ECdomain ecdom;
+	Bits *pk, *sig;
+	char *e;
+
+	e = "unknown algorithm";
+	pk = vrf->publickey;
+	sig = crt->signature;
+	switch(vrf->publickey_alg){
+	case ALG_rsaEncryption:
+		rsapub = asn1toRSApub(pk->data, pk->len);
+		e = X509rsaverifydigest(sig->data, sig->len, crt->digest, crt->digestlen, rsapub);
+		break;
+	case ALG_ecPublicKey:
+		ecdominit(&ecdom, namedcurves[vrf->curve]);
+		ecpub = ecdecodepub(&ecdom, pk->data, pk->len);
+		e = X509ecdsaverifydigest(sig->data, sig->len, crt->digest, crt->digestlen, &ecdom, ecpub);
+		ecdomfree(&ecdom);
+		break;
+	}
+	return e;
+}
+
 /* ------- Elem constructors ---------- */
 static Elem
 Null(void)
@@ -3125,14 +3155,16 @@
 X509digestSPKI(uchar *cert, int ncert, DigestState* (*fun)(uchar*, ulong, uchar*, DigestState*), uchar *digest)
 {
 	CertX509 *c;
+	Bits *pk;
 
-	c = decode_cert(cert, ncert);
+	c = X509decode(cert, ncert);
 	if(c == nil){
 		werrstr("cannot decode cert");
 		return -1;
 	}
-	digestSPKI(c->publickey_alg, c->publickey->data, c->publickey->len, fun, digest);
-	freecert(c);
+	pk = c->publickey;
+	digestSPKI(c->publickey_alg, pk->data, pk->len, fun, digest);
+	X509free(c);
 	return 0;
 }
 
@@ -3230,42 +3262,37 @@
 X509dump(uchar *cert, int ncert)
 {
 	char *e;
+	Bits *pk, *sig;
 	CertX509 *c;
 	RSApub *rsapub;
 	ECpub *ecpub;
 	ECdomain ecdom;
-	int digestlen;
 	uchar digest[MAXdlen];
 
 	print("begin X509dump\n");
-	c = decode_cert(cert, ncert);
+	c = X509decode(cert, ncert);
 	if(c == nil){
 		print("cannot decode cert\n");
 		return;
 	}
 
-	digestlen = digest_certinfo(cert, ncert, digestalg[c->signature_alg], digest);
-	if(digestlen <= 0){
-		freecert(c);
-		print("cannot decode certinfo\n");
-		return;
-	}
-
+	pk = c->publickey;
+	sig = c->signature;
 	print("serial %d\n", c->serial);
 	print("issuer %s\n", c->issuer);
-	print("validity %s %s\n", c->validity_start, c->validity_end);
+	print("validity %lld %lld\n", c->validity_start, c->validity_end);
 	print("subject %s\n", c->subject);
-	print("sigalg=%d digest=%.*H\n", c->signature_alg, digestlen, digest);
-	print("publickey_alg=%d pubkey[%d] %.*H\n", c->publickey_alg, c->publickey->len,
-		c->publickey->len, c->publickey->data);
+	print("sigalg=%d digest=%.*H\n", c->signature_alg, c->digestlen, c->digest);
+	print("publickey_alg=%d pubkey[%d] %.*H\n", c->publickey_alg, pk->len,
+		pk->len, pk->data);
 
 	switch(c->publickey_alg){
 	case ALG_rsaEncryption:
-		rsapub = asn1toRSApub(c->publickey->data, c->publickey->len);
+		rsapub = asn1toRSApub(pk->data, pk->len);
 		if(rsapub != nil){
 			print("rsa pubkey e=%B n(%d)=%B\n", rsapub->ek, mpsignif(rsapub->n), rsapub->n);
-			e = X509rsaverifydigest(c->signature->data, c->signature->len,
-				digest, digestlen, rsapub);
+			e = X509rsaverifydigest(sig->data, sig->len,
+				c->digest, c->digestlen, rsapub);
 			if(e==nil)
 				e = "nil (meaning ok)";
 			print("self-signed X509rsaverifydigest returns: %s\n", e);
@@ -3274,10 +3301,10 @@
 		break;
 	case ALG_ecPublicKey:
 		ecdominit(&ecdom, namedcurves[c->curve]);
-		ecpub = ecdecodepub(&ecdom, c->publickey->data, c->publickey->len);
+		ecpub = ecdecodepub(&ecdom, pk->data, pk->len);
 		if(ecpub != nil){
-			e = X509ecdsaverifydigest(c->signature->data, c->signature->len,
-				digest, digestlen, &ecdom, ecpub);
+			e = X509ecdsaverifydigest(sig->data, sig->len,
+				c->digest, c->digestlen, &ecdom, ecpub);
 			if(e==nil)
 				e = "nil (meaning ok)";
 			print("self-signed X509ecdsaverifydigest returns: %s\n", e);
@@ -3287,8 +3314,8 @@
 		break;
 	}
 
-	digestSPKI(c->publickey_alg, c->publickey->data, c->publickey->len, sha2_256, digest);
-	print("publickey_thumbprint sha256=%.*[\n", SHA2_256dlen, digest);
+	digestSPKI(c->publickey_alg, pk->data, pk->len, sha2_256, c->digest);
+	print("publickey_thumbprint sha256=%.*[\n", SHA2_256dlen, c->digest);
 
 	sha2_256(cert, ncert, digest, nil);
 	print("cert_thumbprint sha256=%.*[\n", SHA2_256dlen, digest);
@@ -3296,6 +3323,6 @@
 	sha1(cert, ncert, digest, nil);
 	print("cert_thumbprint sha1=%.*H\n", SHA1dlen, digest);
 
-	freecert(c);
+	X509free(c);
 	print("end X509dump\n");
 }