]> git.lizzy.rs Git - plan9front.git/commitdiff
libsec: ecdsa client support for tlshand, cleanups
authorcinap_lenrek <cinap_lenrek@felloff.net>
Mon, 1 Feb 2016 20:34:49 +0000 (21:34 +0100)
committercinap_lenrek <cinap_lenrek@felloff.net>
Mon, 1 Feb 2016 20:34:49 +0000 (21:34 +0100)
12 files changed:
sys/include/libsec.h
sys/man/2/ec
sys/man/2/rsa
sys/src/cmd/auth/factotum/ecdsa.c
sys/src/cmd/auth/rsa2csr.c
sys/src/cmd/auth/rsa2x509.c
sys/src/libsec/port/ecc.c
sys/src/libsec/port/mkfile
sys/src/libsec/port/secp256k1.mp [new file with mode: 0644]
sys/src/libsec/port/secp256r1.mp [new file with mode: 0644]
sys/src/libsec/port/tlshand.c
sys/src/libsec/port/x509.c

index 204ca4d26a76fedc20de39c756cc4c9acb9a6829..09db4f0f09606309fe545a8a9484ab054de82b9b 100644 (file)
@@ -339,11 +339,11 @@ RSApriv*  asn1toRSApriv(uchar*, int);
 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 @@ typedef struct ECdomain{
        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);
@@ -504,6 +507,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 *);
 
 /*
index 431c15cfa614fef82aab328011d9469d719016dc..b4e0cc19ebb893f491704dfb434c0f3c95987981 100644 (file)
@@ -19,6 +19,12 @@ ecdsaverify \- elliptic curve cryptography
 .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
@@ -54,6 +60,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
 .IR mp (2).
index 957ac05c235e5acad0d579d678c72a3c8096178c..f4ad430b971afb7dfda33732751f751baf90b482 100644 (file)
@@ -12,8 +12,9 @@ rsaprivtopub,
 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 @@ void                asn1dump(uchar *der, int len)
 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 @@ to convert to binary before computing the fingerprint or calling
 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
index 31cc0853d6196e80f8bedd4510668a7e9f4d28fd..1c48c1a1bdc2dd62fb047395ea389c0d2be6f1ca 100644 (file)
@@ -42,7 +42,7 @@ decryptkey(Fsstate *fss, char *key, char *password)
        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 @@ ecdsainit(Proto *, Fsstate *fss)
        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);
index ebf3ab8b8fbd2357936c41ab735fe24fa793c158..e4107a2d7b0c68bf86ceb8f5229d80cb1cd03e8e 100644 (file)
@@ -34,7 +34,7 @@ main(int argc, char **argv)
        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");
 
index 476e09b46906907cab7ede0aea50078dcf28a58e..3e07bb88ff3475dddc6f2fdc36073d71b8181647 100644 (file)
@@ -41,7 +41,7 @@ main(int argc, char **argv)
        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");
 
index 04d130c5b490dfd70bc52b7059ef58a0eec0fd30..7d3e326481fb5bd07122815cc60840b43f99c0c6 100644 (file)
@@ -407,7 +407,7 @@ ecgen(ECdomain *dom, ECpriv *p)
                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 @@ ecdsaverify(ECdomain *dom, ECpub *pub, uchar *dig, int len, mpint *r, mpint *s)
        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;
@@ -540,3 +540,79 @@ base58dec(char *src, uchar *dst, int len)
        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);
+}
index 113cb33855f274de3452783739d5ff6cc1e5f2e0..55e7a8c95d2a088d1695a84501080df618838db8 100644 (file)
@@ -30,6 +30,10 @@ CFILES = des.c desmodes.c desECB.c desCBC.c des3ECB.c des3CBC.c\
        hkdf.c\
        ccpoly.c\
        tsmemcmp.c\
+       secp256r1.c\
+       secp256k1.c\
+
+CLEANFILES=secp256r1.c secp256k1.c
 
 ALLOFILES=${CFILES:%.c=%.$O}
 
@@ -46,6 +50,12 @@ UPDATE=mkfile\
 
 </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
 
diff --git a/sys/src/libsec/port/secp256k1.mp b/sys/src/libsec/port/secp256k1.mp
new file mode 100644 (file)
index 0000000..216b914
--- /dev/null
@@ -0,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;
+}
diff --git a/sys/src/libsec/port/secp256r1.mp b/sys/src/libsec/port/secp256r1.mp
new file mode 100644 (file)
index 0000000..5175c91
--- /dev/null
@@ -0,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;
+}
index 1a37ef94b40927db0442cfe68b8ae6094914fa63..8f245625a8003830e57ebedb30f8ee6d52cfb177 100644 (file)
@@ -19,6 +19,7 @@ enum {
        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 Algs{
 
 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 @@ enum {
        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 @@ enum {
 
 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,21 +328,32 @@ static uchar compressors[] = {
 };
 
 static Namedcurve namedcurves[] = {
-{0x0017, "secp256r1",
-       "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
-       "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
-       "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
-       "046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
-       "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
-       "1"}
+       0x0017, secp256r1,
 };
 
 static uchar pointformats[] = {
        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 @@ static void freeints(Ints* b);
 
 /* 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 @@ static int
 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 @@ Out:
        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,18 +972,12 @@ tlsSecECDHEc(TlsSec *sec, uchar *srandom, int vers, int curve, Bytes *Ys)
        if(setVers(sec, vers) < 0)
                return nil;
        
-       epm = 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);
+       ecdominit(&dom, nc->init);
+       pub = ecdecodepub(&dom, Ys->data, Ys->len);
+       if(pub == nil){
+               ecdomfree(&dom);
+               return nil;
+       }
 
        memset(&Q, 0, sizeof(Q));
        Q.x = mpnew(0);
@@ -1012,48 +988,22 @@ tlsSecECDHEc(TlsSec *sec, uchar *srandom, int vers, int curve, Bytes *Ys)
        K.x = mpnew(0);
        K.y = mpnew(0);
 
-       memset(&Y, 0, sizeof(Y));
-       Y.x = mpnew(0);
-       Y.y = mpnew(0);
-
-       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);
+       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);
+       }
 
        mpfree(K.x);
        mpfree(K.y);
-
        mpfree(Q.x);
        mpfree(Q.y);
        mpfree(Q.d);
 
-       mpfree(G.x);
-       mpfree(G.y);
-
-       mpfree(dom.p);
-       mpfree(dom.a);
-       mpfree(dom.b);
-       mpfree(dom.n);
-       mpfree(dom.h);
+       ecpubfree(pub);
+       ecdomfree(&dom);
 
        return epm;
 }
@@ -1061,9 +1011,12 @@ Out:
 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,40 +1025,52 @@ verifyDHparams(TlsConnection *c, Bytes *par, Bytes *sig, int sigalg)
        if(sig == nil || sig->len <= 0){
                if(c->sec->psklen > 0)
                        return nil;
-
                return "no signature";
        }
 
        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;
 }
index 571889cb36c166f34807c18e3793e754163684ed..21d8cc9486f4f12b2276c809f418a57d4b5cf70f 100644 (file)
@@ -134,8 +134,7 @@ static int  encode(Elem e, Bytes** pbytes);
 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
@@ -223,6 +222,7 @@ ber_decode(uchar** pp, uchar* pend, Elem* pelem)
        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 @@ is_int(Elem* pe, int* pint)
 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 @@ typedef struct CertX509 {
        Bytes*  publickey;
        int     signature_alg;
        Bytes*  signature;
+       int     curve;
 } CertX509;
 
 /* Algorithm object-ids */
