ref: a291bbdeddfd41a2f0907ecbd7b819f0eedffdaf
parent: 0bfac109a491e61d7cd585060b88e1251da1e928
author: cinap_lenrek <cinap_lenrek@felloff.net>
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");
}