shithub: riscv

Download patch

ref: a291bbdeddfd41a2f0907ecbd7b819f0eedffdaf
parent: 0bfac109a491e61d7cd585060b88e1251da1e928
author: cinap_lenrek <[email protected]>
date: Mon Feb 1 16:34:49 EST 2016

libsec: ecdsa client support for tlshand, cleanups

--- a/sys/include/libsec.h
+++ b/sys/include/libsec.h
@@ -339,11 +339,11 @@
 void		asn1dump(uchar *der, int len);
 uchar*		decodePEM(char *s, char *type, int *len, char **new_s);
 PEMChain*	decodepemchain(char *s, char *type);
-uchar*		X509gen(RSApriv *priv, char *subj, ulong valid[2], int *certlen);
-uchar*		X509req(RSApriv *priv, char *subj, int *certlen);
-char*		X509verifydigest(uchar *sig, int siglen, uchar *edigest, int edigestlen, RSApub *pk);
-char*		X509verifydata(uchar *sig, int siglen, uchar *data, int datalen, RSApub *pk);
-char*		X509verify(uchar *cert, int ncert, RSApub *pk);
+uchar*		X509rsagen(RSApriv *priv, char *subj, ulong valid[2], int *certlen);
+uchar*		X509rsareq(RSApriv *priv, char *subj, int *certlen);
+char*		X509rsaverifydigest(uchar *sig, int siglen, uchar *edigest, int edigestlen, RSApub *pk);
+char*		X509rsaverify(uchar *cert, int ncert, RSApub *pk);
+
 void		X509dump(uchar *cert, int ncert);
 
 /*
@@ -487,11 +487,14 @@
 	mpint *p;
 	mpint *a;
 	mpint *b;
-	ECpoint *G;
+	ECpoint G;
 	mpint *n;
 	mpint *h;
 } ECdomain;
 
+void	ecdominit(ECdomain *, void (*init)(mpint *p, mpint *a, mpint *b, mpint *x, mpint *y, mpint *n, mpint *h));
+void	ecdomfree(ECdomain *);
+
 void	ecassign(ECdomain *, ECpoint *old, ECpoint *new);
 void	ecadd(ECdomain *, ECpoint *a, ECpoint *b, ECpoint *s);
 void	ecmul(ECdomain *, ECpoint *a, mpint *k, ECpoint *s);
@@ -503,6 +506,18 @@
 int	ecdsaverify(ECdomain *, ECpub *, uchar *, int, mpint *, mpint *);
 void	base58enc(uchar *, char *, int);
 int	base58dec(char *, uchar *, int);
+
+ECpub*	ecdecodepub(ECdomain *dom, uchar *, int);
+int	ecencodepub(ECdomain *dom, ECpub *, uchar *, int);
+void	ecpubfree(ECpub *);
+
+ECpub*	X509toECpub(uchar *cert, int ncert, ECdomain *dom);
+char*	X509ecdsaverifydigest(uchar *sig, int siglen, uchar *edigest, int edigestlen, ECdomain *dom, ECpub *pub);
+char*	X509ecdsaverify(uchar *sig, int siglen, ECdomain *dom, ECpub *pub);
+
+/* curves */
+void	secp256r1(mpint *p, mpint *a, mpint *b, mpint *x, mpint *y, mpint *n, mpint *h);
+void	secp256k1(mpint *p, mpint *a, mpint *b, mpint *x, mpint *y, mpint *n, mpint *h);
 
 DigestState*	ripemd160(uchar *, ulong, uchar *, DigestState *);
 
--- a/sys/man/2/ec
+++ b/sys/man/2/ec
@@ -19,6 +19,12 @@
 .B #include <libsec.h>
 .PP
 .B
+void	ecdominit(ECdomain *dom, void (*init)(mpint *p, mpint *a, mpint *b, mpint *x, mpint *y, mpint *n, mpint *h));
+.PP
+.B
+void	ecdomfree(ECdomain *dom);
+.PP
+.B
 void	ecassign(ECdomain *dom, ECpoint *old, ECpoint *new);
 .PP
 .B
@@ -53,6 +59,19 @@
 Points on the curve are represented by 
 .B ECpoint
 structs.
+.PP
+.B ecdominit
+initializes a
+.B ECdomain
+struct and calls the
+.B init
+function such as
+.B secp256r1
+which fills in the parameters of the curve.
+.PP
+.B ecdomfree
+frees the parameters of the curve and zeros the struct. It does
+not free the memory of the struct itself.
 .PP
 .BR ecassign ", " ecadd " and " ecmul
 are analogous to their counterparts in
--- a/sys/man/2/rsa
+++ b/sys/man/2/rsa
@@ -12,8 +12,9 @@
 rsapuballoc,
 rsapubfree,
 X509toRSApub,
-X509gen,
-X509verify \- RSA encryption algorithm
+X509rsagen,
+X509rsareq,
+X509rsaverify \- RSA encryption algorithm
 .SH SYNOPSIS
 .B #include <u.h>
 .br
@@ -61,13 +62,13 @@
 uchar*	decodePEM(char *s, char *type, int *len, char **new_s)
 .PP
 .B
-uchar*	X509gen(RSApriv *priv, char *subj, ulong valid[2], int *certlen);
+uchar*	X509rsagen(RSApriv *priv, char *subj, ulong valid[2], int *certlen);
 .PP
 .B
-uchar*	X509req(RSApriv *priv, char *subj, int *certlen);
+uchar*	X509rsareq(RSApriv *priv, char *subj, int *certlen);
 .PP
 .B
-char*	X509verify(uchar *cert, int ncert, RSApub *pk)
+char*	X509rsaverify(uchar *cert, int ncert, RSApub *pk)
 .DT
 .SH DESCRIPTION
 RSA is a public key encryption algorithm.  The owner of a key publishes
@@ -147,12 +148,12 @@
 For the special case of
 certificates signed by a known trusted key
 (in a single step, without certificate chains),
-.I X509verify
+.I X509rsaverify
 checks the signature on
 .IR cert .
 It returns nil if successful, else an error string.
 .PP
-.I X509gen
+.I X509rsagen
 creates a self-signed X.509 certificate, given an RSA keypair
 .IR priv ,
 a issuer/subject string
--- a/sys/src/cmd/auth/factotum/ecdsa.c
+++ b/sys/src/cmd/auth/factotum/ecdsa.c
@@ -42,7 +42,7 @@
 	st->p.d = betomp(keyenc + 1, 32, nil);
 	st->p.x = mpnew(0);
 	st->p.y = mpnew(0);
-	ecmul(&dom, dom.G, st->p.d, &st->p);
+	ecmul(&dom, &dom.G, st->p.d, &st->p);
 	return RpcOk;
 }
 
@@ -56,14 +56,8 @@
 	char *key, *password;
 	Attr *attr;
 
-	if(dom.p == nil){
-		dom.p = strtomp("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", nil, 16, nil);
-		dom.a = uitomp(0, nil);
-		dom.b = uitomp(7, nil);
-		dom.n = strtomp("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", nil, 16, nil);
-		dom.h = uitomp(1, nil);
-		dom.G = strtoec(&dom, "0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", nil, nil);
-	}
+	if(dom.p == nil)
+		ecdominit(&dom, secp256k1);
 	fss->ps = nil;
 	if((iscli = isclient(_strfindattr(fss->attr, "role"))) < 0)
 		return failure(fss, nil);
--- a/sys/src/cmd/auth/rsa2csr.c
+++ b/sys/src/cmd/auth/rsa2csr.c
@@ -34,7 +34,7 @@
 	if((key = getkey(argc-1, argv+1, 1, nil)) == nil)
 		sysfatal("%r");
 
-	cert = X509req(key, argv[0], &len);
+	cert = X509rsareq(key, argv[0], &len);
 	if(cert == nil)
 		sysfatal("X509req: %r");
 
--- a/sys/src/cmd/auth/rsa2x509.c
+++ b/sys/src/cmd/auth/rsa2x509.c
@@ -41,7 +41,7 @@
 	if((key = getkey(argc-1, argv+1, 1, nil)) == nil)
 		sysfatal("%r");
 
-	cert = X509gen(key, argv[0], valid, &len);
+	cert = X509rsagen(key, argv[0], valid, &len);
 	if(cert == nil)
 		sysfatal("X509gen: %r");
 
--- a/sys/src/libsec/port/ecc.c
+++ b/sys/src/libsec/port/ecc.c
@@ -407,7 +407,7 @@
 		if(mpcmp(p->d, mpzero) > 0 && mpcmp(p->d, dom->n) < 0)
 			break;
 	}
-	ecmul(dom, dom->G, p->d, p);
+	ecmul(dom, &dom->G, p->d, p);
 	return p;
 }
 
@@ -468,7 +468,7 @@
 	mpmod(u1, dom->n, u1);
 	mpmul(r, t, u2);
 	mpmod(u2, dom->n, u2);
-	ecmul(dom, dom->G, u1, &R);
+	ecmul(dom, &dom->G, u1, &R);
 	ecmul(dom, pub, u2, &S);
 	ecadd(dom, &R, &S, &R);
 	ret = 0;
@@ -539,4 +539,80 @@
 	mpfree(r);
 	mpfree(b);
 	return 0;
+}
+
+void
+ecdominit(ECdomain *dom, void (*init)(mpint *p, mpint *a, mpint *b, mpint *x, mpint *y, mpint *n, mpint *h))
+{
+	memset(dom, 0, sizeof(*dom));
+	dom->p = mpnew(0);
+	dom->a = mpnew(0);
+	dom->b = mpnew(0);
+	dom->G.x = mpnew(0);
+	dom->G.y = mpnew(0);
+	dom->n = mpnew(0);
+	dom->h = mpnew(0);
+	if(init){
+		(*init)(dom->p, dom->a, dom->b, dom->G.x, dom->G.y, dom->n, dom->h);
+		dom->p = mpfield(dom->p);
+	}
+}
+
+void
+ecdomfree(ECdomain *dom)
+{
+	mpfree(dom->p);
+	mpfree(dom->a);
+	mpfree(dom->b);
+	mpfree(dom->G.x);
+	mpfree(dom->G.y);
+	mpfree(dom->n);
+	mpfree(dom->h);
+	memset(dom, 0, sizeof(*dom));
+}
+
+int
+ecencodepub(ECdomain *dom, ECpub *pub, uchar *data, int len)
+{
+	int n;
+
+	n = (mpsignif(dom->p)+7)/8;
+	if(len < 1 + 2*n)
+		return 0;
+	len = 1 + 2*n;
+	data[0] = 0x04;
+	mptober(pub->x, data+1, n);
+	mptober(pub->y, data+1+n, n);
+	return len;
+}
+
+ECpub*
+ecdecodepub(ECdomain *dom, uchar *data, int len)
+{
+	ECpub *pub;
+	int n;
+
+	n = (mpsignif(dom->p)+7)/8;
+	if(len != 1 + 2*n || data[0] != 0x04)
+		return nil;
+	pub = mallocz(sizeof(*pub), 1);
+	if(pub == nil)
+		return nil;
+	pub->x = betomp(data+1, n, nil);
+	pub->y = betomp(data+1+n, n, nil);
+	if(!ecpubverify(dom, pub)){
+		ecpubfree(pub);
+		pub = nil;
+	}
+	return pub;
+}
+
+void
+ecpubfree(ECpub *p)
+{
+	if(p == nil)
+		return;
+	mpfree(p->x);
+	mpfree(p->y);
+	free(p);
 }
--- a/sys/src/libsec/port/mkfile
+++ b/sys/src/libsec/port/mkfile
@@ -30,7 +30,11 @@
 	hkdf.c\
 	ccpoly.c\
 	tsmemcmp.c\
+	secp256r1.c\
+	secp256k1.c\
 
