ref: 22a5a98241a10902152b66dde3cb3d9682c83b21
dir: /libsec.diff/
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"); }