libsec: ecdsa client support for tlshand, cleanups

This commit is contained in:
cinap_lenrek 2016-02-01 21:34:49 +01:00
parent 0bfac109a4
commit a291bbdedd
12 changed files with 467 additions and 278 deletions

View 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 *);
/*

View 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).

View 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

View 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);

View 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");

View 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");

View 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);
}

View 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

View file

@ -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;
}

View file

@ -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;
}

View 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;
}

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