+CLEANFILES=secp256r1.c secp256k1.c
+
 ALLOFILES=${CFILES:%.c=%.$O}
 
 # cull things in the per-machine directories from this list
@@ -46,6 +50,12 @@
 
 </sys/src/cmd/mksyslib
 
+%.c:D:	%.mp
+	echo '#include <u.h>' > $target
+	echo '#include <libc.h>' >> $target
+	echo '#include <mp.h>' >> $target
+	mpc $prereq >> $target
+	
 $O.rsatest: rsatest.$O
 	$LD -o $target $prereq
 
--- /dev/null
+++ b/sys/src/libsec/port/secp256k1.mp
@@ -1,0 +1,10 @@
+# E: y² = x³ + ax + b 
+secp256k1(p,a,b,x,y,n,h) {
+	p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1;
+	a = 0;
+	b = 7;
+	x = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798;
+	y = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8;
+	n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141;
+	h = 1;
+}
--- /dev/null
+++ b/sys/src/libsec/port/secp256r1.mp
@@ -1,0 +1,10 @@
+# E: y² = x³ + ax + b 
+secp256r1(p,a,b,x,y,n,h) {
+	p = 2^256 - 2^224 + 2^192 + 2^96 - 1;
+	a = p - 3;
+	b = 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B;
+	x = 0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296;
+	y = 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5;
+	n = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551;
+	h = 1;
+}
--- a/sys/src/libsec/port/tlshand.c
+++ b/sys/src/libsec/port/tlshand.c
@@ -19,6 +19,7 @@
 	SSL3FinishedLen = MD5dlen+SHA1dlen,
 	MaxKeyData = 160,	// amount of secret we may need
 	MaxChunk = 1<<15,
+	MAXdlen = SHA2_512dlen,
 	RandomSize = 32,
 	SidSize = 32,
 	MasterSecretSize = 48,