@@ -1553,6 +1541,12 @@ enum {
        ALG_sha512WithRSAEncryption,
        ALG_sha224WithRSAEncryption,
 
+       ALG_ecPublicKey,
+       ALG_sha1WithECDSA,
+       ALG_sha256WithECDSA,
+       ALG_sha384WithECDSA,
+       ALG_sha512WithECDSA,
+
        ALG_md5,
        ALG_sha1,
        ALG_sha256,
@@ -1587,6 +1581,7 @@ enum {
 };
 
 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_sha384WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 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 @@ static Ints *alg_oid_tab[NUMALGS+1] = {
        (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 @@ static DigestAlg *digestalg[NUMALGS+1] = {
        &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 @@ parse_alg(Elem* e)
        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 @@ decode_cert(Bytes* a)
                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 @@ decode_cert(Bytes* a)
        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 @@ static RSApub*
 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 @@ decode_rsaprivkey(Bytes* a)
        int version;
        Elem e;
        Elist *el;
-       mpint *mp;
        RSApriv* key;
 
        key = rsaprivalloc();
@@ -1929,47 +1955,41 @@ decode_rsaprivkey(Bytes* a)
                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 @@ decode_dsaprivkey(Bytes* a)
        int version;
        Elem e;
        Elist *el;
-       mpint *mp;
        DSApriv* key;
 
        key = dsaprivalloc();
@@ -2003,32 +2022,29 @@ decode_dsaprivkey(Bytes* a)
                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 @@ static mpint*
 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 @@ digest_certinfo(Bytes *cert, DigestAlg *da, uchar *digest)
        return da->len;
 }
 
-int
+static int
 pkcs1decryptsignature(uchar *sig, int siglen, RSApub *pk, uchar **pbuf)
 {
        int nlen, buflen;
@@ -2169,34 +2181,41 @@ bad:
        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 @@ end:
 }
 
 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 @@ X509toRSApub(uchar *cert, int ncert, char *name, int nname)
        char *e;
        Bytes *b;
        CertX509 *c;
-       RSApub *pk;
+       RSApub *pub;
 
        b = makebytes(cert, ncert);
        c = decode_cert(b);
@@ -2256,13 +2321,15 @@ X509toRSApub(uchar *cert, int ncert, char *name, int nname)
                        *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 @@ X509verify(uchar *cert, int ncert, RSApub *pk)
                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 @@ X509encodesignature_sha256(uchar digest[SHA2_256dlen], uchar *buf, int len)
 }
 
 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 @@ errret:
 }
 
 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 @@ X509dump(uchar *cert, int ncert)
        char *e;
        Bytes *b;
        CertX509 *c;
-       RSApub *pk;
+       RSApub *rsapub;
+       ECpub *ecpub;
+       ECdomain ecdom;
        int digestlen;
        uchar digest[MAXdlen];
 
@@ -2762,16 +2831,36 @@ X509dump(uchar *cert, int ncert)
        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);
-
-       rsapubfree(pk);
+       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 = 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");
 }