libsec: implement server side ECDHE key exchange with secp256r1, move DH state in TlsSec structure, simplify
implement ECDHE key exchange with secp256r1 on the server side, providing perfect forward secrecy (tho slowly). it is easier to just keep the ECDH/DH state in the TlsSec structure, which fits better with the grouping of the functions. we do the cleanup in tlsConnectionFree() now, so a lot of error handling logic could go away. reinvestigated some error paths and removed the ones that cannot error. move functions to fit the logical grouping. combine the code for signing handshake hashes (for client certs) and DH parameters. provide digestDHparams() function to be shared between server and client code.
This commit is contained in:
parent
9ba04fd030
commit
ff47cbd464
1 changed files with 393 additions and 237 deletions
|
@ -69,6 +69,14 @@ struct TlsSec {
|
||||||
uchar sec[MasterSecretSize]; // master secret
|
uchar sec[MasterSecretSize]; // master secret
|
||||||
uchar crandom[RandomSize]; // client random
|
uchar crandom[RandomSize]; // client random
|
||||||
uchar srandom[RandomSize]; // server random
|
uchar srandom[RandomSize]; // server random
|
||||||
|
|
||||||
|
// diffie hellman state
|
||||||
|
DHstate dh;
|
||||||
|
struct {
|
||||||
|
ECdomain dom;
|
||||||
|
ECpriv Q;
|
||||||
|
} ec;
|
||||||
|
|
||||||
// byte generation and handshake checksum
|
// byte generation and handshake checksum
|
||||||
void (*prf)(uchar*, int, uchar*, int, char*, uchar*, int, uchar*, int);
|
void (*prf)(uchar*, int, uchar*, int, char*, uchar*, int, uchar*, int);
|
||||||
void (*setFinished)(TlsSec*, HandshakeHash, uchar*, int);
|
void (*setFinished)(TlsSec*, HandshakeHash, uchar*, int);
|
||||||
|
@ -86,7 +94,7 @@ typedef struct TlsConnection{
|
||||||
int cipher;
|
int cipher;
|
||||||
int nsecret; // amount of secret data to init keys
|
int nsecret; // amount of secret data to init keys
|
||||||
char *digest; // name of digest algorithm to use
|
char *digest; // name of digest algorithm to use
|
||||||
char *enc; // name of encryption algorithm to use
|
char *enc; // name of encryption algorithm to use
|
||||||
|
|
||||||
// for finished messages
|
// for finished messages
|
||||||
HandshakeHash handhash;
|
HandshakeHash handhash;
|
||||||
|
@ -345,6 +353,7 @@ static struct {
|
||||||
DigestState* (*fun)(uchar*, ulong, uchar*, DigestState*);
|
DigestState* (*fun)(uchar*, ulong, uchar*, DigestState*);
|
||||||
int len;
|
int len;
|
||||||
} hashfun[] = {
|
} hashfun[] = {
|
||||||
|
/* [0x00] is reserved for MD5+SHA1 for < TLS1.2 */
|
||||||
[0x01] {md5, MD5dlen},
|
[0x01] {md5, MD5dlen},
|
||||||
[0x02] {sha1, SHA1dlen},
|
[0x02] {sha1, SHA1dlen},
|
||||||
[0x03] {sha2_224, SHA2_224dlen},
|
[0x03] {sha2_224, SHA2_224dlen},
|
||||||
|
@ -385,29 +394,38 @@ static int setSecrets(TlsConnection *c, int isclient);
|
||||||
static int finishedMatch(TlsConnection *c, Finished *f);
|
static int finishedMatch(TlsConnection *c, Finished *f);
|
||||||
static void tlsConnectionFree(TlsConnection *c);
|
static void tlsConnectionFree(TlsConnection *c);
|
||||||
|
|
||||||
|
static int isDHE(int tlsid);
|
||||||
|
static int isECDHE(int tlsid);
|
||||||
|
static int isPSK(int tlsid);
|
||||||
|
static int isECDSA(int tlsid);
|
||||||
|
|
||||||
static int setAlgs(TlsConnection *c, int a);
|
static int setAlgs(TlsConnection *c, int a);
|
||||||
static int okCipher(Ints *cv, int ispsk);
|
static int okCipher(Ints *cv, int ispsk);
|
||||||
static int okCompression(Bytes *cv);
|
static int okCompression(Bytes *cv);
|
||||||
static int initCiphers(void);
|
static int initCiphers(void);
|
||||||
static Ints* makeciphers(int ispsk);
|
static Ints* makeciphers(int ispsk);
|
||||||
|
|
||||||
|
static AuthRpc* factotum_rsa_open(RSApub *rsapub);
|
||||||
|
static mpint* factotum_rsa_decrypt(AuthRpc *rpc, mpint *cipher);
|
||||||
|
static void factotum_rsa_close(AuthRpc *rpc);
|
||||||
|
|
||||||
static void tlsSecInits(TlsSec *sec, int cvers, uchar *crandom);
|
static void tlsSecInits(TlsSec *sec, int cvers, uchar *crandom);
|
||||||
static int tlsSecRSAs(TlsSec *sec, Bytes *epm);
|
static int tlsSecRSAs(TlsSec *sec, Bytes *epm);
|
||||||
static void tlsSecPSKs(TlsSec *sec);
|
static Bytes* tlsSecECDHEs1(TlsSec *sec, Namedcurve *nc);
|
||||||
|
static int tlsSecECDHEs2(TlsSec *sec, Bytes *Yc);
|
||||||
static void tlsSecInitc(TlsSec *sec, int cvers);
|
static void tlsSecInitc(TlsSec *sec, int cvers);
|
||||||
static Bytes* tlsSecRSAc(TlsSec *sec, uchar *cert, int ncert);
|
static Bytes* tlsSecRSAc(TlsSec *sec, uchar *cert, int ncert);
|
||||||
static void tlsSecPSKc(TlsSec *sec);
|
|
||||||
static Bytes* tlsSecDHEc(TlsSec *sec, Bytes *p, Bytes *g, Bytes *Ys);
|
static Bytes* tlsSecDHEc(TlsSec *sec, Bytes *p, Bytes *g, Bytes *Ys);
|
||||||
static Bytes* tlsSecECDHEc(TlsSec *sec, int curve, Bytes *Ys);
|
static Bytes* tlsSecECDHEc(TlsSec *sec, int curve, Bytes *Ys);
|
||||||
static void tlsSecVers(TlsSec *sec, int v);
|
static void tlsSecVers(TlsSec *sec, int v);
|
||||||
static int tlsSecFinished(TlsSec *sec, HandshakeHash hsh, uchar *fin, int nfin, int isclient);
|
static int tlsSecFinished(TlsSec *sec, HandshakeHash hsh, uchar *fin, int nfin, int isclient);
|
||||||
static void setMasterSecret(TlsSec *sec, Bytes *pm);
|
static void setMasterSecret(TlsSec *sec, Bytes *pm);
|
||||||
|
static int digestDHparams(TlsSec *sec, Bytes *par, uchar digest[MAXdlen], int sigalg);
|
||||||
|
static char* verifyDHparams(TlsSec *sec, Bytes *par, Bytes *cert, Bytes *sig, int sigalg);
|
||||||
|
|
||||||
static Bytes* pkcs1_encrypt(Bytes* data, RSApub* key, int blocktype);
|
static Bytes* pkcs1_encrypt(Bytes* data, RSApub* key, int blocktype);
|
||||||
static Bytes* pkcs1_decrypt(TlsSec *sec, Bytes *cipher);
|
static Bytes* pkcs1_decrypt(TlsSec *sec, Bytes *cipher);
|
||||||
|
static Bytes* pkcs1_sign(TlsSec *sec, uchar *digest, int digestlen, int sigalg);
|
||||||
static AuthRpc* factotum_rsa_open(RSApub *rsapub);
|
|
||||||
static mpint* factotum_rsa_decrypt(AuthRpc *rpc, mpint *cipher);
|
|
||||||
static void factotum_rsa_close(AuthRpc *rpc);
|
|
||||||
|
|
||||||
static void* emalloc(int);
|
static void* emalloc(int);
|
||||||
static void* erealloc(void*, int);
|
static void* erealloc(void*, int);
|
||||||
|
@ -520,7 +538,7 @@ tlsClientExtensions(TLSconn *conn, int *plen)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ECDHE
|
// ECDHE
|
||||||
if(1){
|
if(ProtocolVersion >= TLS10Version){
|
||||||
m = p - b;
|
m = p - b;
|
||||||
b = erealloc(b, m + 2+2+2+nelem(namedcurves)*2 + 2+2+1+nelem(pointformats));
|
b = erealloc(b, m + 2+2+2+nelem(namedcurves)*2 + 2+2+1+nelem(pointformats));
|
||||||
p = b + m;
|
p = b + m;
|
||||||
|
@ -655,9 +673,9 @@ tlsServer2(int ctl, int hand,
|
||||||
char *pskid, uchar *psk, int psklen,
|
char *pskid, uchar *psk, int psklen,
|
||||||
int (*trace)(char*fmt, ...), PEMChain *chp)
|
int (*trace)(char*fmt, ...), PEMChain *chp)
|
||||||
{
|
{
|
||||||
|
int cipher, compressor, numcerts, i;
|
||||||
TlsConnection *c;
|
TlsConnection *c;
|
||||||
Msg m;
|
Msg m;
|
||||||
int cipher, compressor, numcerts, i;
|
|
||||||
|
|
||||||
if(trace)
|
if(trace)
|
||||||
trace("tlsServer2\n");
|
trace("tlsServer2\n");
|
||||||
|
@ -742,6 +760,36 @@ tlsServer2(int ctl, int hand,
|
||||||
goto Err;
|
goto Err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(isECDHE(cipher)){
|
||||||
|
Namedcurve *nc = &namedcurves[0]; /* secp256r1 */
|
||||||
|
|
||||||
|
m.tag = HServerKeyExchange;
|
||||||
|
m.u.serverKeyExchange.curve = nc->tlsid;
|
||||||
|
m.u.serverKeyExchange.dh_parameters = tlsSecECDHEs1(c->sec, nc);
|
||||||
|
if(m.u.serverKeyExchange.dh_parameters == nil){
|
||||||
|
tlsError(c, EInternalError, "can't set DH parameters");
|
||||||
|
goto Err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sign the DH parameters */
|
||||||
|
if(certlen > 0){
|
||||||
|
uchar digest[MAXdlen];
|
||||||
|
int digestlen;
|
||||||
|
|
||||||
|
if(c->version >= TLS12Version)
|
||||||
|
m.u.serverKeyExchange.sigalg = 0x0401; /* RSA SHA256 */
|
||||||
|
digestlen = digestDHparams(c->sec, m.u.serverKeyExchange.dh_parameters,
|
||||||
|
digest, m.u.serverKeyExchange.sigalg);
|
||||||
|
if((m.u.serverKeyExchange.dh_signature = pkcs1_sign(c->sec, digest, digestlen,
|
||||||
|
m.u.serverKeyExchange.sigalg)) == nil){
|
||||||
|
tlsError(c, EHandshakeFailure, "pkcs1_sign: %r");
|
||||||
|
goto Err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!msgSend(c, &m, AQueue))
|
||||||
|
goto Err;
|
||||||
|
}
|
||||||
|
|
||||||
m.tag = HServerHelloDone;
|
m.tag = HServerHelloDone;
|
||||||
if(!msgSend(c, &m, AFlush))
|
if(!msgSend(c, &m, AFlush))
|
||||||
goto Err;
|
goto Err;
|
||||||
|
@ -760,13 +808,18 @@ tlsServer2(int ctl, int hand,
|
||||||
goto Err;
|
goto Err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(certlen > 0){
|
if(isECDHE(cipher)){
|
||||||
|
if(tlsSecECDHEs2(c->sec, m.u.clientKeyExchange.key) < 0){
|
||||||
|
tlsError(c, EHandshakeFailure, "couldn't set keys: %r");
|
||||||
|
goto Err;
|
||||||
|
}
|
||||||
|
} else if(certlen > 0){
|
||||||
if(tlsSecRSAs(c->sec, m.u.clientKeyExchange.key) < 0){
|
if(tlsSecRSAs(c->sec, m.u.clientKeyExchange.key) < 0){
|
||||||
tlsError(c, EHandshakeFailure, "couldn't set keys: %r");
|
tlsError(c, EHandshakeFailure, "couldn't set keys: %r");
|
||||||
goto Err;
|
goto Err;
|
||||||
}
|
}
|
||||||
} else if(psklen > 0){
|
} else if(psklen > 0){
|
||||||
tlsSecPSKs(c->sec);
|
setMasterSecret(c->sec, newbytes(psklen));
|
||||||
} else {
|
} else {
|
||||||
tlsError(c, EInternalError, "no psk or certificate");
|
tlsError(c, EInternalError, "no psk or certificate");
|
||||||
goto Err;
|
goto Err;
|
||||||
|
@ -823,79 +876,29 @@ Err:
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
isDHE(int tlsid)
|
|
||||||
{
|
|
||||||
switch(tlsid){
|
|
||||||
case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
|
|
||||||
case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
|
|
||||||
case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
|
|
||||||
case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
|
|
||||||
case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
|
|
||||||
case TLS_DHE_RSA_WITH_CHACHA20_POLY1305:
|
|
||||||
case GOOGLE_DHE_RSA_WITH_CHACHA20_POLY1305:
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
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_GCM_SHA256:
|
|
||||||
case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
|
|
||||||
|
|
||||||
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:
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
isPSK(int tlsid)
|
|
||||||
{
|
|
||||||
switch(tlsid){
|
|
||||||
case TLS_PSK_WITH_CHACHA20_POLY1305:
|
|
||||||
case TLS_PSK_WITH_AES_128_CBC_SHA256:
|
|
||||||
case TLS_PSK_WITH_AES_128_CBC_SHA:
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Bytes*
|
static Bytes*
|
||||||
tlsSecDHEc(TlsSec *sec, Bytes *p, Bytes *g, Bytes *Ys)
|
tlsSecDHEc(TlsSec *sec, Bytes *p, Bytes *g, Bytes *Ys)
|
||||||
{
|
{
|
||||||
|
DHstate *dh = &sec->dh;
|
||||||
mpint *G, *P, *Y, *K;
|
mpint *G, *P, *Y, *K;
|
||||||
Bytes *epm;
|
Bytes *Yc;
|
||||||
DHstate dh;
|
|
||||||
|
|
||||||
if(p == nil || g == nil || Ys == nil)
|
if(p == nil || g == nil || Ys == nil)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
epm = nil;
|
Yc = nil;
|
||||||
P = bytestomp(p);
|
P = bytestomp(p);
|
||||||
G = bytestomp(g);
|
G = bytestomp(g);
|
||||||
Y = bytestomp(Ys);
|
Y = bytestomp(Ys);
|
||||||
K = nil;
|
K = nil;
|
||||||
|
|
||||||
if(P == nil || G == nil || Y == nil || dh_new(&dh, P, nil, G) == nil)
|
if(dh_new(dh, P, nil, G) == nil)
|
||||||
goto Out;
|
goto Out;
|
||||||
epm = mptobytes(dh.y);
|
Yc = mptobytes(dh->y);
|
||||||
K = dh_finish(&dh, Y);
|
K = dh_finish(dh, Y); /* zeros dh */
|
||||||
if(K == nil){
|
if(K == nil){
|
||||||
freebytes(epm);
|
freebytes(Yc);
|
||||||
epm = nil;
|
Yc = nil;
|
||||||
goto Out;
|
goto Out;
|
||||||
}
|
}
|
||||||
setMasterSecret(sec, mptobytes(K));
|
setMasterSecret(sec, mptobytes(K));
|
||||||
|
@ -906,132 +909,53 @@ Out:
|
||||||
mpfree(G);
|
mpfree(G);
|
||||||
mpfree(P);
|
mpfree(P);
|
||||||
|
|
||||||
return epm;
|
return Yc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Bytes*
|
static Bytes*
|
||||||
tlsSecECDHEc(TlsSec *sec, int curve, Bytes *Ys)
|
tlsSecECDHEc(TlsSec *sec, int curve, Bytes *Ys)
|
||||||
{
|
{
|
||||||
Namedcurve *nc, *enc;
|
ECdomain *dom = &sec->ec.dom;
|
||||||
Bytes *epm;
|
ECpriv *Q = &sec->ec.Q;
|
||||||
ECdomain dom;
|
Namedcurve *nc;
|
||||||
ECpub *pub;
|
ECpub *pub;
|
||||||
ECpoint K;
|
ECpoint K;
|
||||||
ECpriv Q;
|
Bytes *Yc;
|
||||||
|
|
||||||
if(Ys == nil)
|
if(Ys == nil)
|
||||||
return nil;
|
return nil;
|
||||||
|
for(nc = namedcurves; nc != &namedcurves[nelem(namedcurves)]; nc++)
|
||||||
enc = &namedcurves[nelem(namedcurves)];
|
|
||||||
for(nc = namedcurves; nc != enc; nc++)
|
|
||||||
if(nc->tlsid == curve)
|
if(nc->tlsid == curve)
|
||||||
break;
|
goto Found;
|
||||||
|
return nil;
|
||||||
|
|
||||||
if(nc == enc)
|
Found:
|
||||||
|
ecdominit(dom, nc->init);
|
||||||
|
pub = ecdecodepub(dom, Ys->data, Ys->len);
|
||||||
|
if(pub == nil)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
ecdominit(&dom, nc->init);
|
|
||||||
pub = ecdecodepub(&dom, Ys->data, Ys->len);
|
|
||||||
if(pub == nil){
|
|
||||||
ecdomfree(&dom);
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&Q, 0, sizeof(Q));
|
memset(Q, 0, sizeof(*Q));
|
||||||
Q.x = mpnew(0);
|
Q->x = mpnew(0);
|
||||||
Q.y = mpnew(0);
|
Q->y = mpnew(0);
|
||||||
Q.d = mpnew(0);
|
Q->d = mpnew(0);
|
||||||
|
|
||||||
memset(&K, 0, sizeof(K));
|
memset(&K, 0, sizeof(K));
|
||||||
K.x = mpnew(0);
|
K.x = mpnew(0);
|
||||||
K.y = mpnew(0);
|
K.y = mpnew(0);
|
||||||
|
|
||||||
epm = nil;
|
ecgen(dom, Q);
|
||||||
if(ecgen(&dom, &Q) != nil){
|
ecmul(dom, pub, Q->d, &K);
|
||||||
ecmul(&dom, pub, Q.d, &K);
|
setMasterSecret(sec, mptobytes(K.x));
|
||||||
setMasterSecret(sec, mptobytes(K.x));
|
Yc = newbytes(1 + 2*((mpsignif(dom->p)+7)/8));
|
||||||
epm = newbytes(1 + 2*((mpsignif(dom.p)+7)/8));
|
Yc->len = ecencodepub(dom, Q, Yc->data, Yc->len);
|
||||||
epm->len = ecencodepub(&dom, &Q, epm->data, epm->len);
|
|
||||||
}
|
|
||||||
|
|
||||||
mpfree(K.x);
|
mpfree(K.x);
|
||||||
mpfree(K.y);
|
mpfree(K.y);
|
||||||
mpfree(Q.x);
|
|
||||||
mpfree(Q.y);
|
|
||||||
mpfree(Q.d);
|
|
||||||
|
|
||||||
ecpubfree(pub);
|
ecpubfree(pub);
|
||||||
ecdomfree(&dom);
|
|
||||||
|
|
||||||
return epm;
|
return Yc;
|
||||||
}
|
|
||||||
|
|
||||||
static char*
|
|
||||||
verifyDHparams(TlsConnection *c, Bytes *par, Bytes *sig, int sigalg)
|
|
||||||
{
|
|
||||||
uchar digest[MAXdlen];
|
|
||||||
int digestlen;
|
|
||||||
ECdomain dom;
|
|
||||||
ECpub *ecpk;
|
|
||||||
RSApub *rsapk;
|
|
||||||
Bytes *blob;
|
|
||||||
char *err;
|
|
||||||
|
|
||||||
if(par == nil || par->len <= 0)
|
|
||||||
return "no DH parameters";
|
|
||||||
|
|
||||||
if(sig == nil || sig->len <= 0){
|
|
||||||
if(c->sec->psklen > 0)
|
|
||||||
return nil;
|
|
||||||
return "no signature";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(c->cert == nil)
|
|
||||||
return "no certificate";
|
|
||||||
|
|
||||||
blob = newbytes(2*RandomSize + par->len);
|
|
||||||
memmove(blob->data+0*RandomSize, c->sec->crandom, RandomSize);
|
|
||||||
memmove(blob->data+1*RandomSize, c->sec->srandom, RandomSize);
|
|
||||||
memmove(blob->data+2*RandomSize, par->data, par->len);
|
|
||||||
if(c->version < TLS12Version){
|
|
||||||
digestlen = MD5dlen + SHA1dlen;
|
|
||||||
md5(blob->data, blob->len, digest, nil);
|
|
||||||
sha1(blob->data, blob->len, digest+MD5dlen, nil);
|
|
||||||
sigalg = 1; // only RSA signatures supported for version <= TLS1.1
|
|
||||||
} else {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
freebytes(blob);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static TlsConnection *
|
static TlsConnection *
|
||||||
|
@ -1041,10 +965,10 @@ tlsClient2(int ctl, int hand,
|
||||||
uchar *ext, int extlen,
|
uchar *ext, int extlen,
|
||||||
int (*trace)(char*fmt, ...))
|
int (*trace)(char*fmt, ...))
|
||||||
{
|
{
|
||||||
TlsConnection *c;
|
|
||||||
Msg m;
|
|
||||||
int creq, dhx, cipher;
|
int creq, dhx, cipher;
|
||||||
|
TlsConnection *c;
|
||||||
Bytes *epm;
|
Bytes *epm;
|
||||||
|
Msg m;
|
||||||
|
|
||||||
if(!initCiphers())
|
if(!initCiphers())
|
||||||
return nil;
|
return nil;
|
||||||
|
@ -1130,10 +1054,11 @@ tlsClient2(int ctl, int hand,
|
||||||
}
|
}
|
||||||
if(m.tag == HServerKeyExchange) {
|
if(m.tag == HServerKeyExchange) {
|
||||||
if(dhx){
|
if(dhx){
|
||||||
char *err = verifyDHparams(c,
|
char *err = verifyDHparams(c->sec,
|
||||||
m.u.serverKeyExchange.dh_parameters,
|
m.u.serverKeyExchange.dh_parameters,
|
||||||
|
c->cert,
|
||||||
m.u.serverKeyExchange.dh_signature,
|
m.u.serverKeyExchange.dh_signature,
|
||||||
m.u.serverKeyExchange.sigalg);
|
c->version<TLS12Version ? 0x01 : m.u.serverKeyExchange.sigalg);
|
||||||
if(err != nil){
|
if(err != nil){
|
||||||
tlsError(c, EBadCertificate, "can't verify DH parameters: %s", err);
|
tlsError(c, EBadCertificate, "can't verify DH parameters: %s", err);
|
||||||
goto Err;
|
goto Err;
|
||||||
|
@ -1184,7 +1109,7 @@ tlsClient2(int ctl, int hand,
|
||||||
goto Err;
|
goto Err;
|
||||||
}
|
}
|
||||||
} else if(psklen > 0){
|
} else if(psklen > 0){
|
||||||
tlsSecPSKc(c->sec);
|
setMasterSecret(c->sec, newbytes(psklen));
|
||||||
} else {
|
} else {
|
||||||
tlsError(c, EInternalError, "no psk or certificate");
|
tlsError(c, EInternalError, "no psk or certificate");
|
||||||
goto Err;
|
goto Err;
|
||||||
|
@ -1224,39 +1149,28 @@ tlsClient2(int ctl, int hand,
|
||||||
|
|
||||||
/* certificate verify */
|
/* certificate verify */
|
||||||
if(creq && certlen > 0) {
|
if(creq && certlen > 0) {
|
||||||
mpint *signedMP, *paddedHashes;
|
|
||||||
HandshakeHash hsave;
|
HandshakeHash hsave;
|
||||||
uchar buf[512];
|
uchar digest[MAXdlen];
|
||||||
int buflen;
|
int digestlen;
|
||||||
|
|
||||||
/* save the state for the Finish message */
|
/* save the state for the Finish message */
|
||||||
hsave = c->handhash;
|
hsave = c->handhash;
|
||||||
if(c->version >= TLS12Version){
|
if(c->version < TLS12Version){
|
||||||
uchar digest[SHA2_256dlen];
|
md5(nil, 0, digest, &c->handhash.md5);
|
||||||
|
sha1(nil, 0, digest+MD5dlen, &c->handhash.sha1);
|
||||||
|
digestlen = MD5dlen+SHA1dlen;
|
||||||
|
} else {
|
||||||
m.u.certificateVerify.sigalg = 0x0401; /* RSA SHA256 */
|
m.u.certificateVerify.sigalg = 0x0401; /* RSA SHA256 */
|
||||||
sha2_256(nil, 0, digest, &c->handhash.sha2_256);
|
sha2_256(nil, 0, digest, &c->handhash.sha2_256);
|
||||||
buflen = asn1encodedigest(sha2_256, digest, buf, sizeof(buf));
|
digestlen = SHA2_256dlen;
|
||||||
} else {
|
|
||||||
md5(nil, 0, buf, &c->handhash.md5);
|
|
||||||
sha1(nil, 0, buf+MD5dlen, &c->handhash.sha1);
|
|
||||||
buflen = MD5dlen+SHA1dlen;
|
|
||||||
}
|
}
|
||||||
c->handhash = hsave;
|
c->handhash = hsave;
|
||||||
|
|
||||||
if(buflen <= 0){
|
if((m.u.certificateVerify.signature = pkcs1_sign(c->sec, digest, digestlen,
|
||||||
tlsError(c, EInternalError, "can't encode handshake hashes");
|
m.u.certificateVerify.sigalg)) == nil){
|
||||||
|
tlsError(c, EHandshakeFailure, "pkcs1_sign: %r");
|
||||||
goto Err;
|
goto Err;
|
||||||
}
|
}
|
||||||
|
|
||||||
paddedHashes = pkcs1padbuf(buf, buflen, c->sec->rsapub->n);
|
|
||||||
signedMP = factotum_rsa_decrypt(c->sec->rpc, paddedHashes);
|
|
||||||
if(signedMP == nil){
|
|
||||||
tlsError(c, EHandshakeFailure, "factotum_rsa_decrypt: %r");
|
|
||||||
goto Err;
|
|
||||||
}
|
|
||||||
m.u.certificateVerify.signature = mptobytes(signedMP);
|
|
||||||
mpfree(signedMP);
|
|
||||||
|
|
||||||
m.tag = HCertificateVerify;
|
m.tag = HCertificateVerify;
|
||||||
if(!msgSend(c, &m, AFlush))
|
if(!msgSend(c, &m, AFlush))
|
||||||
|
@ -1440,6 +1354,30 @@ msgSend(TlsConnection *c, Msg *m, int act)
|
||||||
memmove(p, m->u.certificateVerify.signature->data, m->u.certificateVerify.signature->len);
|
memmove(p, m->u.certificateVerify.signature->data, m->u.certificateVerify.signature->len);
|
||||||
p += m->u.certificateVerify.signature->len;
|
p += m->u.certificateVerify.signature->len;
|
||||||
break;
|
break;
|
||||||
|
case HServerKeyExchange:
|
||||||
|
if(m->u.serverKeyExchange.pskid != nil){
|
||||||
|
n = m->u.serverKeyExchange.pskid->len;
|
||||||
|
put16(p, n);
|
||||||
|
p += 2;
|
||||||
|
memmove(p, m->u.serverKeyExchange.pskid->data, n);
|
||||||
|
p += n;
|
||||||
|
}
|
||||||
|
if(m->u.serverKeyExchange.dh_parameters == nil)
|
||||||
|
break;
|
||||||
|
n = m->u.serverKeyExchange.dh_parameters->len;
|
||||||
|
memmove(p, m->u.serverKeyExchange.dh_parameters->data, n);
|
||||||
|
p += n;
|
||||||
|
if(m->u.serverKeyExchange.dh_signature == nil)
|
||||||
|
break;
|
||||||
|
if(c->version >= TLS12Version){
|
||||||
|
put16(p, m->u.serverKeyExchange.sigalg);
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
|
n = m->u.serverKeyExchange.dh_signature->len;
|
||||||
|
put16(p, n), p += 2;
|
||||||
|
memmove(p, m->u.serverKeyExchange.dh_signature->data, n);
|
||||||
|
p += n;
|
||||||
|
break;
|
||||||
case HClientKeyExchange:
|
case HClientKeyExchange:
|
||||||
if(m->u.clientKeyExchange.pskid != nil){
|
if(m->u.clientKeyExchange.pskid != nil){
|
||||||
n = m->u.clientKeyExchange.pskid->len;
|
n = m->u.clientKeyExchange.pskid->len;
|
||||||
|
@ -1823,10 +1761,6 @@ msgRecv(TlsConnection *c, Msg *m)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HClientKeyExchange:
|
case HClientKeyExchange:
|
||||||
/*
|
|
||||||
* this message depends upon the encryption selected
|
|
||||||
* assume rsa.
|
|
||||||
*/
|
|
||||||
if(isPSK(c->cipher)){
|
if(isPSK(c->cipher)){
|
||||||
if(n < 2)
|
if(n < 2)
|
||||||
goto Short;
|
goto Short;
|
||||||
|
@ -1844,8 +1778,12 @@ msgRecv(TlsConnection *c, Msg *m)
|
||||||
else{
|
else{
|
||||||
if(n < 2)
|
if(n < 2)
|
||||||
goto Short;
|
goto Short;
|
||||||
nn = get16(p);
|
if(isECDHE(c->cipher))
|
||||||
p += 2, n -= 2;
|
nn = *p++, n--;
|
||||||
|
else {
|
||||||
|
nn = get16(p);
|
||||||
|
p += 2, n -= 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(n < nn)
|
if(n < nn)
|
||||||
goto Short;
|
goto Short;
|
||||||
|
@ -1941,11 +1879,11 @@ bytesPrint(char *bs, char *be, char *s0, Bytes *b, char *s1)
|
||||||
if(b == nil)
|
if(b == nil)
|
||||||
bs = seprint(bs, be, "nil");
|
bs = seprint(bs, be, "nil");
|
||||||
else {
|
else {
|
||||||
bs = seprint(bs, be, "<%d> [", b->len);
|
bs = seprint(bs, be, "<%d> [ ", b->len);
|
||||||
for(i=0; i<b->len; i++)
|
for(i=0; i<b->len; i++)
|
||||||
bs = seprint(bs, be, "%.2x ", b->data[i]);
|
bs = seprint(bs, be, "%.2x ", b->data[i]);
|
||||||
|
bs = seprint(bs, be, "]");
|
||||||
}
|
}
|
||||||
bs = seprint(bs, be, "]");
|
|
||||||
if(s1)
|
if(s1)
|
||||||
bs = seprint(bs, be, "%s", s1);
|
bs = seprint(bs, be, "%s", s1);
|
||||||
return bs;
|
return bs;
|
||||||
|
@ -1958,13 +1896,14 @@ intsPrint(char *bs, char *be, char *s0, Ints *b, char *s1)
|
||||||
|
|
||||||
if(s0)
|
if(s0)
|
||||||
bs = seprint(bs, be, "%s", s0);
|
bs = seprint(bs, be, "%s", s0);
|
||||||
bs = seprint(bs, be, "[");
|
|
||||||
if(b == nil)
|
if(b == nil)
|
||||||
bs = seprint(bs, be, "nil");
|
bs = seprint(bs, be, "nil");
|
||||||
else
|
else {
|
||||||
|
bs = seprint(bs, be, "[ ");
|
||||||
for(i=0; i<b->len; i++)
|
for(i=0; i<b->len; i++)
|
||||||
bs = seprint(bs, be, "%x ", b->data[i]);
|
bs = seprint(bs, be, "%x ", b->data[i]);
|
||||||
bs = seprint(bs, be, "]");
|
bs = seprint(bs, be, "]");
|
||||||
|
}
|
||||||
if(s1)
|
if(s1)
|
||||||
bs = seprint(bs, be, "%s", s1);
|
bs = seprint(bs, be, "%s", s1);
|
||||||
return bs;
|
return bs;
|
||||||
|
@ -2116,9 +2055,18 @@ tlsConnectionFree(TlsConnection *c)
|
||||||
{
|
{
|
||||||
if(c == nil)
|
if(c == nil)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
dh_finish(&c->sec->dh, nil);
|
||||||
|
|
||||||
|
mpfree(c->sec->ec.Q.x);
|
||||||
|
mpfree(c->sec->ec.Q.y);
|
||||||
|
mpfree(c->sec->ec.Q.d);
|
||||||
|
ecdomfree(&c->sec->ec.dom);
|
||||||
|
|
||||||
factotum_rsa_close(c->sec->rpc);
|
factotum_rsa_close(c->sec->rpc);
|
||||||
rsapubfree(c->sec->rsapub);
|
rsapubfree(c->sec->rsapub);
|
||||||
freebytes(c->cert);
|
freebytes(c->cert);
|
||||||
|
|
||||||
memset(c, 0, sizeof(*c));
|
memset(c, 0, sizeof(*c));
|
||||||
free(c);
|
free(c);
|
||||||
}
|
}
|
||||||
|
@ -2126,6 +2074,69 @@ tlsConnectionFree(TlsConnection *c)
|
||||||
|
|
||||||
//================= cipher choices ========================
|
//================= cipher choices ========================
|
||||||
|
|
||||||
|
static int
|
||||||
|
isDHE(int tlsid)
|
||||||
|
{
|
||||||
|
switch(tlsid){
|
||||||
|
case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
|
||||||
|
case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
|
||||||
|
case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
|
||||||
|
case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
|
||||||
|
case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
|
||||||
|
case TLS_DHE_RSA_WITH_CHACHA20_POLY1305:
|
||||||
|
case GOOGLE_DHE_RSA_WITH_CHACHA20_POLY1305:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_GCM_SHA256:
|
||||||
|
case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
|
||||||
|
|
||||||
|
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:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
isPSK(int tlsid)
|
||||||
|
{
|
||||||
|
switch(tlsid){
|
||||||
|
case TLS_PSK_WITH_CHACHA20_POLY1305:
|
||||||
|
case TLS_PSK_WITH_AES_128_CBC_SHA256:
|
||||||
|
case TLS_PSK_WITH_AES_128_CBC_SHA:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
isECDSA(int tlsid)
|
||||||
|
{
|
||||||
|
switch(tlsid){
|
||||||
|
case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305:
|
||||||
|
case GOOGLE_ECDHE_ECDSA_WITH_CHACHA20_POLY1305:
|
||||||
|
case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
|
||||||
|
case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
setAlgs(TlsConnection *c, int a)
|
setAlgs(TlsConnection *c, int a)
|
||||||
{
|
{
|
||||||
|
@ -2152,8 +2163,8 @@ okCipher(Ints *cv, int ispsk)
|
||||||
|
|
||||||
for(i = 0; i < cv->len; i++) {
|
for(i = 0; i < cv->len; i++) {
|
||||||
c = cv->data[i];
|
c = cv->data[i];
|
||||||
if(isDHE(c) || isECDHE(c) || isPSK(c) != ispsk)
|
if(isECDSA(c) || isDHE(c) || isPSK(c) != ispsk)
|
||||||
continue; /* TODO: not implemented for server */
|
continue; /* not implemented for server */
|
||||||
for(j = 0; j < nelem(cipherAlgs); j++)
|
for(j = 0; j < nelem(cipherAlgs); j++)
|
||||||
if(cipherAlgs[j].ok && cipherAlgs[j].tlsid == c)
|
if(cipherAlgs[j].ok && cipherAlgs[j].tlsid == c)
|
||||||
return c;
|
return c;
|
||||||
|
@ -2261,7 +2272,6 @@ makeciphers(int ispsk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//================= security functions ========================
|
//================= security functions ========================
|
||||||
|
|
||||||
// given a public key, set up connection to factotum
|
// given a public key, set up connection to factotum
|
||||||
|
@ -2528,8 +2538,6 @@ tls12SetFinished(TlsSec *sec, HandshakeHash hsh, uchar *finished, int isclient)
|
||||||
p_sha256(finished, TLSFinishedLen, sec->sec, MasterSecretSize, (uchar*)label, strlen(label), seed, SHA2_256dlen);
|
p_sha256(finished, TLSFinishedLen, sec->sec, MasterSecretSize, (uchar*)label, strlen(label), seed, SHA2_256dlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* the keys are verified to have the same public components
|
|
||||||
* and to function correctly with pkcs 1 encryption and decryption. */
|
|
||||||
static void
|
static void
|
||||||
tlsSecInits(TlsSec *sec, int cvers, uchar *crandom)
|
tlsSecInits(TlsSec *sec, int cvers, uchar *crandom)
|
||||||
{
|
{
|
||||||
|
@ -2562,10 +2570,62 @@ tlsSecRSAs(TlsSec *sec, Bytes *epm)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static Bytes*
|
||||||
tlsSecPSKs(TlsSec *sec)
|
tlsSecECDHEs1(TlsSec *sec, Namedcurve *nc)
|
||||||
{
|
{
|
||||||
setMasterSecret(sec, newbytes(sec->psklen));
|
ECdomain *dom = &sec->ec.dom;
|
||||||
|
ECpriv *Q = &sec->ec.Q;
|
||||||
|
Bytes *par;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
ecdominit(dom, nc->init);
|
||||||
|
memset(Q, 0, sizeof(*Q));
|
||||||
|
Q->x = mpnew(0);
|
||||||
|
Q->y = mpnew(0);
|
||||||
|
Q->d = mpnew(0);
|
||||||
|
ecgen(dom, Q);
|
||||||
|
n = 1 + 2*((mpsignif(dom->p)+7)/8);
|
||||||
|
par = newbytes(1+2+1+n);
|
||||||
|
par->data[0] = 3;
|
||||||
|
put16(par->data+1, nc->tlsid);
|
||||||
|
n = ecencodepub(dom, Q, par->data+4, par->len-4);
|
||||||
|
par->data[3] = n;
|
||||||
|
par->len = 1+2+1+n;
|
||||||
|
|
||||||
|
return par;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
tlsSecECDHEs2(TlsSec *sec, Bytes *Yc)
|
||||||
|
{
|
||||||
|
ECdomain *dom = &sec->ec.dom;
|
||||||
|
ECpriv *Q = &sec->ec.Q;
|
||||||
|
ECpoint K;
|
||||||
|
ECpub *Y;
|
||||||
|
|
||||||
|
if(Yc == nil){
|
||||||
|
werrstr("no public key");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((Y = ecdecodepub(dom, Yc->data, Yc->len)) == nil){
|
||||||
|
werrstr("bad public key");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&K, 0, sizeof(K));
|
||||||
|
K.x = mpnew(0);
|
||||||
|
K.y = mpnew(0);
|
||||||
|
|
||||||
|
ecmul(dom, Y, Q->d, &K);
|
||||||
|
setMasterSecret(sec, mptobytes(K.x));
|
||||||
|
|
||||||
|
mpfree(K.x);
|
||||||
|
mpfree(K.y);
|
||||||
|
|
||||||
|
ecpubfree(Y);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -2577,12 +2637,6 @@ tlsSecInitc(TlsSec *sec, int cvers)
|
||||||
genrandom(sec->crandom+4, RandomSize-4);
|
genrandom(sec->crandom+4, RandomSize-4);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
tlsSecPSKc(TlsSec *sec)
|
|
||||||
{
|
|
||||||
setMasterSecret(sec, newbytes(sec->psklen));
|
|
||||||
}
|
|
||||||
|
|
||||||
static Bytes*
|
static Bytes*
|
||||||
tlsSecRSAc(TlsSec *sec, uchar *cert, int ncert)
|
tlsSecRSAc(TlsSec *sec, uchar *cert, int ncert)
|
||||||
{
|
{
|
||||||
|
@ -2695,28 +2749,82 @@ setMasterSecret(TlsSec *sec, Bytes *pm)
|
||||||
freebytes(pm);
|
freebytes(pm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static mpint*
|
static int
|
||||||
bytestomp(Bytes* bytes)
|
digestDHparams(TlsSec *sec, Bytes *par, uchar digest[MAXdlen], int sigalg)
|
||||||
{
|
{
|
||||||
return betomp(bytes->data, bytes->len, nil);
|
int hashalg = (sigalg>>8) & 0xFF;
|
||||||
|
int digestlen;
|
||||||
|
Bytes *blob;
|
||||||
|
|
||||||
|
blob = newbytes(2*RandomSize + par->len);
|
||||||
|
memmove(blob->data+0*RandomSize, sec->crandom, RandomSize);
|
||||||
|
memmove(blob->data+1*RandomSize, sec->srandom, RandomSize);
|
||||||
|
memmove(blob->data+2*RandomSize, par->data, par->len);
|
||||||
|
if(hashalg == 0){
|
||||||
|
digestlen = MD5dlen+SHA1dlen;
|
||||||
|
md5(blob->data, blob->len, digest, nil);
|
||||||
|
sha1(blob->data, blob->len, digest+MD5dlen, nil);
|
||||||
|
} else {
|
||||||
|
digestlen = -1;
|
||||||
|
if(hashalg < nelem(hashfun) && hashfun[hashalg].fun != nil){
|
||||||
|
digestlen = hashfun[hashalg].len;
|
||||||
|
(*hashfun[hashalg].fun)(blob->data, blob->len, digest, nil);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freebytes(blob);
|
||||||
|
return digestlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static char*
|
||||||
* Convert mpint* to Bytes, putting high order byte first.
|
verifyDHparams(TlsSec *sec, Bytes *par, Bytes *cert, Bytes *sig, int sigalg)
|
||||||
*/
|
|
||||||
static Bytes*
|
|
||||||
mptobytes(mpint* big)
|
|
||||||
{
|
{
|
||||||
Bytes* ans;
|
uchar digest[MAXdlen];
|
||||||
int n;
|
int digestlen;
|
||||||
|
ECdomain dom;
|
||||||
|
ECpub *ecpk;
|
||||||
|
RSApub *rsapk;
|
||||||
|
char *err;
|
||||||
|
|
||||||
n = (mpsignif(big)+7)/8;
|
if(par == nil || par->len <= 0)
|
||||||
if(n == 0) n = 1;
|
return "no DH parameters";
|
||||||
ans = newbytes(n);
|
|
||||||
mptober(big, ans->data, ans->len);
|
if(sig == nil || sig->len <= 0){
|
||||||
return ans;
|
if(sec->psklen > 0)
|
||||||
|
return nil;
|
||||||
|
return "no signature";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cert == nil)
|
||||||
|
return "no certificate";
|
||||||
|
|
||||||
|
digestlen = digestDHparams(sec, par, digest, sigalg);
|
||||||
|
if(digestlen <= 0)
|
||||||
|
return "unknown signature digest algorithm";
|
||||||
|
|
||||||
|
switch(sigalg & 0xFF){
|
||||||
|
case 0x01:
|
||||||
|
rsapk = X509toRSApub(cert->data, 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(cert->data, 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Do RSA computation on block according to key, and pad
|
// Do RSA computation on block according to key, and pad
|
||||||
// result on left with zeros to make it modlen long.
|
// result on left with zeros to make it modlen long.
|
||||||
static Bytes*
|
static Bytes*
|
||||||
|
@ -2817,6 +2925,32 @@ pkcs1_decrypt(TlsSec *sec, Bytes *cipher)
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Bytes*
|
||||||
|
pkcs1_sign(TlsSec *sec, uchar *digest, int digestlen, int sigalg)
|
||||||
|
{
|
||||||
|
int hashalg = (sigalg>>8)&0xFF;
|
||||||
|
mpint *signedMP;
|
||||||
|
Bytes *signature;
|
||||||
|
uchar buf[128];
|
||||||
|
|
||||||
|
if(hashalg > 0 && hashalg < nelem(hashfun) && hashfun[hashalg].len == digestlen)
|
||||||
|
digestlen = asn1encodedigest(hashfun[hashalg].fun, digest, buf, sizeof(buf));
|
||||||
|
else if(digestlen == MD5dlen+SHA1dlen)
|
||||||
|
memmove(buf, digest, digestlen);
|
||||||
|
else
|
||||||
|
digestlen = -1;
|
||||||
|
if(digestlen <= 0){
|
||||||
|
werrstr("bad digest algorithm");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
signedMP = factotum_rsa_decrypt(sec->rpc, pkcs1padbuf(buf, digestlen, sec->rsapub->n));
|
||||||
|
if(signedMP == nil)
|
||||||
|
return nil;
|
||||||
|
signature = mptobytes(signedMP);
|
||||||
|
mpfree(signedMP);
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//================= general utility functions ========================
|
//================= general utility functions ========================
|
||||||
|
|
||||||
|
@ -2920,6 +3054,28 @@ freebytes(Bytes* b)
|
||||||
free(b);
|
free(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static mpint*
|
||||||
|
bytestomp(Bytes* bytes)
|
||||||
|
{
|
||||||
|
return betomp(bytes->data, bytes->len, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert mpint* to Bytes, putting high order byte first.
|
||||||
|
*/
|
||||||
|
static Bytes*
|
||||||
|
mptobytes(mpint* big)
|
||||||
|
{
|
||||||
|
Bytes* ans;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
n = (mpsignif(big)+7)/8;
|
||||||
|
if(n == 0) n = 1;
|
||||||
|
ans = newbytes(n);
|
||||||
|
mptober(big, ans->data, ans->len);
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
/* len is number of ints */
|
/* len is number of ints */
|
||||||
static Ints*
|
static Ints*
|
||||||
newints(int len)
|
newints(int len)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue