shithub: pki

Download patch

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");
+ }
--