ref: 065d312a1728a00c7a12f8cc64f05b8b210d8426
dir: /libsec.diff/
diff 051804186780ef7f3b2f4cb548be1dd0685de5fe uncommitted --- a/sys/include/libsec.h +++ b/sys/include/libsec.h @@ -1,7 +1,6 @@ #pragma lib "libsec.a" #pragma src "/sys/src/libsec" - #ifndef _MPINT typedef struct mpint mpint; #endif @@ -318,6 +317,7 @@ typedef struct RSApub RSApub; typedef struct RSApriv RSApriv; typedef struct PEMChain PEMChain; +typedef struct CertX509 CertX509; /* public/encryption key */ struct RSApub @@ -347,6 +347,24 @@ int pemlen; }; +struct CertX509 { + int serial; + char* issuer; + vlong validity_start; + vlong validity_end; + char* subject; + char** altsubject; + int naltsubject; + 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 +374,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); @@ -368,7 +389,7 @@ char* X509rsaverify(uchar *cert, int ncert, RSApub *pk); char* X509rsaverifydigest(uchar *sig, int siglen, uchar *edigest, int edigestlen, RSApub *pk); -void X509dump(uchar *cert, int ncert); +void X509dump(int fd, uchar *cert, int ncert); mpint* pkcs1padbuf(uchar *buf, int len, mpint *modulus, int blocktype); int pkcs1unpadbuf(uchar *buf, int len, mpint *modulus, int blocktype); @@ -488,7 +509,51 @@ char *pskID; } TLSconn; +typedef struct TLSClientConf { + uchar *cert; + int ncert; + int noverify; + char *sessiontype; + int (*trace)(char*fmt, ...); + struct { + uchar *key; + int nkey; + char *id; + } psk; + struct { + int nkey; + char *constant; + } ttls; +} TLSClientConf; + +typedef struct TLSServerConf { + PEMChain *certs; + char *sessiontype; + int (*trace)(char*fmt, ...); + struct { + uchar *key; + int nkey; + char *id; + } psk; + struct { + int nkey; + char *constant; + } ttls; +} TLSServerConf; + +typedef struct TLSParams { + char dir[40]; /* connection directory */ + PEMChain *certs; + struct { + uchar *key; + int nkey; + } ttls; +} TLSParams; + /* tlshand.c */ +int tlsclient(int fd, char *srv, TLSClientConf *cfg, TLSParams **pparam); +int tlsserver(int fd, TLSServerConf *cfg, TLSParams **pparam); +void tlsparamfree(TLSParams *p); int tlsClient(int fd, TLSconn *c); int tlsServer(int fd, TLSconn *c); --- a/sys/src/libsec/port/tlshand.c +++ b/sys/src/libsec/port/tlshand.c @@ -91,7 +91,8 @@ int erred; // set when tlsError called int (*trace)(char*fmt, ...); // for debugging int version; // protocol we are speaking - Bytes *cert; // server certificate; only last - no chain + Bytes **certs; // server certificate; only last - no chain + int ncerts; int cipher; int nsecret; // amount of secret data to init keys @@ -406,6 +407,8 @@ static Bytes* pkcs1_decrypt(TlsSec *sec, Bytes *data); static Bytes* pkcs1_sign(TlsSec *sec, uchar *digest, int digestlen, int sigalg); +static int validCert(char *rsrc, PEMChain *pc); + static void* emalloc(int); static void* erealloc(void*, int); static void put32(uchar *p, u32int); @@ -424,6 +427,78 @@ //================= client/server ======================== +int +tlsserver(int fd, TLSServerConf *cfg, TLSParams **pparam) +{ + char buf[8]; + char dname[32]; + uchar seed[2*RandomSize]; + int n, data, ctl, hand; + TlsConnection *tls; + TLSParams *param; + + param = emalloc(sizeof(TLSParams)); + ctl = open("/net/tls/clone", ORDWR|OCEXEC); + if(ctl < 0) + return -1; + n = read(ctl, buf, sizeof(buf)-1); + if(n < 0){ + close(ctl); + return -1; + } + buf[n] = 0; + snprint(param->dir, sizeof(param->dir), "/net/tls/%s", buf); + snprint(dname, sizeof(dname), "/net/tls/%s/hand", buf); + hand = open(dname, ORDWR|OCEXEC); + if(hand < 0){ + close(ctl); + return -1; + } + data = -1; + fprint(ctl, "fd %d 0x%x", fd, ProtocolVersion); + tls = tlsServer2(ctl, hand, + cfg->certs->pem, cfg->certs->pemlen, + cfg->psk.id, cfg->psk.key, cfg->psk.nkey, + cfg->trace, cfg->certs->next); + if(tls != nil){ + snprint(dname, sizeof(dname), "/net/tls/%s/data", buf); + data = open(dname, ORDWR); + } + close(hand); + close(ctl); + if(data < 0){ + tlsparamfree(param); + tlsConnectionFree(tls); + return -1; + } + param->certs = nil; // client certificates are not yet implemented + if(cfg->sessiontype != nil){ + if(strcmp(cfg->sessiontype, "ttls") != 0 || cfg->ttls.nkey == 0){ + werrstr("invalid tls session: %s", cfg->sessiontype); + close(data); + tlsparamfree(param); + tlsConnectionFree(tls); + return -1; + } + param->ttls.key = emalloc(param->ttls.nkey); + memmove(seed, tls->sec->crandom, RandomSize); + memmove(seed+RandomSize, tls->sec->srandom, RandomSize); + tls->sec->prf( + param->ttls.key, param->ttls.nkey, + tls->sec->sec, MasterSecretSize, + cfg->ttls.constant, + seed, sizeof(seed)); + } + tlsConnectionFree(tls); + close(fd); + if(pparam == nil) + tlsparamfree(param); + else + *pparam = param; + return data; + +} + // push TLS onto fd, returning new (application) file descriptor // or -1 if error. int @@ -491,7 +566,7 @@ } static uchar* -tlsClientExtensions(TLSconn *conn, int *plen) +tlsClientExtensions(char *srvname, int *plen) { uchar *b, *p; int i, n, m; @@ -499,7 +574,7 @@ p = b = nil; // RFC6066 - Server Name Identification - if(conn->serverName != nil && (n = strlen(conn->serverName)) > 0){ + if(srvname != nil && (n = strlen(srvname)) > 0){ m = p - b; b = erealloc(b, m + 2+2+2+1+2+n); p = b + m; @@ -509,7 +584,7 @@ put16(p, 1+2+n), p += 2; /* Server Name list length */ *p++ = 0; /* Server Name Type: host_name */ put16(p, n), p += 2; /* Server Name length */ - memmove(p, conn->serverName, n); + memmove(p, srvname, n); p += n; } @@ -557,6 +632,118 @@ return b; } +int +tlsclient(int fd, char *srvname, TLSClientConf *cfg, TLSParams **pparam) +{ + char buf[8]; + char dname[32]; + uchar seed[2*RandomSize]; + int i, n, data, ctl, hand; + TlsConnection *tls; + TLSParams *param; + PEMChain *pc, **ppc; + uchar *ext; + + param = emalloc(sizeof(TLSParams)); + ctl = open("/net/tls/clone", ORDWR|OCEXEC); + if(ctl < 0) + return -1; + n = read(ctl, buf, sizeof(buf)-1); + if(n < 0){ + close(ctl); + return -1; + } + buf[n] = 0; + snprint(param->dir, sizeof(param->dir), "/net/tls/%s", buf); + snprint(dname, sizeof(dname), "/net/tls/%s/hand", buf); + hand = open(dname, ORDWR|OCEXEC); + if(hand < 0){ + close(ctl); + return -1; + } + snprint(dname, sizeof(dname), "/net/tls/%s/data", buf); + data = open(dname, ORDWR); + if(data < 0){ + close(hand); + close(ctl); + return -1; + } + fprint(ctl, "fd %d 0x%x", fd, ProtocolVersion); + ext = tlsClientExtensions(srvname, &n); + tls = tlsClient2(ctl, hand, + cfg->cert, cfg->ncert, + cfg->psk.id, cfg->psk.key, cfg->psk.nkey, + ext, n, cfg->trace); + free(ext); + close(hand); + close(ctl); + if(tls == nil){ + tlsparamfree(param); + close(data); + return -1; + } +fprint(2, "certs: %#p, ncerts: %d\n", tls->certs, tls->ncerts); + if(tls->certs != nil){ + ppc = ¶m->certs; + for(i = 0; i < tls->ncerts; i++){ +fprint(2, "add cert [%d]\n", i); + pc = emalloc(sizeof(PEMChain) + tls->certs[i]->len); + pc->next = nil; + pc->pem = (uchar*)(pc+1); + pc->pemlen = tls->certs[i]->len; + memcpy(pc->pem, tls->certs[i]->data, pc->pemlen); + *ppc = pc; + ppc = &pc->next; + } + } else { + param->certs = nil; + } + param->ttls.nkey = cfg->ttls.nkey; + if(cfg->sessiontype != nil){ + if(strcmp(cfg->sessiontype, "ttls") != 0 || cfg->ttls.nkey == 0){ + werrstr("invalid tls session: %s", cfg->sessiontype); + tlsparamfree(param); + close(data); + return -1; + } + param->ttls.key = emalloc(param->ttls.nkey); + memmove(seed, tls->sec->crandom, RandomSize); + memmove(seed+RandomSize, tls->sec->srandom, RandomSize); + tls->sec->prf( + param->ttls.key, param->ttls.nkey, + tls->sec->sec, MasterSecretSize, + cfg->ttls.constant, + seed, sizeof(seed)); + } + tlsConnectionFree(tls); + close(fd); + if(cfg->noverify == 0 + && cfg->psk.key == nil + && validCert("orib.dev", param->certs) == 0){ + tlsparamfree(param); + close(data); + return -1; + } + if(pparam == nil) + tlsparamfree(param); + else + *pparam = param; + return data; +} + +void +tlsparamfree(TLSParams *param) +{ + PEMChain *pc, *pn; + + for(pc = param->certs; pc != nil; pc = pn){ + pn = pc->next; + free(pc); + } + free(param->ttls.key); + free(param); +} + // push TLS onto fd, returning new (application) file descriptor // or -1 if error. int @@ -595,7 +782,7 @@ return -1; } fprint(ctl, "fd %d 0x%x", fd, ProtocolVersion); - ext = tlsClientExtensions(conn, &n); + ext = tlsClientExtensions(conn->serverName, &n); tls = tlsClient2(ctl, hand, conn->cert, conn->certlen, conn->pskID, conn->psk, conn->psklen, @@ -608,10 +795,10 @@ return -1; } free(conn->cert); - if(tls->cert != nil){ - conn->certlen = tls->cert->len; + if(tls->certs != nil){ + conn->certlen = tls->certs[0]->len; conn->cert = emalloc(conn->certlen); - memcpy(conn->cert, tls->cert->data, conn->certlen); + memcpy(conn->cert, tls->certs[0]->data, conn->certlen); } else { conn->certlen = 0; conn->cert = nil; @@ -1042,7 +1229,7 @@ uchar *ext, int extlen, int (*trace)(char*fmt, ...)) { - int creq, dhx, cipher; + int i, creq, dhx, cipher; TlsConnection *c; Bytes *epm; Msg m; @@ -1057,7 +1244,7 @@ c->ctl = ctl; c->hand = hand; c->trace = trace; - c->cert = nil; + c->certs = nil; c->sendp = c->buf; c->version = ProtocolVersion; @@ -1118,11 +1305,15 @@ if(!msgRecv(c, &m)) goto Err; if(m.tag == HCertificate){ +fprint(2, "here! %d\n", m.u.certificate.ncert); if(m.u.certificate.ncert < 1) { tlsError(c, EIllegalParameter, "runt certificate"); goto Err; } - c->cert = makebytes(m.u.certificate.certs[0]->data, m.u.certificate.certs[0]->len); + c->ncerts = m.u.certificate.ncert; + c->certs = emalloc(c->ncerts * sizeof(Bytes*)); + for(i = 0; i < c->ncerts; i++) + c->certs[i] = makebytes(m.u.certificate.certs[i]->data, m.u.certificate.certs[i]->len); if(!msgRecv(c, &m)) goto Err; } else if(psklen == 0) { @@ -1133,7 +1324,7 @@ if(dhx){ char *err = verifyDHparams(c->sec, m.u.serverKeyExchange.dh_parameters, - c->cert, + c->certs[0], m.u.serverKeyExchange.dh_signature, c->version<TLS12Version ? 0x01 : m.u.serverKeyExchange.sigalg); if(err != nil){ @@ -1179,8 +1370,8 @@ msgClear(&m); if(!dhx){ - if(c->cert != nil){ - epm = tlsSecRSAc(c->sec, c->cert->data, c->cert->len); + if(c->certs != nil){ + epm = tlsSecRSAc(c->sec, c->certs[0]->data, c->certs[0]->len); if(epm == nil){ tlsError(c, EBadCertificate, "bad certificate: %r"); goto Err; @@ -2100,11 +2291,12 @@ static void tlsConnectionFree(TlsConnection *c) { + int i; + if(c == nil) return; dh_finish(&c->sec->dh, nil); - mpfree(c->sec->ec.Q.x); mpfree(c->sec->ec.Q.y); mpfree(c->sec->ec.Q.d); @@ -2112,12 +2304,58 @@ factotum_rsa_close(c->sec->rpc); rsapubfree(c->sec->rsapub); - freebytes(c->cert); + for(i = 0; i < c->ncerts; i++) + freebytes(c->certs[i]); + free(c->certs); memset(c, 0, sizeof(*c)); free(c); } +static int +validCert(char *host, PEMChain *pc) +{ + char *q, *t, buf[64]; + PEMChain *e; + int n, fd, r; + +print("host: %s\n", host); + if(host == nil) + return 0; + if((fd = open("/mnt/pki/new", ORDWR)) == -1) + return 0; + q = quotestrdup(host); + fprint(fd, "verify host %s", q); + free(q); + + t = "cert"; + for(e = pc; e != nil; e = e->next){ +fprint(2, "%s der %d\n", t, e->pemlen); + if((r = fprint(fd, "%s der %d\n", t, e->pemlen)) == -1){ +fprint(2, "nope0[%d]: %r", r); + close(fd); + return 0; + } + if((write(fd, e->pem, e->pemlen)) != e->pemlen){ +fprint(2, "nope1: %r"); + close(fd); + return 0; + } + t = "icert"; + } + fprint(fd, "done\n"); + if((n = pread(fd, buf, sizeof(buf)-1, 0)) == -1){ + close(fd); + return 0; + } + buf[n] = 0; + close(fd); + if(strcmp(buf, "accept") != 0){ + werrstr("cert validation failed: %s", buf); + return 0; + } + return 1; +} //================= cipher choices ======================== --- 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; } @@ -3227,60 +3259,55 @@ } void -X509dump(uchar *cert, int ncert) +X509dump(int fd, 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); + fprint(fd, "begin X509dump\n"); + c = X509decode(cert, ncert); if(c == nil){ - print("cannot decode cert\n"); + fprint(fd, "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; + fprint(fd, "serial %d\n", c->serial); + fprint(fd, "issuer %s\n", c->issuer); + fprint(fd, "validity %lld %lld\n", c->validity_start, c->validity_end); + fprint(fd, "subject %s\n", c->subject); + fprint(fd, "sigalg=%d digest=%.*H\n", c->signature_alg, c->digestlen, c->digest); + fprint(fd, "publickey_alg=%d pubkey[%d] %.*H\n", c->publickey_alg, pk->len, + pk->len, pk->data); - print("serial %d\n", c->serial); - print("issuer %s\n", c->issuer); - print("validity %s %s\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); - 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); + fprint(fd, "rsa pubkey e=%B n(%d)=%B\n", rsapub->ek, mpsignif(rsapub->n), rsapub->n); + 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); + fprint(fd, "self-signed X509rsaverifydigest returns: %s\n", e); rsapubfree(rsapub); } 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); + fprint(fd, "self-signed X509ecdsaverifydigest returns: %s\n", e); ecpubfree(ecpub); } ecdomfree(&ecdom); @@ -3287,15 +3314,15 @@ 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); + fprint(fd, "publickey_thumbprint sha256=%.*[\n", SHA2_256dlen, c->digest); sha2_256(cert, ncert, digest, nil); - print("cert_thumbprint sha256=%.*[\n", SHA2_256dlen, digest); + fprint(fd, "cert_thumbprint sha256=%.*[\n", SHA2_256dlen, digest); sha1(cert, ncert, digest, nil); - print("cert_thumbprint sha1=%.*H\n", SHA1dlen, digest); + fprint(fd, "cert_thumbprint sha1=%.*H\n", SHA1dlen, digest); - freecert(c); - print("end X509dump\n"); + X509free(c); + fprint(fd, "end X509dump\n"); }