ref: 22a5a98241a10902152b66dde3cb3d9682c83b21
parent: 28981fdd9499edc1223e393204d5b735c2210a2c
author: Ori Bernstein <ori@eigenstate.org>
date: Wed Oct 23 15:14:38 EDT 2024
surroundings: add libsec diff
--- /dev/null
+++ b/libsec.diff
@@ -1,0 +1,707 @@
+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");
+ }
--
⑨