@@ -48,14 +49,7 @@
 
 typedef struct Namedcurve{
 	int tlsid;
-	char *name;
-
-	char *p;
-	char *a;
-	char *b;
-	char *G;
-	char *n;
-	char *h;
+	void (*init)(mpint *p, mpint *a, mpint *b, mpint *x, mpint *y, mpint *n, mpint *h);
 } Namedcurve;
 
 typedef struct Finished{
@@ -279,12 +273,15 @@
 	TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA	= 0XC013,
 	TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA	= 0XC014,
 	TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256	= 0xC027,
+	TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256	= 0xC023,
 
 	TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305	= 0xCCA8,
+	TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305	= 0xCCA9,
 	TLS_DHE_RSA_WITH_CHACHA20_POLY1305	= 0xCCAA,
 
-	GOOGLE_ECDHE_RSA_WITH_CHACHA20_POLY1305	= 0xCC13,
-	GOOGLE_DHE_RSA_WITH_CHACHA20_POLY1305	= 0xCC15,
+	GOOGLE_ECDHE_RSA_WITH_CHACHA20_POLY1305		= 0xCC13,
+	GOOGLE_ECDHE_ECDSA_WITH_CHACHA20_POLY1305	= 0xCC14,
+	GOOGLE_DHE_RSA_WITH_CHACHA20_POLY1305		= 0xCC15,
 
 	TLS_PSK_WITH_CHACHA20_POLY1305		= 0xCCAB,
 	TLS_PSK_WITH_AES_128_CBC_SHA256		= 0x00AE,
@@ -299,11 +296,14 @@
 
 static Algs cipherAlgs[] = {
 	{"ccpoly96_aead", "clear", 2*(32+12), TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305},
+	{"ccpoly96_aead", "clear", 2*(32+12), TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305},
 	{"ccpoly96_aead", "clear", 2*(32+12), TLS_DHE_RSA_WITH_CHACHA20_POLY1305},
 
 	{"ccpoly64_aead", "clear", 2*32, GOOGLE_ECDHE_RSA_WITH_CHACHA20_POLY1305},
+	{"ccpoly64_aead", "clear", 2*32, GOOGLE_ECDHE_ECDSA_WITH_CHACHA20_POLY1305},
 	{"ccpoly64_aead", "clear", 2*32, GOOGLE_DHE_RSA_WITH_CHACHA20_POLY1305},
 
+	{"aes_128_cbc", "sha256", 2*(16+16+SHA2_256dlen), TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256},
 	{"aes_128_cbc", "sha256", 2*(16+16+SHA2_256dlen), TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256},
 	{"aes_128_cbc", "sha1", 2*(16+16+SHA1dlen), TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
 	{"aes_256_cbc", "sha1", 2*(32+16+SHA1dlen), TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
@@ -328,13 +328,7 @@
 };
 
 static Namedcurve namedcurves[] = {
-{0x0017, "secp256r1",
-	"FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
-	"FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
-	"5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
-	"046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
-	"FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
-	"1"}
+	0x0017, secp256r1,
 };
 
 static uchar pointformats[] = {
@@ -341,8 +335,25 @@
 	CompressionNull /* support of uncompressed point format is mandatory */
 };
 
-// signature algorithms (only RSA at the moment)
+static struct {
+	DigestState* (*fun)(uchar*, ulong, uchar*, DigestState*);
+	int len;
+} hashfun[] = {
+	[0x01]	{md5,		MD5dlen},
+	[0x02]	{sha1,		SHA1dlen},
+	[0x03]	{sha2_224,	SHA2_224dlen},
+	[0x04]	{sha2_256,	SHA2_256dlen},
+	[0x05]	{sha2_384,	SHA2_384dlen},
+	[0x06]	{sha2_512,	SHA2_512dlen},
+};
+
+// signature algorithms (only RSA and ECDSA at the moment)
 static int sigalgs[] = {
+	0x0603,		/* SHA512 ECDSA */
+	0x0503,		/* SHA384 ECDSA */
+	0x0403,		/* SHA256 ECDSA */
+	0x0203,		/* SHA1 ECDSA */
+
 	0x0601,		/* SHA512 RSA */
 	0x0501,		/* SHA384 RSA */
 	0x0401,		/* SHA256 RSA */
@@ -421,7 +432,6 @@
 
 /* x509.c */
 extern mpint*	pkcs1padbuf(uchar *buf, int len, mpint *modulus);
-extern int	pkcs1decryptsignature(uchar *sig, int siglen, RSApub *pk, uchar **pbuf);
 extern int	X509encodesignature_sha256(uchar digest[SHA2_256dlen], uchar *buf, int len);
 
 //================= client/server ========================
@@ -869,11 +879,16 @@
 isECDHE(int tlsid)
 {
 	switch(tlsid){
+	case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305:
+	case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305:
+
+	case GOOGLE_ECDHE_ECDSA_WITH_CHACHA20_POLY1305:
+	case GOOGLE_ECDHE_RSA_WITH_CHACHA20_POLY1305:
+
+	case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
 	case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
 	case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
 	case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
-	case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305:
-	case GOOGLE_ECDHE_RSA_WITH_CHACHA20_POLY1305:
 		return 1;
 	}
 	return 0;
@@ -932,47 +947,14 @@
 	return epm;
 }
 
-static ECpoint*
-bytestoec(ECdomain *dom, Bytes *bp, ECpoint *ret)
-{
-	char *hex = "0123456789ABCDEF";
-	char *s;
-	int i;
-
-	s = emalloc(2*bp->len + 1);
-	for(i=0; i < bp->len; i++){
-		s[2*i] = hex[bp->data[i]>>4 & 15];
-		s[2*i+1] = hex[bp->data[i] & 15];
-	}
-	s[2*bp->len] = '\0';
-	ret = strtoec(dom, s, nil, ret);
-	free(s);
-	return ret;
-}
-
 static Bytes*
-ectobytes(int type, ECpoint *p)
-{
-	Bytes *bx, *by, *bp;
-
-	bx = mptobytes(p->x);
-	by = mptobytes(p->y);
-	bp = newbytes(bx->len + by->len + 1);
-	bp->data[0] =  type;
-	memmove(bp->data+1, bx->data, bx->len);
-	memmove(bp->data+1+bx->len, by->data, by->len);
-	freebytes(bx);
-	freebytes(by);
-	return bp;
-}
-
-static Bytes*
 tlsSecECDHEc(TlsSec *sec, uchar *srandom, int vers, int curve, Bytes *Ys)
 {
 	Namedcurve *nc, *enc;
 	Bytes *epm;
 	ECdomain dom;
-	ECpoint G, K, Y;
+	ECpub *pub;
+	ECpoint K;
 	ECpriv Q;
 
 	if(Ys == nil)
@@ -990,19 +972,13 @@
 	if(setVers(sec, vers) < 0)
 		return nil;
 	
-	epm = nil;
+	ecdominit(&dom, nc->init);
+	pub = ecdecodepub(&dom, Ys->data, Ys->len);
+	if(pub == nil){
+		ecdomfree(&dom);
+		return nil;
+	}
 
-	memset(&dom, 0, sizeof(dom));
-	dom.p = mpfield(strtomp(nc->p, nil, 16, nil));
-	dom.a = strtomp(nc->a, nil, 16, nil);
-	dom.b = strtomp(nc->b, nil, 16, nil);
-	dom.n = strtomp(nc->n, nil, 16, nil);
-	dom.h = strtomp(nc->h, nil, 16, nil);
-
-	memset(&G, 0, sizeof(G));
-	G.x = mpnew(0);
-	G.y = mpnew(0);
-
 	memset(&Q, 0, sizeof(Q));
 	Q.x = mpnew(0);
 	Q.y = mpnew(0);
@@ -1012,49 +988,23 @@
 	K.x = mpnew(0);
 	K.y = mpnew(0);
 
-	memset(&Y, 0, sizeof(Y));
-	Y.x = mpnew(0);
-	Y.y = mpnew(0);
+	epm = nil;
+	if(ecgen(&dom, &Q) != nil){
+		ecmul(&dom, pub, Q.d, &K);
+		setMasterSecret(sec, mptobytes(K.x));
+		epm = newbytes(1 + 2*((mpsignif(dom.p)+7)/8));
+		epm->len = ecencodepub(&dom, &Q, epm->data, epm->len);
+	}
 
-	if(dom.p == nil || dom.a == nil || dom.b == nil || dom.n == nil || dom.h == nil)
-		goto Out;
-
-	dom.G = strtoec(&dom, nc->G, nil, &G);
-	if(dom.G == nil)
-		goto Out;
-
-	if(bytestoec(&dom, Ys, &Y) == nil)
-		goto Out;
-
-	if(ecgen(&dom, &Q) == nil)
-		goto Out;
-
-	ecmul(&dom, &Y, Q.d, &K);
-	setMasterSecret(sec, mptobytes(K.x));
-
-	/* 0x04 = uncompressed public key */
-	epm = ectobytes(0x04, &Q);
-	
-Out:
-	mpfree(Y.x);
-	mpfree(Y.y);
-
 	mpfree(K.x);
 	mpfree(K.y);
-
 	mpfree(Q.x);
 	mpfree(Q.y);
 	mpfree(Q.d);
 
-	mpfree(G.x);
-	mpfree(G.y);
+	ecpubfree(pub);
+	ecdomfree(&dom);
 
-	mpfree(dom.p);
-	mpfree(dom.a);
-	mpfree(dom.b);
-	mpfree(dom.n);
-	mpfree(dom.h);
-
 	return epm;
 }
 
@@ -1061,9 +1011,12 @@
 static char*
 verifyDHparams(TlsConnection *c, Bytes *par, Bytes *sig, int sigalg)
 {
-	uchar hashes[MD5dlen+SHA1dlen], *buf;
+	uchar digest[MAXdlen];
+	int digestlen;
+	ECdomain dom;
+	ECpub *ecpk;
+	RSApub *rsapk;
 	Bytes *blob;
-	RSApub *pk;
 	char *err;
 
 	if(par == nil || par->len <= 0)
@@ -1072,7 +1025,6 @@
 	if(sig == nil || sig->len <= 0){
 		if(c->sec->psklen > 0)
 			return nil;
-
 		return "no signature";
 	}
 
@@ -1079,33 +1031,46 @@
 	if(c->cert == nil)
 		return "no certificate";
 
-	pk = X509toRSApub(c->cert->data, c->cert->len, nil, 0);
-	if(pk == nil)
-		return "bad certificate";
-
 	blob = newbytes(2*RandomSize + par->len);
 	memmove(blob->data+0*RandomSize, c->crandom, RandomSize);
 	memmove(blob->data+1*RandomSize, c->srandom, RandomSize);
 	memmove(blob->data+2*RandomSize, par->data, par->len);
-	if(c->version >= TLS12Version) {
-		if((sigalg & 0xFF) == 1)
-			err = X509verifydata(sig->data, sig->len, blob->data, blob->len, pk);
-		else
-			err = "signaure algorithm not RSA";
+	if(c->version < TLS12Version){
+		digestlen = MD5dlen + SHA1dlen;
+		md5(blob->data, blob->len, digest, nil);
+		sha1(blob->data, blob->len, digest+MD5dlen, nil);
 	} else {
-		err = nil;
-		if(pkcs1decryptsignature(sig->data, sig->len, pk, &buf) != sizeof(hashes))
-			err = "bad signature";
-		else {
-			md5(blob->data, blob->len, hashes, nil);
-			sha1(blob->data, blob->len, hashes+MD5dlen, nil);
-			if(tsmemcmp(buf, hashes, sizeof(hashes)) != 0)
-				err = "digests did not match";
+		int hashalg = (sigalg>>8) & 0xFF;
+		digestlen = -1;
+		if(hashalg < nelem(hashfun) && hashfun[hashalg].fun != nil){
+			digestlen = hashfun[hashalg].len;
+			(*hashfun[hashalg].fun)(blob->data, blob->len, digest, nil);
 		}
-		free(buf);
 	}
 	freebytes(blob);
-	rsapubfree(pk);
+
+	if(digestlen <= 0)
+		return "unknown signature digest algorithm";
+	
+	switch(sigalg & 0xFF){
+	case 0x01:
+		rsapk = X509toRSApub(c->cert->data, c->cert->len, nil, 0);
+		if(rsapk == nil)
+			return "bad certificate";
+		err = X509rsaverifydigest(sig->data, sig->len, digest, digestlen, rsapk);
+		rsapubfree(rsapk);
+		break;
+	case 0x03:
+		ecpk = X509toECpub(c->cert->data, c->cert->len, &dom);
+		if(ecpk == nil)
+			return "bad certificate";
+		err = X509ecdsaverifydigest(sig->data, sig->len, digest, digestlen, &dom, ecpk);
+		ecdomfree(&dom);
+		ecpubfree(ecpk);
+		break;
+	default:
+		err = "signaure algorithm not RSA or ECDSA";
+	}
 
 	return err;
 }
--- a/sys/src/libsec/port/x509.c
+++ b/sys/src/libsec/port/x509.c
@@ -134,9 +134,8 @@
 static int	oid_lookup(Ints* o, Ints** tab);
 static void	freevalfields(Value* v);
 static mpint	*asn1mpint(Elem *e);
+static void	edump(Elem);
 
-
-
 #define TAG_MASK 0x1F
 #define CONSTR_MASK 0x20
 #define CLASS_MASK 0xC0
@@ -223,6 +222,7 @@
 	Tag tag;
 	Value val;
 
+	memset(pelem, 0, sizeof(*pelem));
 	err = tag_decode(pp, pend, &tag, &isconstr);
 	if(err == ASN_OK) {
 		err = length_decode(pp, pend, &length);
@@ -1159,21 +1159,8 @@
 static int
 is_bigint(Elem* pe, Bytes** pbigint)
 {
-	int v, n, i;
-
-	if(pe->tag.class == Universal && pe->tag.num == INTEGER) {
-		if(pe->val.tag == VBigInt)
-			*pbigint = pe->val.u.bigintval;
-		else if(pe->val.tag == VInt){
-			v = pe->val.u.intval;
-			for(n = 1; n < 4; n++)
-				if((1 << (8 * n)) > v)
-					break;
-			*pbigint = newbytes(n);
-			for(i = 0; i < n; i++)
-				(*pbigint)->data[i] = (v >> ((n - 1 - i) * 8));
-		}else
-			return 0;
+	if(pe->tag.class == Universal && pe->tag.num == INTEGER && pe->val.tag == VBigInt) {
+		*pbigint = pe->val.u.bigintval;
 		return 1;
 	}
 	return 0;
@@ -1536,6 +1523,7 @@
 	Bytes*	publickey;
 	int	signature_alg;
 	Bytes*	signature;
+	int	curve;
 } CertX509;
 
 /* Algorithm object-ids */
@@ -1553,6 +1541,12 @@
 	ALG_sha512WithRSAEncryption,
 	ALG_sha224WithRSAEncryption,
 
+	ALG_ecPublicKey,
+	ALG_sha1WithECDSA,
+	ALG_sha256WithECDSA,
+	ALG_sha384WithECDSA,
+	ALG_sha512WithECDSA,
+
 	ALG_md5,
 	ALG_sha1,
 	ALG_sha256,
@@ -1587,6 +1581,7 @@
 };
 
 static Ints15 oid_rsaEncryption = {7, 1, 2, 840, 113549, 1, 1, 1 };
+
 static Ints15 oid_md2WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 2 };
 static Ints15 oid_md4WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 3 };
 static Ints15 oid_md5WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 4 };
@@ -1597,6 +1592,12 @@
 static Ints15 oid_sha512WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 13 };
 static Ints15 oid_sha224WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 14 };
 
+static Ints15 oid_ecPublicKey = {6, 1, 2, 840, 10045, 2, 1 };
+static Ints15 oid_sha1WithECDSA = {6, 1, 2, 840, 10045, 4, 1 };
+static Ints15 oid_sha256WithECDSA = {7, 1, 2, 840, 10045, 4, 3, 2 };
+static Ints15 oid_sha384WithECDSA = {7, 1, 2, 840, 10045, 4, 3, 3 };
+static Ints15 oid_sha512WithECDSA = {7, 1, 2, 840, 10045, 4, 3, 4 };
+
 static Ints15 oid_md5 = {6, 1, 2, 840, 113549, 2, 5 };
 static Ints15 oid_sha1 = {6, 1, 3, 14, 3, 2, 26 };
 static Ints15 oid_sha256= {9, 2, 16, 840, 1, 101, 3, 4, 2, 1 };
@@ -1618,6 +1619,12 @@
 	(Ints*)&oid_sha512WithRSAEncryption,
 	(Ints*)&oid_sha224WithRSAEncryption,
 
+	(Ints*)&oid_ecPublicKey,
+	(Ints*)&oid_sha1WithECDSA,
+	(Ints*)&oid_sha256WithECDSA,
+	(Ints*)&oid_sha384WithECDSA,
+	(Ints*)&oid_sha512WithECDSA,
+
 	(Ints*)&oid_md5,
 	(Ints*)&oid_sha1,
 	(Ints*)&oid_sha256,
@@ -1631,10 +1638,22 @@
 	&alg_md5, &alg_md5, &alg_md5, &alg_md5,
 	&alg_sha1, &alg_sha1,
 	&alg_sha256, &alg_sha384, &alg_sha512, &alg_sha224,
+	&alg_sha256, &alg_sha1, &alg_sha256, &alg_sha384, &alg_sha512,
 	&alg_md5, &alg_sha1, &alg_sha256, &alg_sha384, &alg_sha512, &alg_sha224,
 	nil
 };
 
+static Ints15 oid_secp256r1 = {7, 1, 2, 840, 10045, 3, 1, 7};
+
+static Ints *namedcurves_oid_tab[] = {
+	(Ints*)&oid_secp256r1,
+	nil,
+};
+static void (*namedcurves[])(mpint *p, mpint *a, mpint *b, mpint *x, mpint *y, mpint *n, mpint *h) = {
+	secp256r1,
+	nil,
+};
+
 static void
 freecert(CertX509* c)
 {
@@ -1726,6 +1745,17 @@
 	return oid_lookup(oid, alg_oid_tab);
 }
 
+static int
+parse_curve(Elem* e)
+{
+	Elist* el;
+	Ints* oid;
+
+	if(!is_seq(e, &el) || elistlen(el)<2 || !is_oid(&el->tl->hd, &oid))
+		return -1;
+	return oid_lookup(oid, namedcurves_oid_tab);
+}
+
 static CertX509*
 decode_cert(Bytes* a)
 {
@@ -1828,7 +1858,7 @@
 		goto errret;
 
 	/* SubjectPublicKeyInfo */
- 	if(!is_seq(epubkey, &elpubkey))
+	if(!is_seq(epubkey, &elpubkey))
 		goto errret;
 	if(elistlen(elpubkey) != 2)
 		goto errret;
@@ -1836,6 +1866,12 @@
 	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;
+	}
   	if(!is_bitstring(&elpubkey->tl->hd, &bits))
 		goto errret;
 	if(bits->unusedbits != 0)
@@ -1869,32 +1905,23 @@
 decode_rsapubkey(Bytes* a)
 {
 	Elem e;
-	Elist *el, *l;
-	mpint *mp;
+	Elist *el;
 	RSApub* key;
 
-	l = nil;
 	key = rsapuballoc();
 	if(decode(a->data, a->len, &e) != ASN_OK)
 		goto errret;
 	if(!is_seq(&e, &el) || elistlen(el) != 2)
 		goto errret;
-
-	l = el;
-
-	key->n = mp = asn1mpint(&el->hd);
-	if(mp == nil)
+	if((key->n = asn1mpint(&el->hd)) == nil)
 		goto errret;
-
 	el = el->tl;
-	key->ek = mp = asn1mpint(&el->hd);
-	if(mp == nil)
+	if((key->ek = asn1mpint(&el->hd)) == nil)
 		goto errret;
-
-	freeelist(l);
+	freevalfields(&e.val);
 	return key;
 errret:
-	freeelist(l);
+	freevalfields(&e.val);
 	rsapubfree(key);
 	return nil;
 }
@@ -1917,7 +1944,6 @@
 	int version;
 	Elem e;
 	Elist *el;
-	mpint *mp;
 	RSApriv* key;
 
 	key = rsaprivalloc();
@@ -1929,47 +1955,41 @@
 		goto errret;
 
 	el = el->tl;
-	key->pub.n = mp = asn1mpint(&el->hd);
-	if(mp == nil)
+	if((key->pub.n = asn1mpint(&el->hd)) == nil)
 		goto errret;
 
 	el = el->tl;
-	key->pub.ek = mp = asn1mpint(&el->hd);
-	if(mp == nil)
+	if((key->pub.ek = asn1mpint(&el->hd)) == nil)
 		goto errret;
 
 	el = el->tl;
-	key->dk = mp = asn1mpint(&el->hd);
-	if(mp == nil)
+	if((key->dk = asn1mpint(&el->hd)) == nil)
 		goto errret;
 
 	el = el->tl;
-	key->q = mp = asn1mpint(&el->hd);
-	if(mp == nil)
+	if((key->q = asn1mpint(&el->hd)) == nil)
 		goto errret;
 
 	el = el->tl;
-	key->p = mp = asn1mpint(&el->hd);
-	if(mp == nil)
+	if((key->p = asn1mpint(&el->hd)) == nil)
 		goto errret;
 
 	el = el->tl;
-	key->kq = mp = asn1mpint(&el->hd);
-	if(mp == nil)
+	if((key->kq = asn1mpint(&el->hd)) == nil)
 		goto errret;
 
 	el = el->tl;
-	key->kp = mp = asn1mpint(&el->hd);
-	if(mp == nil)
+	if((key->kp = asn1mpint(&el->hd)) == nil)
 		goto errret;
 
 	el = el->tl;
-	key->c2 = mp = asn1mpint(&el->hd);
-	if(mp == nil)
+	if((key->c2 = asn1mpint(&el->hd)) == nil)
 		goto errret;
 
+	freevalfields(&e.val);
 	return key;
 errret:
+	freevalfields(&e.val);
 	rsaprivfree(key);
 	return nil;
 }
