From a291bbdeddfd41a2f0907ecbd7b819f0eedffdaf Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Mon, 1 Feb 2016 21:34:49 +0100 Subject: [PATCH] libsec: ecdsa client support for tlshand, cleanups --- sys/include/libsec.h | 27 ++- sys/man/2/ec | 19 ++ sys/man/2/rsa | 15 +- sys/src/cmd/auth/factotum/ecdsa.c | 12 +- sys/src/cmd/auth/rsa2csr.c | 2 +- sys/src/cmd/auth/rsa2x509.c | 2 +- sys/src/libsec/port/ecc.c | 80 ++++++- sys/src/libsec/port/mkfile | 10 + sys/src/libsec/port/secp256k1.mp | 10 + sys/src/libsec/port/secp256r1.mp | 10 + sys/src/libsec/port/tlshand.c | 215 ++++++++----------- sys/src/libsec/port/x509.c | 343 +++++++++++++++++++----------- 12 files changed, 467 insertions(+), 278 deletions(-) create mode 100644 sys/src/libsec/port/secp256k1.mp create mode 100644 sys/src/libsec/port/secp256r1.mp diff --git a/sys/include/libsec.h b/sys/include/libsec.h index 204ca4d26..09db4f0f0 100644 --- a/sys/include/libsec.h +++ b/sys/include/libsec.h @@ -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 *); /* diff --git a/sys/man/2/ec b/sys/man/2/ec index 431c15cfa..b4e0cc19e 100644 --- a/sys/man/2/ec +++ b/sys/man/2/ec @@ -19,6 +19,12 @@ ecdsaverify \- elliptic curve cryptography .B #include .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). diff --git a/sys/man/2/rsa b/sys/man/2/rsa index 957ac05c2..f4ad430b9 100644 --- a/sys/man/2/rsa +++ b/sys/man/2/rsa @@ -12,8 +12,9 @@ rsaprivtopub, rsapuballoc, rsapubfree, X509toRSApub, -X509gen, -X509verify \- RSA encryption algorithm +X509rsagen, +X509rsareq, +X509rsaverify \- RSA encryption algorithm .SH SYNOPSIS .B #include .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 diff --git a/sys/src/cmd/auth/factotum/ecdsa.c b/sys/src/cmd/auth/factotum/ecdsa.c index 31cc0853d..1c48c1a1b 100644 --- a/sys/src/cmd/auth/factotum/ecdsa.c +++ b/sys/src/cmd/auth/factotum/ecdsa.c @@ -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); diff --git a/sys/src/cmd/auth/rsa2csr.c b/sys/src/cmd/auth/rsa2csr.c index ebf3ab8b8..e4107a2d7 100644 --- a/sys/src/cmd/auth/rsa2csr.c +++ b/sys/src/cmd/auth/rsa2csr.c @@ -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"); diff --git a/sys/src/cmd/auth/rsa2x509.c b/sys/src/cmd/auth/rsa2x509.c index 476e09b46..3e07bb88f 100644 --- a/sys/src/cmd/auth/rsa2x509.c +++ b/sys/src/cmd/auth/rsa2x509.c @@ -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"); diff --git a/sys/src/libsec/port/ecc.c b/sys/src/libsec/port/ecc.c index 04d130c5b..7d3e32648 100644 --- a/sys/src/libsec/port/ecc.c +++ b/sys/src/libsec/port/ecc.c @@ -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); +} diff --git a/sys/src/libsec/port/mkfile b/sys/src/libsec/port/mkfile index 113cb3385..55e7a8c95 100644 --- a/sys/src/libsec/port/mkfile +++ b/sys/src/libsec/port/mkfile @@ -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\ ' > $target + echo '#include ' >> $target + echo '#include ' >> $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 index 000000000..216b9149d --- /dev/null +++ b/sys/src/libsec/port/secp256k1.mp @@ -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 index 000000000..5175c919b --- /dev/null +++ b/sys/src/libsec/port/secp256r1.mp @@ -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; +} diff --git a/sys/src/libsec/port/tlshand.c b/sys/src/libsec/port/tlshand.c index 1a37ef94b..8f245625a 100644 --- a/sys/src/libsec/port/tlshand.c +++ b/sys/src/libsec/port/tlshand.c @@ -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; } diff --git a/sys/src/libsec/port/x509.c b/sys/src/libsec/port/x509.c index 571889cb3..21d8cc948 100644 --- a/sys/src/libsec/port/x509.c +++ b/sys/src/libsec/port/x509.c @@ -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,64 +2224,60 @@ 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; } -char* -X509verifydata(uchar *sig, int siglen, uchar *data, int datalen, RSApub *pk) +ECpub* +X509toECpub(uchar *cert, int ncert, ECdomain *dom) { - uchar digest[MAXdlen], edigest[MAXdlen]; - int sigalg; - char *e; - - 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; -} - -RSApub* -X509toRSApub(uchar *cert, int ncert, char *name, int nname) -{ - char *e; - Bytes *b; CertX509 *c; - RSApub *pk; + ECpub *pub; + Bytes *b; b = makebytes(cert, ncert); c = decode_cert(b); freebytes(b); if(c == nil) return nil; - if(name != nil && c->subject != nil){ - e = strchr(c->subject, ','); - if(e != nil) - *e = 0; /* take just CN part of Distinguished Name */ - strncpy(name, c->subject, nname); + 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); } - pk = decode_rsapubkey(c->publickey); freecert(c); - return pk; + return pub; } char* -X509verify(uchar *cert, int ncert, RSApub *pk) +X509ecdsaverify(uchar *cert, int ncert, ECdomain *dom, ECpub *pk) { char *e; Bytes *b; @@ -2282,7 +2297,59 @@ 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 = X509ecdsaverifydigest(c->signature->data, c->signature->len, digest, digestlen, dom, pk); + freecert(c); + return e; +} + +RSApub* +X509toRSApub(uchar *cert, int ncert, char *name, int nname) +{ + char *e; + Bytes *b; + CertX509 *c; + RSApub *pub; + + b = makebytes(cert, ncert); + c = decode_cert(b); + freebytes(b); + if(c == nil) + return nil; + if(name != nil && c->subject != nil){ + e = strchr(c->subject, ','); + if(e != nil) + *e = 0; /* take just CN part of Distinguished Name */ + strncpy(name, c->subject, nname); + } + pub = nil; + if(c->publickey_alg == ALG_rsaEncryption) + pub = decode_rsapubkey(c->publickey); + freecert(c); + return pub; +} + +char* +X509rsaverify(uchar *cert, int ncert, RSApub *pk) +{ + char *e; + Bytes *b; + CertX509 *c; + int digestlen; + uchar digest[MAXdlen]; + + 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 = 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); + 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"); }