ref: f85ef344505b687ed057d5f452db033292253f00
parent: 72da0579a82cc83574d6f5eb7710d702d6df865e
author: cinap_lenrek <[email protected]>
date: Mon Apr 25 18:44:03 EDT 2016
libsec: update ecc and tlshand (sync with 9front)
--- a/include/libsec.h
+++ b/include/libsec.h
@@ -485,6 +485,7 @@
int inf;
mpint *x;
mpint *y;
+ mpint *z;
} ECpoint;
typedef ECpoint ECpub;
--- a/libsec/Makefile
+++ b/libsec/Makefile
@@ -26,6 +26,7 @@
dsasign.$O\
dsaverify.$O\
ecc.$O\
+ jacobian.$O\
egalloc.$O\
egdecrypt.$O\
egencrypt.$O\
--- a/libsec/ecc.c
+++ b/libsec/ecc.c
@@ -3,20 +3,38 @@
#include <libsec.h>
#include <ctype.h>
+extern void jacobian_affine(mpint *p,
+ mpint *X, mpint *Y, mpint *Z);
+extern void jacobian_dbl(mpint *p, mpint *a,
+ mpint *X1, mpint *Y1, mpint *Z1,
+ mpint *X3, mpint *Y3, mpint *Z3);
+extern void jacobian_add(mpint *p, mpint *a,
+ mpint *X1, mpint *Y1, mpint *Z1,
+ mpint *X2, mpint *Y2, mpint *Z2,
+ mpint *X3, mpint *Y3, mpint *Z3);
+
void
ecassign(ECdomain *dom, ECpoint *a, ECpoint *b)
{
- USED(dom);
- b->inf = a->inf;
+ if((b->inf = a->inf) != 0)
+ return;
mpassign(a->x, b->x);
mpassign(a->y, b->y);
+ if(b->z != nil){
+ mpassign(a->z != nil ? a->z : mpone, b->z);
+ return;
+ }
+ if(a->z != nil){
+ b->z = mpcopy(a->z);
+ jacobian_affine(dom->p, b->x, b->y, b->z);
+ mpfree(b->z);
+ b->z = nil;
+ }
}
void
ecadd(ECdomain *dom, ECpoint *a, ECpoint *b, ECpoint *s)
{
- mpint *l, *k, *sx, *sy;
-
if(a->inf && b->inf){
s->inf = 1;
return;
@@ -29,66 +47,27 @@
ecassign(dom, a, s);
return;
}
- if(mpcmp(a->x, b->x) == 0 && (mpcmp(a->y, mpzero) == 0 || mpcmp(a->y, b->y) != 0)){
- s->inf = 1;
- return;
- }
- l = mpnew(0);
- k = mpnew(0);
- sx = mpnew(0);
- sy = mpnew(0);
- if(mpcmp(a->x, b->x) == 0 && mpcmp(a->y, b->y) == 0){
- mpadd(mpone, mptwo, k);
- mpmul(a->x, a->x, l);
- mpmul(l, k, l);
- mpadd(l, dom->a, l);
- mpleft(a->y, 1, k);
- mpmod(k, dom->p, k);
- mpinvert(k, dom->p, k);
- mpmul(k, l, l);
- mpmod(l, dom->p, l);
- mpleft(a->x, 1, k);
- mpmul(l, l, sx);
- mpsub(sx, k, sx);
- mpmod(sx, dom->p, sx);
-
- mpsub(a->x, sx, sy);
- mpmul(l, sy, sy);
- mpsub(sy, a->y, sy);
- mpmod(sy, dom->p, sy);
- mpassign(sx, s->x);
- mpassign(sy, s->y);
- mpfree(sx);
- mpfree(sy);
- mpfree(l);
- mpfree(k);
+ if(s->z == nil){
+ s->z = mpcopy(mpone);
+ ecadd(dom, a, b, s);
+ if(!s->inf)
+ jacobian_affine(dom->p, s->x, s->y, s->z);
+ mpfree(s->z);
+ s->z = nil;
return;
}
- mpsub(b->y, a->y, l);
- mpmod(l, dom->p, l);
- mpsub(b->x, a->x, k);
- mpmod(k, dom->p, k);
- mpinvert(k, dom->p, k);
- mpmul(k, l, l);
- mpmod(l, dom->p, l);
-
- mpmul(l, l, sx);
- mpsub(sx, a->x, sx);
- mpsub(sx, b->x, sx);
- mpmod(sx, dom->p, sx);
-
- mpsub(a->x, sx, sy);
- mpmul(sy, l, sy);
- mpsub(sy, a->y, sy);
- mpmod(sy, dom->p, sy);
-
- mpassign(sx, s->x);
- mpassign(sy, s->y);
- mpfree(sx);
- mpfree(sy);
- mpfree(l);
- mpfree(k);
+
+ if(a == b)
+ jacobian_dbl(dom->p, dom->a,
+ a->x, a->y, a->z != nil ? a->z : mpone,
+ s->x, s->y, s->z);
+ else
+ jacobian_add(dom->p, dom->a,
+ a->x, a->y, a->z != nil ? a->z : mpone,
+ b->x, b->y, b->z != nil ? b->z : mpone,
+ s->x, s->y, s->z);
+ s->inf = mpcmp(s->z, mpzero) == 0;
}
void
@@ -104,8 +83,10 @@
ns.inf = 1;
ns.x = mpnew(0);
ns.y = mpnew(0);
+ ns.z = mpnew(0);
na.x = mpnew(0);
na.y = mpnew(0);
+ na.z = mpnew(0);
ecassign(dom, a, &na);
l = mpcopy(k);
l->sign = 1;
@@ -115,7 +96,7 @@
ecadd(dom, &na, &na, &na);
mpright(l, 1, l);
}
- if(k->sign < 0){
+ if(k->sign < 0 && !ns.inf){
ns.y->sign = -1;
mpmod(ns.y, dom->p, ns.y);
}
@@ -122,8 +103,10 @@
ecassign(dom, &ns, s);
mpfree(ns.x);
mpfree(ns.y);
+ mpfree(ns.z);
mpfree(na.x);
mpfree(na.y);
+ mpfree(na.z);
mpfree(l);
}
@@ -135,16 +118,15 @@
if(a->inf)
return 1;
-
+
+ assert(a->z == nil); /* need affine coordinates */
p = mpnew(0);
q = mpnew(0);
- mpmul(a->y, a->y, p);
- mpmod(p, dom->p, p);
- mpmul(a->x, a->x, q);
- mpadd(q, dom->a, q);
- mpmul(a->x, q, q);
- mpadd(q, dom->b, q);
- mpmod(q, dom->p, q);
+ mpmodmul(a->y, a->y, dom->p, p);
+ mpmodmul(a->x, a->x, dom->p, q);
+ mpmodadd(q, dom->a, dom->p, q);
+ mpmodmul(q, a->x, dom->p, q);
+ mpmodadd(q, dom->b, dom->p, q);
r = mpcmp(p, q);
mpfree(p);
mpfree(q);
@@ -163,10 +145,12 @@
return 0;
p.x = mpnew(0);
p.y = mpnew(0);
+ p.z = mpnew(0);
ecmul(dom, a, dom->n, &p);
r = p.inf;
mpfree(p.x);
mpfree(p.y);
+ mpfree(p.z);
return r;
}
@@ -273,8 +257,8 @@
zq = mpnew(0);
for(;;){
for(;;){
- mprand(mpsignif(p), genrandom, a);
- if(mpcmp(a, mpzero) > 0 && mpcmp(a, p) < 0)
+ mpnrand(p, genrandom, a);
+ if(mpcmp(a, mpzero) > 0)
break;
}
mpmul(a, a, t);
@@ -346,11 +330,12 @@
ret->x = mpnew(0);
ret->y = mpnew(0);
}
+ ret->inf = 0;
o = 0;
switch(octet(&s)){
case 0:
ret->inf = 1;
- return ret;
+ break;
case 3:
o = 1;
case 2:
@@ -371,7 +356,7 @@
mpfree(r);
if(!ecverify(dom, ret))
goto err;
- return ret;
+ break;
case 4:
if(halfpt(dom, s, &s, ret->x) == nil)
goto err;
@@ -379,8 +364,12 @@
goto err;
if(!ecverify(dom, ret))
goto err;
- return ret;
+ break;
}
+ if(ret->z != nil && !ret->inf)
+ mpassign(mpone, ret->z);
+ return ret;
+
err:
if(rptr)
*rptr = s;
@@ -404,11 +393,11 @@
p->d = mpnew(0);
}
for(;;){
- mprand(mpsignif(dom->n), genrandom, p->d);
- if(mpcmp(p->d, mpzero) > 0 && mpcmp(p->d, dom->n) < 0)
+ mpnrand(dom->n, genrandom, p->d);
+ if(mpcmp(p->d, mpzero) > 0)
break;
}
- ecmul(dom, &dom->G, p->d, (ECpoint*)p);
+ ecmul(dom, &dom->G, p->d, &p->a);
return p;
}
@@ -420,6 +409,7 @@
tmp.a.x = mpnew(0);
tmp.a.y = mpnew(0);
+ tmp.a.z = nil;
tmp.d = mpnew(0);
E = betomp(dig, len, nil);
t = mpnew(0);
@@ -433,8 +423,7 @@
mpmul(r, priv->d, s);
mpadd(E, s, s);
mpinvert(tmp.d, dom->n, t);
- mpmul(s, t, s);
- mpmod(s, dom->n, s);
+ mpmodmul(s, t, dom->n, s);
if(mpcmp(s, mpzero) != 0)
break;
}
@@ -462,18 +451,19 @@
u2 = mpnew(0);
R.x = mpnew(0);
R.y = mpnew(0);
+ R.z = mpnew(0);
S.x = mpnew(0);
S.y = mpnew(0);
+ S.z = mpnew(0);
mpinvert(s, dom->n, t);
- mpmul(E, t, u1);
- mpmod(u1, dom->n, u1);
- mpmul(r, t, u2);
- mpmod(u2, dom->n, u2);
+ mpmodmul(E, t, dom->n, u1);
+ mpmodmul(r, t, dom->n, u2);
ecmul(dom, &dom->G, u1, &R);
ecmul(dom, pub, u2, &S);
ecadd(dom, &R, &S, &R);
ret = 0;
if(!R.inf){
+ jacobian_affine(dom->p, R.x, R.y, R.z);
mpmod(R.x, dom->n, t);
ret = mpcmp(r, t) == 0;
}
@@ -483,8 +473,10 @@
mpfree(u2);
mpfree(R.x);
mpfree(R.y);
+ mpfree(R.z);
mpfree(S.x);
mpfree(S.y);
+ mpfree(S.z);
return ret;
}
--- /dev/null
+++ b/libsec/jacobian.c
@@ -1,0 +1,166 @@
+#include "os.h"
+#include <mp.h>
+void jacobian_new(mpint *x, mpint *y, mpint *z, mpint *X, mpint *Y, mpint *Z){
+ mpassign(x, X);
+ mpassign(y, Y);
+ mpassign(z, Z);
+ }
+void jacobian_inf(mpint *X, mpint *Y, mpint *Z){
+ jacobian_new(mpzero, mpone, mpzero, X, Y, Z);
+ }
+void jacobian_affine(mpint *p, mpint *X, mpint *Y, mpint *Z){
+ mpint *ZZZ = mpnew(0);
+ mpint *ZZ = mpnew(0);
+ if(mpcmp(Z, mpzero) != 0){
+ mpmodmul(Z, Z, p, ZZ);
+ mpmodmul(ZZ, Z, p, ZZZ);
+ mpint *tmp1 = mpnew(0);
+ mpinvert(ZZ, p, tmp1);
+ mpmodmul(X, tmp1, p, X);
+ mpfree(tmp1);
+ tmp1 = mpnew(0);
+ mpinvert(ZZZ, p, tmp1);
+ mpmodmul(Y, tmp1, p, Y);
+ mpfree(tmp1);
+ mpassign(mpone, Z);
+ }
+ mpfree(ZZZ);
+ mpfree(ZZ);
+ }
+void jacobian_dbl(mpint *p, mpint *a, mpint *X1, mpint *Y1, mpint *Z1, mpint *X3, mpint *Y3, mpint *Z3){
+ mpint *M = mpnew(0);
+ mpint *S = mpnew(0);
+ mpint *ZZ = mpnew(0);
+ mpint *YYYY = mpnew(0);
+ mpint *YY = mpnew(0);
+ mpint *XX = mpnew(0);
+ if(mpcmp(Y1, mpzero) == 0){
+ jacobian_inf(X3, Y3, Z3);
+ }else{
+ mpmodmul(X1, X1, p, XX);
+ mpmodmul(Y1, Y1, p, YY);
+ mpmodmul(YY, YY, p, YYYY);
+ mpmodmul(Z1, Z1, p, ZZ);
+ mpint *tmp1 = mpnew(0);
+ mpmodadd(X1, YY, p, tmp1);
+ mpmodmul(tmp1, tmp1, p, tmp1);
+ mpmodsub(tmp1, XX, p, tmp1);
+ mpmodsub(tmp1, YYYY, p, tmp1);
+ mpmodadd(tmp1, tmp1, p, S); // 2*tmp1
+ mpfree(tmp1);
+ tmp1 = mpnew(0);
+ uitomp(3UL, tmp1);
+ mpmodmul(tmp1, XX, p, M);
+ mpfree(tmp1);
+ tmp1 = mpnew(0);
+ mpint *tmp2 = mpnew(0);
+ mpmodmul(ZZ, ZZ, p, tmp2);
+ mpmodmul(a, tmp2, p, tmp1);
+ mpfree(tmp2);
+ mpmodadd(M, tmp1, p, M);
+ mpfree(tmp1);
+ mpmodadd(Y1, Z1, p, Z3);
+ mpmodmul(Z3, Z3, p, Z3);
+ mpmodsub(Z3, YY, p, Z3);
+ mpmodsub(Z3, ZZ, p, Z3);
+ mpmodmul(M, M, p, X3);
+ tmp1 = mpnew(0);
+ mpmodadd(S, S, p, tmp1); // 2*S
+ mpmodsub(X3, tmp1, p, X3);
+ mpfree(tmp1);
+ tmp1 = mpnew(0);
+ mpmodsub(S, X3, p, tmp1);
+ mpmodmul(M, tmp1, p, Y3);
+ mpfree(tmp1);
+ tmp1 = mpnew(0);
+ tmp2 = mpnew(0);
+ uitomp(8UL, tmp2);
+ mpmodmul(tmp2, YYYY, p, tmp1);
+ mpfree(tmp2);
+ mpmodsub(Y3, tmp1, p, Y3);
+ mpfree(tmp1);
+ }
+ mpfree(M);
+ mpfree(S);
+ mpfree(ZZ);
+ mpfree(YYYY);
+ mpfree(YY);
+ mpfree(XX);
+ }
+void jacobian_add(mpint *p, mpint *a, mpint *X1, mpint *Y1, mpint *Z1, mpint *X2, mpint *Y2, mpint *Z2, mpint *X3, mpint *Y3, mpint *Z3){
+ mpint *V = mpnew(0);
+ mpint *r = mpnew(0);
+ mpint *J = mpnew(0);
+ mpint *I = mpnew(0);
+ mpint *H = mpnew(0);
+ mpint *S2 = mpnew(0);
+ mpint *S1 = mpnew(0);
+ mpint *U2 = mpnew(0);
+ mpint *U1 = mpnew(0);
+ mpint *Z2Z2 = mpnew(0);
+ mpint *Z1Z1 = mpnew(0);
+ mpmodmul(Z1, Z1, p, Z1Z1);
+ mpmodmul(Z2, Z2, p, Z2Z2);
+ mpmodmul(X1, Z2Z2, p, U1);
+ mpmodmul(X2, Z1Z1, p, U2);
+ mpint *tmp1 = mpnew(0);
+ mpmodmul(Y1, Z2, p, tmp1);
+ mpmodmul(tmp1, Z2Z2, p, S1);
+ mpfree(tmp1);
+ tmp1 = mpnew(0);
+ mpmodmul(Y2, Z1, p, tmp1);
+ mpmodmul(tmp1, Z1Z1, p, S2);
+ mpfree(tmp1);
+ if(mpcmp(U1, U2) == 0){
+ if(mpcmp(S1, S2) != 0){
+ jacobian_inf(X3, Y3, Z3);
+ }else{
+ jacobian_dbl(p, a, X1, Y1, Z1, X3, Y3, Z3);
+ }
+ }else{
+ mpmodsub(U2, U1, p, H);
+ mpmodadd(H, H, p, I); // 2*H
+ mpmodmul(I, I, p, I);
+ mpmodmul(H, I, p, J);
+ mpint *tmp2 = mpnew(0);
+ mpmodsub(S2, S1, p, tmp2);
+ mpmodadd(tmp2, tmp2, p, r); // 2*tmp2
+ mpfree(tmp2);
+ mpmodmul(U1, I, p, V);
+ mpmodmul(r, r, p, X3);
+ mpmodsub(X3, J, p, X3);
+ tmp2 = mpnew(0);
+ mpmodadd(V, V, p, tmp2); // 2*V
+ mpmodsub(X3, tmp2, p, X3);
+ mpfree(tmp2);
+ tmp2 = mpnew(0);
+ mpmodsub(V, X3, p, tmp2);
+ mpmodmul(r, tmp2, p, Y3);
+ mpfree(tmp2);
+ tmp2 = mpnew(0);
+ mpint *tmp3 = mpnew(0);
+ mpmodadd(S1, S1, p, tmp3); // 2*S1
+ mpmodmul(tmp3, J, p, tmp2);
+ mpfree(tmp3);
+ mpmodsub(Y3, tmp2, p, Y3);
+ mpfree(tmp2);
+ tmp2 = mpnew(0);
+ mpmodadd(Z1, Z2, p, tmp2);
+ mpmodmul(tmp2, tmp2, p, tmp2);
+ mpmodsub(tmp2, Z1Z1, p, tmp2);
+ mpmodsub(tmp2, Z2Z2, p, tmp2);
+ mpmodmul(tmp2, H, p, Z3);
+ mpfree(tmp2);
+ }
+ mpfree(V);
+ mpfree(r);
+ mpfree(J);
+ mpfree(I);
+ mpfree(H);
+ mpfree(S2);
+ mpfree(S1);
+ mpfree(U2);
+ mpfree(U1);
+ mpfree(Z2Z2);
+ mpfree(Z1Z1);
+ }
--- a/libsec/tlshand.c
+++ b/libsec/tlshand.c
@@ -69,6 +69,14 @@
uchar sec[MasterSecretSize]; // master secret
uchar crandom[RandomSize]; // client random
uchar srandom[RandomSize]; // server random
+
+ // diffie hellman state
+ DHstate dh;
+ struct {
+ ECdomain dom;
+ ECpriv Q;
+ } ec;
+
// byte generation and handshake checksum
void (*prf)(uchar*, int, uchar*, int, char*, uchar*, int, uchar*, int);
void (*setFinished)(TlsSec*, HandshakeHash, uchar*, int);
@@ -86,7 +94,7 @@
int cipher;
int nsecret; // amount of secret data to init keys
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
HandshakeHash handhash;
@@ -203,6 +211,7 @@
EProtocolVersion = 70,
EInsufficientSecurity = 71,
EInternalError = 80,
+ EInappropriateFallback = 86,
EUserCanceled = 90,
ENoRenegotiation = 100,
EUnknownPSKidentity = 115,
@@ -287,6 +296,8 @@
TLS_PSK_WITH_CHACHA20_POLY1305 = 0xCCAB,
TLS_PSK_WITH_AES_128_CBC_SHA256 = 0x00AE,
TLS_PSK_WITH_AES_128_CBC_SHA = 0x008C,
+
+ TLS_FALLBACK_SCSV = 0x5600,
};
// compression methods
@@ -296,34 +307,38 @@
};
static Algs cipherAlgs[] = {
- {"ccpoly96_aead", "clear", 2*(32+12), TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305},
+ // ECDHE-ECDSA
{"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_gcm_aead", "clear", 2*(16+4), TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
{"aes_128_gcm_aead", "clear", 2*(16+4), TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
- {"aes_128_gcm_aead", "clear", 2*(16+4), TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
- {"aes_128_gcm_aead", "clear", 2*(16+4), TLS_RSA_WITH_AES_128_GCM_SHA256},
-
{"aes_128_cbc", "sha256", 2*(16+16+SHA2_256dlen), TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256},
+
+ // ECDHE-RSA
+ {"ccpoly96_aead", "clear", 2*(32+12), TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305},
+ {"ccpoly64_aead", "clear", 2*32, GOOGLE_ECDHE_RSA_WITH_CHACHA20_POLY1305},
+ {"aes_128_gcm_aead", "clear", 2*(16+4), TLS_ECDHE_RSA_WITH_AES_128_GCM_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},
+
+ // DHE-RSA
+ {"ccpoly96_aead", "clear", 2*(32+12), TLS_DHE_RSA_WITH_CHACHA20_POLY1305},
+ {"ccpoly64_aead", "clear", 2*32, GOOGLE_DHE_RSA_WITH_CHACHA20_POLY1305},
+ {"aes_128_gcm_aead", "clear", 2*(16+4), TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
{"aes_128_cbc", "sha256", 2*(16+16+SHA2_256dlen), TLS_DHE_RSA_WITH_AES_128_CBC_SHA256},
{"aes_128_cbc", "sha1", 2*(16+16+SHA1dlen), TLS_DHE_RSA_WITH_AES_128_CBC_SHA},
{"aes_256_cbc", "sha1", 2*(32+16+SHA1dlen), TLS_DHE_RSA_WITH_AES_256_CBC_SHA},
+ {"3des_ede_cbc","sha1", 2*(4*8+SHA1dlen), TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA},
+
+ // RSA
+ {"aes_128_gcm_aead", "clear", 2*(16+4), TLS_RSA_WITH_AES_128_GCM_SHA256},
{"aes_128_cbc", "sha256", 2*(16+16+SHA2_256dlen), TLS_RSA_WITH_AES_128_CBC_SHA256},
{"aes_256_cbc", "sha256", 2*(32+16+SHA2_256dlen), TLS_RSA_WITH_AES_256_CBC_SHA256},
{"aes_128_cbc", "sha1", 2*(16+16+SHA1dlen), TLS_RSA_WITH_AES_128_CBC_SHA},
{"aes_256_cbc", "sha1", 2*(32+16+SHA1dlen), TLS_RSA_WITH_AES_256_CBC_SHA},
- {"3des_ede_cbc","sha1", 2*(4*8+SHA1dlen), TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA},
{"3des_ede_cbc","sha1", 2*(4*8+SHA1dlen), TLS_RSA_WITH_3DES_EDE_CBC_SHA},
- // PSK cipher suits
+ // PSK
{"ccpoly96_aead", "clear", 2*(32+12), TLS_PSK_WITH_CHACHA20_POLY1305},
{"aes_128_cbc", "sha256", 2*(16+16+SHA2_256dlen), TLS_PSK_WITH_AES_128_CBC_SHA256},
{"aes_128_cbc", "sha1", 2*(16+16+SHA1dlen), TLS_PSK_WITH_AES_128_CBC_SHA},
@@ -345,6 +360,7 @@
DigestState* (*fun)(uchar*, ulong, uchar*, DigestState*);
int len;
} hashfun[] = {
+/* [0x00] is reserved for MD5+SHA1 for < TLS1.2 */
[0x01] {md5, MD5dlen},
[0x02] {sha1, SHA1dlen},
[0x03] {sha2_224, SHA2_224dlen},
@@ -384,6 +400,11 @@
static int finishedMatch(TlsConnection *c, Finished *f);
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 okCipher(Ints *cv, int ispsk);
static int okCompression(Bytes *cv);
@@ -390,24 +411,28 @@
static int initCiphers(void);
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 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 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* tlsSecECDHEc(TlsSec *sec, int curve, Bytes *Ys);
static void tlsSecVers(TlsSec *sec, int v);
static int tlsSecFinished(TlsSec *sec, HandshakeHash hsh, uchar *fin, int nfin, int isclient);
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_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* erealloc(void*, int);
static void put32(uchar *p, u32int);
@@ -423,6 +448,7 @@
static void freebytes(Bytes* b);
static Ints* newints(int len);
static void freeints(Ints* b);
+static int lookupid(Ints* b, int id);
/* x509.c */
extern mpint* pkcs1padbuf(uchar *buf, int len, mpint *modulus);
@@ -519,7 +545,7 @@
}
// ECDHE
- if(1){
+ if(ProtocolVersion >= TLS10Version){
m = p - b;
b = erealloc(b, m + 2+2+2+nelem(namedcurves)*2 + 2+2+1+nelem(pointformats));
p = b + m;
@@ -654,9 +680,9 @@
char *pskid, uchar *psk, int psklen,
int (*trace)(char*fmt, ...), PEMChain *chp)
{
+ int cipher, compressor, numcerts, i;
TlsConnection *c;
Msg m;
- int cipher, compressor, numcerts, i;
if(trace)
trace("tlsServer2\n");
@@ -685,7 +711,11 @@
tlsError(c, EIllegalParameter, "incompatible version");
goto Err;
}
-
+ if(c->version < ProtocolVersion
+ && lookupid(m.u.clientHello.ciphers, TLS_FALLBACK_SCSV) >= 0){
+ tlsError(c, EInappropriateFallback, "inappropriate fallback");
+ goto Err;
+ }
cipher = okCipher(m.u.clientHello.ciphers, psklen > 0);
if(cipher < 0 || !setAlgs(c, cipher)) {
tlsError(c, EHandshakeFailure, "no matching cipher suite");
@@ -741,6 +771,36 @@
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;
if(!msgSend(c, &m, AFlush))
goto Err;
@@ -759,13 +819,18 @@
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){
tlsError(c, EHandshakeFailure, "couldn't set keys: %r");
goto Err;
}
} else if(psklen > 0){
- tlsSecPSKs(c->sec);
+ setMasterSecret(c->sec, newbytes(psklen));
} else {
tlsError(c, EInternalError, "no psk or certificate");
goto Err;
@@ -822,79 +887,29 @@
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*
tlsSecDHEc(TlsSec *sec, Bytes *p, Bytes *g, Bytes *Ys)
{
+ DHstate *dh = &sec->dh;
mpint *G, *P, *Y, *K;
- Bytes *epm;
- DHstate dh;
+ Bytes *Yc;
if(p == nil || g == nil || Ys == nil)
return nil;
- epm = nil;
+ Yc = nil;
P = bytestomp(p);
G = bytestomp(g);
Y = bytestomp(Ys);
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;
- epm = mptobytes(dh.y);
- K = dh_finish(&dh, Y);
+ Yc = mptobytes(dh->y);
+ K = dh_finish(dh, Y); /* zeros dh */
if(K == nil){
- freebytes(epm);
- epm = nil;
+ freebytes(Yc);
+ Yc = nil;
goto Out;
}
setMasterSecret(sec, mptobytes(K));
@@ -905,134 +920,55 @@
mpfree(G);
mpfree(P);
- return epm;
+ return Yc;
}
static Bytes*
tlsSecECDHEc(TlsSec *sec, int curve, Bytes *Ys)
{
- Namedcurve *nc, *enc;
- Bytes *epm;
- ECdomain dom;
+ ECdomain *dom = &sec->ec.dom;
+ ECpriv *Q = &sec->ec.Q;
+ Namedcurve *nc;
ECpub *pub;
ECpoint K;
- ECpriv Q;
+ Bytes *Yc;
if(Ys == nil)
return nil;
-
- enc = &namedcurves[nelem(namedcurves)];
- for(nc = namedcurves; nc != enc; nc++)
+ for(nc = namedcurves; nc != &namedcurves[nelem(namedcurves)]; nc++)
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;
-
- ecdominit(&dom, nc->init);
- pub = ecdecodepub(&dom, Ys->data, Ys->len);
- if(pub == nil){
- ecdomfree(&dom);
- return nil;
- }
- memset(&Q, 0, sizeof(Q));
- Q.a.x = mpnew(0);
- Q.a.y = mpnew(0);
- Q.d = mpnew(0);
+ memset(Q, 0, sizeof(*Q));
+ Q->a.x = mpnew(0);
+ Q->a.y = mpnew(0);
+ Q->d = mpnew(0);
memset(&K, 0, sizeof(K));
K.x = mpnew(0);
K.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, (ECpub*)&Q, epm->data, epm->len);
- }
+ ecgen(dom, Q);
+ ecmul(dom, pub, Q->d, &K);
+ setMasterSecret(sec, mptobytes(K.x));
+ Yc = newbytes(1 + 2*((mpsignif(dom->p)+7)/8));
+ Yc->len = ecencodepub(dom, (ECpub*)Q, Yc->data, Yc->len);
mpfree(K.x);
mpfree(K.y);
- mpfree(Q.a.x);
- mpfree(Q.a.y);
- mpfree(Q.d);
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 *
tlsClient2(int ctl, int hand,
uchar *cert, int certlen,
@@ -1040,10 +976,10 @@
uchar *ext, int extlen,
int (*trace)(char*fmt, ...))
{
- TlsConnection *c;
- Msg m;
int creq, dhx, cipher;
+ TlsConnection *c;
Bytes *epm;
+ Msg m;
if(!initCiphers())
return nil;
@@ -1129,10 +1065,11 @@
}
if(m.tag == HServerKeyExchange) {
if(dhx){
- char *err = verifyDHparams(c,
+ char *err = verifyDHparams(c->sec,
m.u.serverKeyExchange.dh_parameters,
+ c->cert,
m.u.serverKeyExchange.dh_signature,
- m.u.serverKeyExchange.sigalg);
+ c->version<TLS12Version ? 0x01 : m.u.serverKeyExchange.sigalg);
if(err != nil){
tlsError(c, EBadCertificate, "can't verify DH parameters: %s", err);
goto Err;
@@ -1183,7 +1120,7 @@
goto Err;
}
} else if(psklen > 0){
- tlsSecPSKc(c->sec);
+ setMasterSecret(c->sec, newbytes(psklen));
} else {
tlsError(c, EInternalError, "no psk or certificate");
goto Err;
@@ -1223,39 +1160,28 @@
/* certificate verify */
if(creq && certlen > 0) {
- mpint *signedMP, *paddedHashes;
HandshakeHash hsave;
- uchar buf[512];
- int buflen;
+ uchar digest[MAXdlen];
+ int digestlen;
/* save the state for the Finish message */
hsave = c->handhash;
- if(c->version >= TLS12Version){
- uchar digest[SHA2_256dlen];
-
+ if(c->version < TLS12Version){
+ 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 */
sha2_256(nil, 0, digest, &c->handhash.sha2_256);
- buflen = asn1encodedigest(sha2_256, digest, buf, sizeof(buf));
- } else {
- md5(nil, 0, buf, &c->handhash.md5);
- sha1(nil, 0, buf+MD5dlen, &c->handhash.sha1);
- buflen = MD5dlen+SHA1dlen;
+ digestlen = SHA2_256dlen;
}
c->handhash = hsave;
- if(buflen <= 0){
- tlsError(c, EInternalError, "can't encode handshake hashes");
+ if((m.u.certificateVerify.signature = pkcs1_sign(c->sec, digest, digestlen,
+ m.u.certificateVerify.sigalg)) == nil){
+ tlsError(c, EHandshakeFailure, "pkcs1_sign: %r");
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;
if(!msgSend(c, &m, AFlush))
@@ -1439,6 +1365,30 @@
memmove(p, m->u.certificateVerify.signature->data, m->u.certificateVerify.signature->len);
p += m->u.certificateVerify.signature->len;
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:
if(m->u.clientKeyExchange.pskid != nil){
n = m->u.clientKeyExchange.pskid->len;
@@ -1822,10 +1772,6 @@
}
break;
case HClientKeyExchange:
- /*
- * this message depends upon the encryption selected
- * assume rsa.
- */
if(isPSK(c->cipher)){
if(n < 2)
goto Short;
@@ -1843,8 +1789,12 @@
else{
if(n < 2)
goto Short;
- nn = get16(p);
- p += 2, n -= 2;
+ if(isECDHE(c->cipher))
+ nn = *p++, n--;
+ else {
+ nn = get16(p);
+ p += 2, n -= 2;
+ }
}
if(n < nn)
goto Short;
@@ -1940,11 +1890,11 @@
if(b == nil)
bs = seprint(bs, be, "nil");
else {
- bs = seprint(bs, be, "<%d> [", b->len);
+ bs = seprint(bs, be, "<%d> [ ", b->len);
for(i=0; i<b->len; i++)
bs = seprint(bs, be, "%.2x ", b->data[i]);
+ bs = seprint(bs, be, "]");
}
- bs = seprint(bs, be, "]");
if(s1)
bs = seprint(bs, be, "%s", s1);
return bs;
@@ -1957,13 +1907,14 @@
if(s0)
bs = seprint(bs, be, "%s", s0);
- bs = seprint(bs, be, "[");
if(b == nil)
bs = seprint(bs, be, "nil");
- else
+ else {
+ bs = seprint(bs, be, "[ ");
for(i=0; i<b->len; i++)
bs = seprint(bs, be, "%x ", b->data[i]);
- bs = seprint(bs, be, "]");
+ bs = seprint(bs, be, "]");
+ }
if(s1)
bs = seprint(bs, be, "%s", s1);
return bs;
@@ -2075,10 +2026,10 @@
va_end(arg);
if(c->trace)
c->trace("tlsError: %s\n", msg);
- else if(c->erred)
+ if(c->erred)
fprint(2, "double error: %r, %s", msg);
else
- werrstr("tls: local %s", msg);
+ errstr(msg, sizeof(msg));
c->erred = 1;
fprint(c->ctl, "alert %d", err);
}
@@ -2115,9 +2066,18 @@
{
if(c == nil)
return;
+
+ dh_finish(&c->sec->dh, nil);
+
+ mpfree(c->sec->ec.Q.a.x);
+ mpfree(c->sec->ec.Q.a.y);
+ mpfree(c->sec->ec.Q.d);
+ ecdomfree(&c->sec->ec.dom);
+
factotum_rsa_close(c->sec->rpc);
rsapubfree(c->sec->rsapub);
freebytes(c->cert);
+
memset(c, 0, sizeof(*c));
free(c);
}
@@ -2126,6 +2086,69 @@
//================= 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
setAlgs(TlsConnection *c, int a)
{
int i;
@@ -2147,15 +2170,14 @@
static int
okCipher(Ints *cv, int ispsk)
{
- int i, j, c;
+ int i, c;
- for(i = 0; i < cv->len; i++) {
- c = cv->data[i];
- if(isDHE(c) || isECDHE(c) || isPSK(c) != ispsk)
- continue; /* TODO: not implemented for server */
- for(j = 0; j < nelem(cipherAlgs); j++)
- if(cipherAlgs[j].ok && cipherAlgs[j].tlsid == c)
- return c;
+ for(i = 0; i < nelem(cipherAlgs); i++) {
+ c = cipherAlgs[i].tlsid;
+ if(!cipherAlgs[i].ok || isECDSA(c) || isDHE(c) || isPSK(c) != ispsk)
+ continue;
+ if(lookupid(cv, c) >= 0)
+ return c;
}
return -1;
}
@@ -2163,14 +2185,12 @@
static int
okCompression(Bytes *cv)
{
- int i, j, c;
+ int i, c;
- for(i = 0; i < cv->len; i++) {
- c = cv->data[i];
- for(j = 0; j < nelem(compressors); j++) {
- if(compressors[j] == c)
- return c;
- }
+ for(i = 0; i < nelem(compressors); i++) {
+ c = compressors[i];
+ if(memchr(cv->data, c, cv->len) != nil)
+ return c;
}
return -1;
}
@@ -2260,7 +2280,6 @@
}
-
//================= security functions ========================
// given a public key, set up connection to factotum
@@ -2527,8 +2546,6 @@
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
tlsSecInits(TlsSec *sec, int cvers, uchar *crandom)
{
@@ -2561,12 +2578,64 @@
return 0;
}
-static void
-tlsSecPSKs(TlsSec *sec)
+static Bytes*
+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->a.x = mpnew(0);
+ Q->a.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, (ECpub*)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
tlsSecInitc(TlsSec *sec, int cvers)
{
@@ -2576,12 +2645,6 @@
genrandom(sec->crandom+4, RandomSize-4);
}
-static void
-tlsSecPSKc(TlsSec *sec)
-{
- setMasterSecret(sec, newbytes(sec->psklen));
-}
-
static Bytes*
tlsSecRSAc(TlsSec *sec, uchar *cert, int ncert)
{
@@ -2694,28 +2757,82 @@
freebytes(pm);
}
-static mpint*
-bytestomp(Bytes* bytes)
+static int
+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;
}
-/*
- * Convert mpint* to Bytes, putting high order byte first.
- */
-static Bytes*
-mptobytes(mpint* big)
+static char*
+verifyDHparams(TlsSec *sec, Bytes *par, Bytes *cert, Bytes *sig, int sigalg)
{
- Bytes* ans;
- int n;
+ uchar digest[MAXdlen];
+ int digestlen;
+ ECdomain dom;
+ ECpub *ecpk;
+ RSApub *rsapk;
+ char *err;
- n = (mpsignif(big)+7)/8;
- if(n == 0) n = 1;
- ans = newbytes(n);
- mptober(big, ans->data, ans->len);
- return ans;
+ if(par == nil || par->len <= 0)
+ return "no DH parameters";
+
+ if(sig == nil || sig->len <= 0){
+ 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
// result on left with zeros to make it modlen long.
static Bytes*
@@ -2816,7 +2933,33 @@
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 ========================
static void *
@@ -2919,6 +3062,28 @@
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 */
static Ints*
newints(int len)
@@ -2936,4 +3101,15 @@
freeints(Ints* b)
{
free(b);
+}
+
+static int
+lookupid(Ints* b, int id)
+{
+ int i;
+
+ for(i=0; i<b->len; i++)
+ if(b->data[i] == id)
+ return i;
+ return -1;
}