@@ -1990,7 +2010,6 @@
 	int version;
 	Elem e;
 	Elist *el;
-	mpint *mp;
 	DSApriv* key;
 
 	key = dsaprivalloc();
@@ -2003,32 +2022,29 @@
 		goto errret;
 
 	el = el->tl;
-	key->pub.p = mp = asn1mpint(&el->hd);
-	if(mp == nil)
+	if((key->pub.p = asn1mpint(&el->hd)) == nil)
 		goto errret;
 
 	el = el->tl;
-	key->pub.q = mp = asn1mpint(&el->hd);
-	if(mp == nil)
+	if((key->pub.q = asn1mpint(&el->hd)) == nil)
 		goto errret;
 
 	el = el->tl;
-	key->pub.alpha = mp = asn1mpint(&el->hd);
-	if(mp == nil)
+	if((key->pub.alpha = asn1mpint(&el->hd)) == nil)
 		goto errret;
 
 	el = el->tl;
-	key->pub.key = mp = asn1mpint(&el->hd);
-	if(mp == nil)
+	if((key->pub.key = asn1mpint(&el->hd)) == nil)
 		goto errret;
 
 	el = el->tl;
-	key->secret = mp = asn1mpint(&el->hd);
-	if(mp == nil)
+	if((key->secret = asn1mpint(&el->hd)) == nil)
 		goto errret;
 
+	freevalfields(&e.val);
 	return key;
 errret:
+	freevalfields(&e.val);
 	dsaprivfree(key);
 	return nil;
 }
@@ -2037,16 +2053,12 @@
 asn1mpint(Elem *e)
 {
 	Bytes *b;
-	mpint *mp;
 	int v;
 
 	if(is_int(e, &v))
 		return itomp(v, nil);
-	if(is_bigint(e, &b)) {
-		mp = betomp(b->data, b->len, nil);
-		freebytes(b);
-		return mp;
-	}
+	if(is_bigint(e, &b))
+		return betomp(b->data, b->len, nil);
 	return nil;
 }
 
@@ -2134,7 +2146,7 @@
 	return da->len;
 }
 
-int
+static int
 pkcs1decryptsignature(uchar *sig, int siglen, RSApub *pk, uchar **pbuf)
 {
 	int nlen, buflen;
@@ -2169,34 +2181,41 @@
 	return -1;
 }
 
-static char*
-verify_digestinfo(uchar *sig, int siglen, RSApub *pk, uchar *pdigest, int *psigalg)
+char*
+X509rsaverifydigest(uchar *sig, int siglen, uchar *edigest, int edigestlen, RSApub *pk)
 {
 	Elem e;
 	Elist *el;
 	Bytes *digest;
 	uchar *buf;
-	int buflen;
+	int alg, buflen;
 	char *err;
 
+	buflen = pkcs1decryptsignature(sig, siglen, pk, &buf);
+	if(buflen == edigestlen && tsmemcmp(buf, edigest, edigestlen) == 0){
+		free(buf);
+		return nil;
+	}
 	el = nil;
 	memset(&e, 0, sizeof(e));
-	buflen = pkcs1decryptsignature(sig, siglen, pk, &buf);
 	if(buflen < 0 || decode(buf, buflen, &e) != ASN_OK
 	|| !is_seq(&e, &el) || elistlen(el) != 2 || !is_octetstring(&el->tl->hd, &digest)) {
 		err = "signature parse error";
 		goto end;
 	}
-	*psigalg = parse_alg(&el->hd);
-	if(*psigalg < 0){
+	alg = parse_alg(&el->hd);
+	if(alg < 0){
 		err = "unknown signature algorithm";
 		goto end;
 	}
-	if(digest->len != digestalg[*psigalg]->len){
+	if(digest->len != edigestlen || digest->len != digestalg[alg]->len){
 		err = "bad digest length";
 		goto end;
 	}
-	memmove(pdigest, digest->data, digest->len);
+	if(tsmemcmp(digest->data, edigest, edigestlen) != 0){
+		err = "digest did not match";
+		goto end;
+	}
 	err = nil;
 end:
 	freevalfields(&e.val);
@@ -2205,36 +2224,82 @@
 }
 
 char*
-X509verifydigest(uchar *sig, int siglen, uchar *edigest, int edigestlen, RSApub *pk)
+X509ecdsaverifydigest(uchar *sig, int siglen, uchar *edigest, int edigestlen, ECdomain *dom, ECpub *pub)
 {
-	uchar digest[MAXdlen];
-	int sigalg;
-	char *e;
+	Elem e;
+	Elist *el;
+	mpint *r, *s;
+	char *err;
 
-	e = verify_digestinfo(sig, siglen, pk, digest, &sigalg);
-	if(e != nil)
-		return e;
-	if(digestalg[sigalg]->len != edigestlen)
-		return "bad digest length";
-	if(tsmemcmp(digest, edigest, edigestlen) != 0)
-		return "digests did not match";
-	return nil;
+	r = s = nil;
+	err = "bad signature";
+	if(decode(sig, siglen, &e) != ASN_OK)
+		goto end;
+	if(!is_seq(&e, &el) || elistlen(el) != 2)
+		goto end;
+	r = asn1mpint(&el->hd);
+	if(r == nil)
+		goto end;
+	el = el->tl;
+	s = asn1mpint(&el->hd);
+	if(s == nil)
+		goto end;
+	if(ecdsaverify(dom, pub, edigest, edigestlen, r, s))
+		err = nil;
+end:
+	freevalfields(&e.val);
+	mpfree(s);
+	mpfree(r);
+	return err;
 }
 
+ECpub*
+X509toECpub(uchar *cert, int ncert, ECdomain *dom)
+{
+	CertX509 *c;
+	ECpub *pub;
+	Bytes *b;
+
+	b = makebytes(cert, ncert);
+	c = decode_cert(b);
+	freebytes(b);
+	if(c == nil)
+		return nil;
+	pub = nil;
+	if(c->publickey_alg == ALG_ecPublicKey){
+		ecdominit(dom, namedcurves[c->curve]);
+		pub = ecdecodepub(dom, c->publickey->data, c->publickey->len);
+		if(pub == nil)
+			ecdomfree(dom);
+	}
+	freecert(c);
+	return pub;
+}
+
 char*
-X509verifydata(uchar *sig, int siglen, uchar *data, int datalen, RSApub *pk)
+X509ecdsaverify(uchar *cert, int ncert, ECdomain *dom, ECpub *pk)
 {
-	uchar digest[MAXdlen], edigest[MAXdlen];
-	int sigalg;
 	char *e;
+	Bytes *b;
+	CertX509 *c;
+	int digestlen;
+	uchar digest[MAXdlen];
 
-	e = verify_digestinfo(sig, siglen, pk, digest, &sigalg);
-	if(e != nil)
-		return e;
-	(*digestalg[sigalg]->fun)(data, datalen, edigest, nil);
-	if(tsmemcmp(digest, edigest, digestalg[sigalg]->len) != 0)
-		return "digests did not match";
-	return nil;
+	b = makebytes(cert, ncert);
+	c = decode_cert(b);
+	if(c == nil){
+		freebytes(b);
+		return "cannot decode cert";
+	}
+	digestlen = digest_certinfo(b, digestalg[c->signature_alg], digest);
+	freebytes(b);
+	if(digestlen <= 0){
+		freecert(c);
+		return "cannot decode certinfo";
+	}
+	e = X509ecdsaverifydigest(c->signature->data, c->signature->len, digest, digestlen, dom, pk);
+	freecert(c);
+	return e;
 }
 
 RSApub*
@@ -2243,7 +2308,7 @@
 	char *e;
 	Bytes *b;
 	CertX509 *c;
-	RSApub *pk;
+	RSApub *pub;
 
 	b = makebytes(cert, ncert);
 	c = decode_cert(b);
@@ -2256,13 +2321,15 @@
 			*e = 0;	/* take just CN part of Distinguished Name */
 		strncpy(name, c->subject, nname);
 	}
-	pk = decode_rsapubkey(c->publickey);
+	pub = nil;
+	if(c->publickey_alg == ALG_rsaEncryption)
+		pub = decode_rsapubkey(c->publickey);
 	freecert(c);
-	return pk;
+	return pub;
 }
 
 char*
-X509verify(uchar *cert, int ncert, RSApub *pk)
+X509rsaverify(uchar *cert, int ncert, RSApub *pk)
 {
 	char *e;
 	Bytes *b;
@@ -2282,7 +2349,7 @@
 		freecert(c);
 		return "cannot decode certinfo";
 	}
-	e = X509verifydigest(c->signature->data, c->signature->len, digest, digestlen, pk);
+	e = X509rsaverifydigest(c->signature->data, c->signature->len, digest, digestlen, pk);
 	freecert(c);
 	return e;
 }
@@ -2512,7 +2579,7 @@
 }
 
 uchar*
-X509gen(RSApriv *priv, char *subj, ulong valid[2], int *certlen)
+X509rsagen(RSApriv *priv, char *subj, ulong valid[2], int *certlen)
 {
 	int serial = 0, sigalg = ALG_sha256WithRSAEncryption;
 	uchar *cert = nil;
@@ -2583,7 +2650,7 @@
 }
 
 uchar*
-X509req(RSApriv *priv, char *subj, int *certlen)
+X509rsareq(RSApriv *priv, char *subj, int *certlen)
 {
 	/* RFC 2314, PKCS #10 Certification Request Syntax */
 	int version = 0, sigalg = ALG_sha256WithRSAEncryption;
@@ -2738,7 +2805,9 @@
 	char *e;
 	Bytes *b;
 	CertX509 *c;
-	RSApub *pk;
+	RSApub *rsapub;
+	ECpub *ecpub;
+	ECdomain ecdom;
 	int digestlen;
 	uchar digest[MAXdlen];
 
@@ -2762,16 +2831,36 @@
 	print("issuer %s\n", c->issuer);
 	print("validity %s %s\n", c->validity_start, c->validity_end);
 	print("subject %s\n", c->subject);
-	pk = decode_rsapubkey(c->publickey);
-	print("pubkey e=%B n(%d)=%B\n", pk->ek, mpsignif(pk->n), pk->n);
 
 	print("sigalg=%d digest=%.*H\n", c->signature_alg, digestlen, digest);
-	e = X509verifydigest(c->signature->data, c->signature->len, digest, digestlen, pk);
-	if(e==nil)
-		e = "nil (meaning ok)";
-	print("self-signed X509verifydigest returns: %s\n", e);
+	print("publickey_alg=%d pubkey[%d] %.*H\n", c->publickey_alg, c->publickey->len,
+		c->publickey->len, c->publickey->data);
 
-	rsapubfree(pk);
+	switch(c->publickey_alg){
+	case ALG_rsaEncryption:
+		rsapub = decode_rsapubkey(c->publickey);
+		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);
+			if(e==nil)
+				e = "nil (meaning ok)";
+			print("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);
+		if(ecpub != nil){
+			e = X509ecdsaverifydigest(c->signature->data, c->signature->len, digest, digestlen, &ecdom, ecpub);
+			if(e==nil)
+				e = "nil (meaning ok)";
+			print("self-signed X509ecdsaverifydigest returns: %s\n", e);
+			ecpubfree(ecpub);
+		}
+		ecdomfree(&ecdom);
+		break;
+	}
 	freecert(c);
 	print("end X509dump\n");
 }