From: kemal <kemalinanc8@gmail.com>
To: 9front@9front.org
Subject: Re: [9front] libsec: various tls changes
Date: Fri, 18 Jun 2021 18:51:09 +0000 [thread overview]
Message-ID: <CABO6shfTEKNjFdx4O1e_tU-XPn+bu7J=tE6GZF_7xXPDthRyZA@mail.gmail.com> (raw)
In-Reply-To: <1F0E89C0DA556E9265991DE6E86C77D4@felloff.net>
[-- Attachment #1: Type: text/plain, Size: 758 bytes --]
> if we never produce any extension response, maybe
> it would be better to just get rid of it for now
> and return a error status instead?
>
> also, the naming would need to change. as this
> function actually never *produces* server
> extensions and instead *processes* the client
> extensions... what about something like:
>
> if(!okClientExtensions(c, m.u.clientHello.extensions))
> goto Err;
ok.
also, after a bit of diving in the rfcs i found out that
the x25519 rfc specifies an optional step that if the
shared secret turned out to be all zeroes, abort.
rfc 8422 (tls ecc rfc) says that this MUST be done.
i was unsure if i should have added that check to
curve25519_finish, as it would break source compatibility,
so i added it to tlsSecECDHE*.
[-- Attachment #2: diff --]
[-- Type: application/octet-stream, Size: 27438 bytes --]
From e92ab3b04ad05b4f5f22797c29ae88d62fbe309d
From: kemal <kemalinanc8@gmail.com>
Date: Fri, 18 Jun 2021 18:36:38 +0000
Subject: [PATCH] libsec: various changes to tls
1. add the curve x25519 to tls, both client and server.
it's more faster, immune to timing attacks by design,
does not require verifying if the public key is valid,
etc etc. server-side has to check if the client supports
the curve, so a new function has been introduced to parse
the client's extensions.
2. reject weak dhe primes that can be easily cracked with
the number field sieve algorithm. this avoids attacks like
logjam.
3. stop putting unix time to the first 4 bytes of client/
server random. it can allow fingerprinting, tls 1.3 doesn't
recommend it any more and there was a draft to deprecate
this behaviour earlier.[1]
4. simply prf code, remove useless cipher enums.
[1] https://datatracker.ietf.org/doc/html/draft-mathewson-no-gmtunixtime-00
---
diff 7f697e822b2efd5c757141720469d105a5605ca4 e92ab3b04ad05b4f5f22797c29ae88d62fbe309d
--- a/sys/man/1/date Wed Jun 16 03:28:01 2021
+++ b/sys/man/1/date Fri Jun 18 21:36:38 2021
@@ -6,6 +6,9 @@
[
.I option
] [
+.B -f
+.I format
+] [
.I seconds
]
.br
@@ -16,6 +19,8 @@
.B
Tue Aug 16 17:03:52 CDT 1977
.PP
+Or the format specified by the format option.
+
The options are
.TP
.B -u
@@ -33,6 +38,13 @@
.TP
.B -m
Report the date as an email compatible (RFC2822) time stamp.
+.TP
+.B -f
+Print using the format specified by the
+.I format
+string rather than the default. Format strings are in the format used by
+.IR tmdate (2)
+
.PP
The conversion from Greenwich Mean Time to local time depends on the
.B $timezone
@@ -65,3 +77,5 @@
.B /sys/src/cmd/date.c
.br
.B /sys/src/cmd/clock.c
+.SH "SEE ALSO"
+.IR tmdate (2)
--- a/sys/src/cmd/git/branch Wed Jun 16 03:28:01 2021
+++ b/sys/src/cmd/git/branch Fri Jun 18 21:36:38 2021
@@ -37,6 +37,15 @@
if not
base=`{git/query HEAD}
+if(~ $#newbr 0){
+ if(! ~ $#baseref 0)
+ die update would clobber $branch with $baseref
+ baseref=`$nl{echo -n $new | sed s@refs/heads/@refs/remotes/origin/@}
+ echo $baseref
+ if(! test -e .git/$new)
+ if(! base=`{git/query $baseref})
+ die could not find branch $branch
+}
modified=`$nl{git/query -c HEAD $base | grep '^[^-]' | subst '^..'}
deleted=`$nl{git/query -c HEAD $base | grep '^-' | subst '^..'}
@@ -48,14 +57,6 @@
rm -f .git/$new
echo 'deleted branch' $new
exit
-}
-if(~ $#newbr 0){
- if(! ~ $#baseref 0)
- die update would clobber $branch with $baseref
- baseref=`$nl{echo -n $new | sed s@refs/heads/@refs/remotes/origin/@}
- if(! test -e .git/$new)
- if(! base=`{git/query $baseref})
- die could not find branch $branch
}
commit=`{git/query $base} || die 'branch does not exist:' $base
if(~ $new */*)
--- a/sys/src/libsec/port/tlshand.c Wed Jun 16 03:28:01 2021
+++ b/sys/src/libsec/port/tlshand.c Fri Jun 18 21:36:38 2021
@@ -66,18 +66,20 @@
int psklen;
int clientVers; // version in ClientHello
uchar sec[MasterSecretSize]; // master secret
- uchar crandom[RandomSize]; // client random
uchar srandom[RandomSize]; // server random
+ uchar crandom[RandomSize]; // client random
+ Namedcurve *nc; // selected curve for ECDHE
// diffie hellman state
DHstate dh;
struct {
ECdomain dom;
ECpriv Q;
} ec;
+ uchar X[32];
// 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);
void (*setFinished)(TlsSec*, HandshakeHash, uchar*, int);
int nfin;
};
@@ -107,7 +109,7 @@
int tag;
union {
struct {
- int version;
+ int version;
uchar random[RandomSize];
Bytes* sid;
Ints* ciphers;
@@ -115,7 +117,7 @@
Bytes* extensions;
} clientHello;
struct {
- int version;
+ int version;
uchar random[RandomSize];
Bytes* sid;
int cipher;
@@ -214,79 +216,36 @@
// cipher suites
enum {
- TLS_NULL_WITH_NULL_NULL = 0x0000,
- TLS_RSA_WITH_NULL_MD5 = 0x0001,
- TLS_RSA_WITH_NULL_SHA = 0x0002,
- TLS_RSA_EXPORT_WITH_RC4_40_MD5 = 0x0003,
- TLS_RSA_WITH_RC4_128_MD5 = 0x0004,
- TLS_RSA_WITH_RC4_128_SHA = 0x0005,
- TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = 0X0006,
- TLS_RSA_WITH_IDEA_CBC_SHA = 0X0007,
- TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = 0X0008,
- TLS_RSA_WITH_DES_CBC_SHA = 0X0009,
TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0X000A,
- TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = 0X000B,
- TLS_DH_DSS_WITH_DES_CBC_SHA = 0X000C,
- TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = 0X000D,
- TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = 0X000E,
- TLS_DH_RSA_WITH_DES_CBC_SHA = 0X000F,
- TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = 0X0010,
- TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = 0X0011,
- TLS_DHE_DSS_WITH_DES_CBC_SHA = 0X0012,
- TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0X0013, // ZZZ must be implemented for tls1.0 compliance
- TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = 0X0014,
- TLS_DHE_RSA_WITH_DES_CBC_SHA = 0X0015,
TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0X0016,
- TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = 0x0017,
- TLS_DH_anon_WITH_RC4_128_MD5 = 0x0018,
- TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = 0X0019,
- TLS_DH_anon_WITH_DES_CBC_SHA = 0X001A,
- TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = 0X001B,
- TLS_RSA_WITH_AES_128_CBC_SHA = 0X002F, // aes, aka rijndael with 128 bit blocks
- TLS_DH_DSS_WITH_AES_128_CBC_SHA = 0X0030,
- TLS_DH_RSA_WITH_AES_128_CBC_SHA = 0X0031,
- TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0X0032,
+
+ TLS_RSA_WITH_AES_128_CBC_SHA = 0X002F,
TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0X0033,
- TLS_DH_anon_WITH_AES_128_CBC_SHA = 0X0034,
TLS_RSA_WITH_AES_256_CBC_SHA = 0X0035,
- TLS_DH_DSS_WITH_AES_256_CBC_SHA = 0X0036,
- TLS_DH_RSA_WITH_AES_256_CBC_SHA = 0X0037,
- TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0X0038,
TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0X0039,
- TLS_DH_anon_WITH_AES_256_CBC_SHA = 0X003A,
TLS_RSA_WITH_AES_128_CBC_SHA256 = 0X003C,
TLS_RSA_WITH_AES_256_CBC_SHA256 = 0X003D,
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0X0067,
TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x009C,
- TLS_RSA_WITH_AES_256_GCM_SHA384 = 0x009D,
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = 0x009E,
- TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = 0x009F,
- TLS_DH_RSA_WITH_AES_128_GCM_SHA256 = 0x00A0,
- TLS_DH_RSA_WITH_AES_256_GCM_SHA384 = 0x00A1,
- TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 = 0x00A2,
- TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 = 0x00A3,
- TLS_DH_DSS_WITH_AES_128_GCM_SHA256 = 0x00A4,
- TLS_DH_DSS_WITH_AES_256_GCM_SHA384 = 0x00A5,
- TLS_DH_anon_WITH_AES_128_GCM_SHA256 = 0x00A6,
- TLS_DH_anon_WITH_AES_256_GCM_SHA384 = 0x00A7,
-
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02B,
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC02F,
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_AES_128_CBC_SHA256 = 0xC027,
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 = 0xCCA8,
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 = 0xCCA9,
- TLS_DHE_RSA_WITH_CHACHA20_POLY1305 = 0xCCAA,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02B,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC02F,
GOOGLE_ECDHE_RSA_WITH_CHACHA20_POLY1305 = 0xCC13,
GOOGLE_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 = 0xCC14,
GOOGLE_DHE_RSA_WITH_CHACHA20_POLY1305 = 0xCC15,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 = 0xCCA8,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 = 0xCCA9,
+ TLS_DHE_RSA_WITH_CHACHA20_POLY1305 = 0xCCAA,
+
TLS_PSK_WITH_CHACHA20_POLY1305 = 0xCCAB,
TLS_PSK_WITH_AES_128_CBC_SHA256 = 0x00AE,
TLS_PSK_WITH_AES_128_CBC_SHA = 0x008C,
@@ -300,6 +259,20 @@
CompressionMax
};
+
+// curves
+enum {
+ X25519 = 0x001d,
+};
+
+// extensions
+enum {
+ Extsni = 0x0000,
+ Extec = 0x000a,
+ Extecp = 0x000b,
+ Extsigalgs = 0x000d,
+};
+
static Algs cipherAlgs[] = {
// ECDHE-ECDSA
{"ccpoly96_aead", "clear", 2*(32+12), TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305},
@@ -343,6 +316,7 @@
};
static Namedcurve namedcurves[] = {
+ X25519, nil,
0x0017, secp256r1,
0x0018, secp384r1,
};
@@ -402,7 +376,7 @@
static int isECDSA(int tlsid);
static int setAlgs(TlsConnection *c, int a);
-static int okCipher(Ints *cv, int ispsk);
+static int okCipher(Ints *cv, int ispsk, int canec);
static int okCompression(Bytes *cv);
static int initCiphers(void);
static Ints* makeciphers(int ispsk);
@@ -413,7 +387,7 @@
static void tlsSecInits(TlsSec *sec, int cvers, uchar *crandom);
static int tlsSecRSAs(TlsSec *sec, Bytes *epm);
-static Bytes* tlsSecECDHEs1(TlsSec *sec, Namedcurve *nc);
+static Bytes* tlsSecECDHEs1(TlsSec *sec);
static int tlsSecECDHEs2(TlsSec *sec, Bytes *Yc);
static void tlsSecInitc(TlsSec *sec, int cvers);
static Bytes* tlsSecRSAc(TlsSec *sec, uchar *cert, int ncert);
@@ -454,6 +428,7 @@
{
char buf[8];
char dname[64];
+ uchar seed[2*RandomSize];
int n, data, ctl, hand;
TlsConnection *tls;
@@ -498,13 +473,15 @@
conn->sessionID = nil;
if(conn->sessionKey != nil
&& conn->sessionType != nil
- && strcmp(conn->sessionType, "ttls") == 0)
+ && strcmp(conn->sessionType, "ttls") == 0){
+ memmove(seed, tls->sec->crandom, RandomSize);
+ memmove(seed+RandomSize, tls->sec->srandom, RandomSize);
tls->sec->prf(
conn->sessionKey, conn->sessionKeylen,
tls->sec->sec, MasterSecretSize,
conn->sessionConst,
- tls->sec->crandom, RandomSize,
- tls->sec->srandom, RandomSize);
+ seed, sizeof(seed));
+ }
tlsConnectionFree(tls);
close(fd);
return data;
@@ -526,7 +503,7 @@
b = erealloc(b, m + 2+2+2+1+2+n);
p = b + m;
- put16(p, 0), p += 2; /* Type: server_name */
+ put16(p, Extsni), p += 2; /* Type: server_name */
put16(p, 2+1+2+n), p += 2; /* Length */
put16(p, 1+2+n), p += 2; /* Server Name list length */
*p++ = 0; /* Server Name Type: host_name */
@@ -535,26 +512,26 @@
p += n;
}
- // ECDHE
+ // Elliptic Curves (also called Supported Groups)
if(ProtocolVersion >= TLS10Version){
m = p - b;
b = erealloc(b, m + 2+2+2+nelem(namedcurves)*2 + 2+2+1+nelem(pointformats));
p = b + m;
n = nelem(namedcurves);
- put16(p, 0x000a), p += 2; /* Type: elliptic_curves */
+ put16(p, Extec), p += 2; /* Type: elliptic_curves / supported_groups */
put16(p, (n+1)*2), p += 2; /* Length */
put16(p, n*2), p += 2; /* Elliptic Curves Length */
- for(i=0; i < n; i++){ /* Elliptic curves */
+ for(i=0; i < n; i++){ /* Elliptic Curves */
put16(p, namedcurves[i].tlsid);
p += 2;
}
n = nelem(pointformats);
- put16(p, 0x000b), p += 2; /* Type: ec_point_formats */
+ put16(p, Extecp), p += 2; /* Type: ec_point_formats */
put16(p, n+1), p += 2; /* Length */
*p++ = n; /* EC point formats Length */
- for(i=0; i < n; i++) /* Elliptic curves point formats */
+ for(i=0; i < n; i++) /* EC point formats */
*p++ = pointformats[i];
}
@@ -566,7 +543,7 @@
b = erealloc(b, m + 2+2+2+n*2);
p = b + m;
- put16(p, 0x000d), p += 2;
+ put16(p, Extsigalgs), p += 2;
put16(p, n*2 + 2), p += 2;
put16(p, n*2), p += 2;
for(i=0; i < n; i++){
@@ -586,6 +563,7 @@
{
char buf[8];
char dname[64];
+ uchar seed[2*RandomSize];
int n, data, ctl, hand;
TlsConnection *tls;
uchar *ext;
@@ -641,13 +619,15 @@
conn->sessionID = nil;
if(conn->sessionKey != nil
&& conn->sessionType != nil
- && strcmp(conn->sessionType, "ttls") == 0)
+ && strcmp(conn->sessionType, "ttls") == 0){
+ memmove(seed, tls->sec->crandom, RandomSize);
+ memmove(seed+RandomSize, tls->sec->srandom, RandomSize);
tls->sec->prf(
conn->sessionKey, conn->sessionKeylen,
tls->sec->sec, MasterSecretSize,
conn->sessionConst,
- tls->sec->crandom, RandomSize,
- tls->sec->srandom, RandomSize);
+ seed, sizeof(seed));
+ }
tlsConnectionFree(tls);
close(fd);
return data;
@@ -665,6 +645,53 @@
return i;
}
+static int
+checkClientExtensions(TlsConnection *c, Bytes *ext)
+{
+ uchar *p, *e;
+ int i, j, n;
+
+ p = ext->data;
+ e = p+ext->len;
+ while(p < e){
+ if(e-p < 2)
+ goto Short;
+ switch(get16(p)){
+ case Extec:
+ p += 2;
+ n = get16(p);
+ if(e-p < n || n < 2)
+ goto Short;
+ p += 2;
+ n = get16(p);
+ p += 2;
+ if(e-p < n || n & 1 || n == 0)
+ goto Short;
+ for(i = 0; i < nelem(namedcurves) && c->sec->nc == nil; i++)
+ for(j = 0; j < n; j += 2)
+ if(namedcurves[i].tlsid == get16(p+j)){
+ c->sec->nc = &namedcurves[i];
+ break;
+ }
+ p += n;
+ break;
+ default:
+ p += 2;
+ n = get16(p);
+ p += 2;
+ if(e-p < n)
+ goto Short;
+ p += n;
+ break;
+ }
+ }
+
+ return 0;
+Short:
+ tlsError(c, EDecodeError, "clienthello extensions has invalid length");
+ return -1;
+}
+
static TlsConnection *
tlsServer2(int ctl, int hand,
uchar *cert, int certlen,
@@ -708,19 +735,6 @@
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");
- goto Err;
- }
- compressor = okCompression(m.u.clientHello.compressors);
- if(compressor < 0) {
- tlsError(c, EHandshakeFailure, "no matching compressor");
- goto Err;
- }
- if(trace)
- trace(" cipher %x, compressor %x\n", cipher, compressor);
-
tlsSecInits(c->sec, m.u.clientHello.version, m.u.clientHello.random);
tlsSecVers(c->sec, c->version);
if(psklen > 0){
@@ -740,6 +754,20 @@
goto Err;
}
}
+ if(checkClientExtensions(c, m.u.clientHello.extensions) < 0)
+ goto Err;
+ cipher = okCipher(m.u.clientHello.ciphers, psklen > 0, c->sec->nc != nil);
+ if(cipher < 0 || !setAlgs(c, cipher)) {
+ tlsError(c, EHandshakeFailure, "no matching cipher suite");
+ goto Err;
+ }
+ compressor = okCompression(m.u.clientHello.compressors);
+ if(compressor < 0) {
+ tlsError(c, EHandshakeFailure, "no matching compressor");
+ goto Err;
+ }
+ if(trace)
+ trace(" cipher %x, compressor %x\n", cipher, compressor);
msgClear(&m);
m.tag = HServerHello;
@@ -764,11 +792,9 @@
}
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);
+ m.u.serverKeyExchange.curve = c->sec->nc->tlsid;
+ m.u.serverKeyExchange.dh_parameters = tlsSecECDHEs1(c->sec);
if(m.u.serverKeyExchange.dh_parameters == nil){
tlsError(c, EInternalError, "can't set DH parameters");
goto Err;
@@ -889,7 +915,9 @@
if(p == nil || g == nil || Ys == nil)
return nil;
-
+ // reject dh primes that is susceptible to logjam
+ if(p->len <= 1024/8)
+ return nil;
Yc = nil;
P = bytestomp(p);
G = bytestomp(g);
@@ -920,49 +948,65 @@
static Bytes*
tlsSecECDHEc(TlsSec *sec, int curve, Bytes *Ys)
{
+ static char zero[32] = {0};
ECdomain *dom = &sec->ec.dom;
ECpriv *Q = &sec->ec.Q;
- Namedcurve *nc;
ECpub *pub;
ECpoint K;
+ Namedcurve *nc;
Bytes *Yc;
+ Bytes *Z;
int n;
if(Ys == nil)
return nil;
- for(nc = namedcurves; nc != &namedcurves[nelem(namedcurves)]; nc++)
- if(nc->tlsid == curve)
- goto Found;
- return nil;
-
-Found:
- ecdominit(dom, nc->init);
- pub = ecdecodepub(dom, Ys->data, Ys->len);
- if(pub == nil)
- return nil;
- memset(Q, 0, sizeof(*Q));
- Q->x = mpnew(0);
- Q->y = mpnew(0);
- Q->d = mpnew(0);
-
- memset(&K, 0, sizeof(K));
- K.x = mpnew(0);
- K.y = mpnew(0);
-
- ecgen(dom, Q);
- ecmul(dom, pub, Q->d, &K);
-
- n = (mpsignif(dom->p)+7)/8;
- setMasterSecret(sec, mptobytes(K.x, n));
- Yc = newbytes(1 + 2*n);
- Yc->len = ecencodepub(dom, Q, Yc->data, Yc->len);
+ if(curve == X25519){
+ if(Ys->len != 32)
+ return nil;
+ Yc = newbytes(32);
+ curve25519_dh_new(sec->X, Yc->data);
+ Z = newbytes(32);
+ curve25519_dh_finish(sec->X, Ys->data, Z->data);
+ // rfc wants us to terminate the connection if
+ // shared secret == all zeroes.
+ if(tsmemcmp(Z->data, zero, Z->len) == 0){
+ freebytes(Yc);
+ freebytes(Z);
+ return nil;
+ }
+ setMasterSecret(sec, Z);
+ }else{
+ for(nc = namedcurves; nc->tlsid != curve; nc++)
+ if(nc == &namedcurves[nelem(namedcurves)])
+ return nil;
+ ecdominit(dom, nc->init);
+ pub = ecdecodepub(dom, Ys->data, Ys->len);
+ if(pub == nil)
+ return nil;
- mpfree(K.x);
- mpfree(K.y);
+ memset(Q, 0, sizeof(*Q));
+ Q->x = mpnew(0);
+ Q->y = mpnew(0);
+ Q->d = mpnew(0);
+
+ memset(&K, 0, sizeof(K));
+ K.x = mpnew(0);
+ K.y = mpnew(0);
+
+ ecgen(dom, Q);
+ ecmul(dom, pub, Q->d, &K);
+
+ n = (mpsignif(dom->p)+7)/8;
+ setMasterSecret(sec, mptobytes(K.x, n));
+ Yc = newbytes(1 + 2*n);
+ Yc->len = ecencodepub(dom, Q, Yc->data, Yc->len);
- ecpubfree(pub);
+ mpfree(K.x);
+ mpfree(K.y);
+ ecpubfree(pub);
+ }
return Yc;
}
@@ -1045,7 +1089,6 @@
tlsError(c, EIllegalParameter, "invalid compression");
goto Err;
}
-
dhx = isDHE(cipher) || isECDHE(cipher);
if(!msgRecv(c, &m))
goto Err;
@@ -2136,13 +2179,17 @@
}
static int
-okCipher(Ints *cv, int ispsk)
+okCipher(Ints *cv, int ispsk, int canec)
{
int i, c;
for(i = 0; i < nelem(cipherAlgs); i++) {
c = cipherAlgs[i].tlsid;
- if(!cipherAlgs[i].ok || isECDSA(c) || isDHE(c) || isPSK(c) != ispsk)
+ if(!cipherAlgs[i].ok || isECDSA(c) || isDHE(c))
+ continue;
+ if(isPSK(c) != ispsk)
+ continue;
+ if(isECDHE(c) && !canec)
continue;
if(lookupid(cv, c) >= 0)
return c;
@@ -2313,114 +2360,55 @@
}
static void
-tlsPmd5(uchar *buf, int nbuf, uchar *key, int nkey, uchar *label, int nlabel, uchar *seed0, int nseed0, uchar *seed1, int nseed1)
-{
- uchar ai[MD5dlen], tmp[MD5dlen];
- int i, n;
- MD5state *s;
-
- // generate a1
- s = hmac_md5(label, nlabel, key, nkey, nil, nil);
- s = hmac_md5(seed0, nseed0, key, nkey, nil, s);
- hmac_md5(seed1, nseed1, key, nkey, ai, s);
-
- while(nbuf > 0) {
- s = hmac_md5(ai, MD5dlen, key, nkey, nil, nil);
- s = hmac_md5(label, nlabel, key, nkey, nil, s);
- s = hmac_md5(seed0, nseed0, key, nkey, nil, s);
- hmac_md5(seed1, nseed1, key, nkey, tmp, s);
- n = MD5dlen;
- if(n > nbuf)
- n = nbuf;
- for(i = 0; i < n; i++)
- buf[i] ^= tmp[i];
- buf += n;
- nbuf -= n;
- hmac_md5(ai, MD5dlen, key, nkey, tmp, nil);
- memmove(ai, tmp, MD5dlen);
- }
-}
-
-static void
-tlsPsha1(uchar *buf, int nbuf, uchar *key, int nkey, uchar *label, int nlabel, uchar *seed0, int nseed0, uchar *seed1, int nseed1)
-{
- uchar ai[SHA1dlen], tmp[SHA1dlen];
- int i, n;
- SHAstate *s;
-
- // generate a1
- s = hmac_sha1(label, nlabel, key, nkey, nil, nil);
- s = hmac_sha1(seed0, nseed0, key, nkey, nil, s);
- hmac_sha1(seed1, nseed1, key, nkey, ai, s);
-
- while(nbuf > 0) {
- s = hmac_sha1(ai, SHA1dlen, key, nkey, nil, nil);
- s = hmac_sha1(label, nlabel, key, nkey, nil, s);
- s = hmac_sha1(seed0, nseed0, key, nkey, nil, s);
- hmac_sha1(seed1, nseed1, key, nkey, tmp, s);
- n = SHA1dlen;
- if(n > nbuf)
- n = nbuf;
- for(i = 0; i < n; i++)
- buf[i] ^= tmp[i];
- buf += n;
- nbuf -= n;
- hmac_sha1(ai, SHA1dlen, key, nkey, tmp, nil);
- memmove(ai, tmp, SHA1dlen);
- }
-}
-
-static void
-p_sha256(uchar *buf, int nbuf, uchar *key, int nkey, uchar *label, int nlabel, uchar *seed, int nseed)
+tlsP(uchar *buf, int nbuf, uchar *key, int nkey, uchar *label, int nlabel, uchar *seed, int nseed,
+ DigestState* (*x)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*), int xlen)
{
uchar ai[SHA2_256dlen], tmp[SHA2_256dlen];
- SHAstate *s;
+ DigestState *s;
int n;
+ assert(sizeof(ai) <= xlen && sizeof(tmp) <= xlen);
// generate a1
- s = hmac_sha2_256(label, nlabel, key, nkey, nil, nil);
- hmac_sha2_256(seed, nseed, key, nkey, ai, s);
+ s = x(label, nlabel, key, nkey, nil, nil);
+ x(seed, nseed, key, nkey, ai, s);
while(nbuf > 0) {
- s = hmac_sha2_256(ai, SHA2_256dlen, key, nkey, nil, nil);
- s = hmac_sha2_256(label, nlabel, key, nkey, nil, s);
- hmac_sha2_256(seed, nseed, key, nkey, tmp, s);
- n = SHA2_256dlen;
+ s = x(ai, xlen, key, nkey, nil, nil);
+ s = x(label, nlabel, key, nkey, nil, s);
+ x(seed, nseed, key, nkey, tmp, s);
+ n = xlen;
if(n > nbuf)
n = nbuf;
memmove(buf, tmp, n);
buf += n;
nbuf -= n;
- hmac_sha2_256(ai, SHA2_256dlen, key, nkey, tmp, nil);
- memmove(ai, tmp, SHA2_256dlen);
+ x(ai, xlen, key, nkey, tmp, nil);
+ memmove(ai, tmp, xlen);
}
}
// fill buf with md5(args)^sha1(args)
static void
-tls10PRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label, uchar *seed0, int nseed0, uchar *seed1, int nseed1)
+tls10PRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label, uchar *seed, int nseed)
{
int nlabel = strlen(label);
int n = (nkey + 1) >> 1;
- memset(buf, 0, nbuf);
- tlsPmd5(buf, nbuf, key, n, (uchar*)label, nlabel, seed0, nseed0, seed1, nseed1);
- tlsPsha1(buf, nbuf, key+nkey-n, n, (uchar*)label, nlabel, seed0, nseed0, seed1, nseed1);
+ tlsP(buf, nbuf, key, n, (uchar*)label, nlabel, seed, nseed,
+ hmac_md5, MD5dlen);
+ tlsP(buf, nbuf, key+nkey-n, n, (uchar*)label, nlabel, seed, nseed,
+ hmac_sha1, SHA1dlen);
}
static void
-tls12PRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label, uchar *seed0, int nseed0, uchar *seed1, int nseed1)
+tls12PRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label, uchar *seed, int nseed)
{
- uchar seed[2*RandomSize];
-
- assert(nseed0+nseed1 <= sizeof(seed));
- memmove(seed, seed0, nseed0);
- memmove(seed+nseed0, seed1, nseed1);
- p_sha256(buf, nbuf, key, nkey, (uchar*)label, strlen(label), seed, nseed0+nseed1);
+ tlsP(buf, nbuf, key, nkey, (uchar*)label, strlen(label), seed, nseed,
+ hmac_sha2_256, SHA2_256dlen);
}
static void
-sslPRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label, uchar *seed0, int nseed0, uchar *seed1, int nseed1)
+sslPRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label, uchar *seed, int nseed)
{
uchar sha1dig[SHA1dlen], md5dig[MD5dlen], tmp[26];
DigestState *s;
@@ -2435,8 +2423,7 @@
tmp[i] = 'A' - 1 + len;
s = sha1(tmp, len, nil, nil);
s = sha1(key, nkey, nil, s);
- s = sha1(seed0, nseed0, nil, s);
- sha1(seed1, nseed1, sha1dig, s);
+ sha1(seed, nseed, sha1dig, s);
s = md5(key, nkey, nil, nil);
md5(sha1dig, SHA1dlen, md5dig, s);
n = MD5dlen;
@@ -2486,18 +2473,18 @@
static void
tls10SetFinished(TlsSec *sec, HandshakeHash hsh, uchar *finished, int isclient)
{
- uchar h0[MD5dlen], h1[SHA1dlen];
+ uchar h[MD5dlen+SHA1dlen];
char *label;
// get current hash value, but allow further messages to be hashed in
- md5(nil, 0, h0, &hsh.md5);
- sha1(nil, 0, h1, &hsh.sha1);
+ md5(nil, 0, h, &hsh.md5);
+ sha1(nil, 0, h+MD5dlen, &hsh.sha1);
if(isclient)
label = "client finished";
else
label = "server finished";
- tls10PRF(finished, TLSFinishedLen, sec->sec, MasterSecretSize, label, h0, MD5dlen, h1, SHA1dlen);
+ tls10PRF(finished, TLSFinishedLen, sec->sec, MasterSecretSize, label, h, sizeof(h));
}
static void
@@ -2513,7 +2500,7 @@
label = "client finished";
else
label = "server finished";
- p_sha256(finished, TLSFinishedLen, sec->sec, MasterSecretSize, (uchar*)label, strlen(label), seed, SHA2_256dlen);
+ tls12PRF(finished, TLSFinishedLen, sec->sec, MasterSecretSize, label, seed, SHA2_256dlen);
}
static void
@@ -2523,8 +2510,9 @@
sec->clientVers = cvers;
memmove(sec->crandom, crandom, RandomSize);
- put32(sec->srandom, time(nil));
- genrandom(sec->srandom+4, RandomSize-4);
+ // putting time()'s output to the first 4 bytes is no
+ // longer recommended and is not useful
+ genrandom(sec->srandom, RandomSize);
}
static int
@@ -2549,61 +2537,88 @@
}
static Bytes*
-tlsSecECDHEs1(TlsSec *sec, Namedcurve *nc)
+tlsSecECDHEs1(TlsSec *sec)
{
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;
-
+ if(sec->nc == nil)
+ return nil;
+ if(sec->nc->tlsid == X25519){
+ par = newbytes(1+2+1+32);
+ par->data[0] = 3;
+ put16(par->data+1, X25519);
+ par->data[3] = 32;
+ curve25519_dh_new(sec->X, par->data+4);
+ }else{
+ ecdominit(dom, sec->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, sec->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)
{
+ static char zero[32] = {0};
ECdomain *dom = &sec->ec.dom;
ECpriv *Q = &sec->ec.Q;
ECpoint K;
ECpub *Y;
+ Bytes *Z;
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);
+ if(sec->nc->tlsid == X25519){
+ if(Yc->len != 32){
+ werrstr("bad public key");
+ return -1;
+ }
+ Z = newbytes(32);
+ curve25519_dh_finish(sec->X, Yc->data, Z->data);
+ // rfc wants us to terminate the connection if
+ // shared secret == all zeroes.
+ if(tsmemcmp(Z->data, zero, Z->len) == 0){
+ werrstr("unlucky shared key");
+ freebytes(Z);
+ return -1;
+ }
+ setMasterSecret(sec, Z);
+ }else{
+ 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);
+ ecmul(dom, Y, Q->d, &K);
- setMasterSecret(sec, mptobytes(K.x, (mpsignif(dom->p)+7)/8));
+ setMasterSecret(sec, mptobytes(K.x, (mpsignif(dom->p)+7)/8));
- mpfree(K.x);
- mpfree(K.y);
-
- ecpubfree(Y);
+ mpfree(K.x);
+ mpfree(K.y);
+ ecpubfree(Y);
+ }
return 0;
}
@@ -2612,8 +2627,8 @@
{
memset(sec, 0, sizeof(*sec));
sec->clientVers = cvers;
- put32(sec->crandom, time(nil));
- genrandom(sec->crandom+4, RandomSize-4);
+ // see the comment on tlsSecInits
+ genrandom(sec->crandom, RandomSize);
}
static Bytes*
@@ -2671,13 +2686,15 @@
static int
setSecrets(TlsConnection *c, int isclient)
{
- uchar kd[MaxKeyData];
+ uchar kd[MaxKeyData], seed[2*RandomSize];
char *secrets;
int rv;
assert(c->nsecret <= sizeof(kd));
secrets = emalloc(2*c->nsecret);
+ memmove(seed, c->sec->srandom, RandomSize);
+ memmove(seed+RandomSize, c->sec->crandom, RandomSize);
/*
* generate secret keys from the master secret.
*
@@ -2686,7 +2703,7 @@
* but it's all generated using the same function.
*/
(*c->sec->prf)(kd, c->nsecret, c->sec->sec, MasterSecretSize, "key expansion",
- c->sec->srandom, RandomSize, c->sec->crandom, RandomSize);
+ seed, sizeof(seed));
enc64(secrets, 2*c->nsecret, kd, c->nsecret);
memset(kd, 0, c->nsecret);
@@ -2705,6 +2722,8 @@
static void
setMasterSecret(TlsSec *sec, Bytes *pm)
{
+ uchar seed[2*RandomSize];
+
if(sec->psklen > 0){
Bytes *opm = pm;
uchar *p;
@@ -2721,8 +2740,10 @@
freebytes(opm);
}
+ memmove(seed, sec->crandom, RandomSize);
+ memmove(seed+RandomSize, sec->srandom, RandomSize);
(*sec->prf)(sec->sec, MasterSecretSize, pm->data, pm->len, "master secret",
- sec->crandom, RandomSize, sec->srandom, RandomSize);
+ seed, sizeof(seed));
memset(pm->data, 0, pm->len);
freebytes(pm);
next prev parent reply other threads:[~2021-06-18 19:36 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-06-11 15:06 kemal
2021-06-12 13:15 ` cinap_lenrek
2021-06-12 19:54 ` kemal
2021-06-14 18:26 ` cinap_lenrek
2021-06-14 20:27 ` kemal
2021-06-16 9:48 ` cinap_lenrek
2021-06-16 11:59 ` kemal
2021-06-16 14:02 ` cinap_lenrek
2021-06-18 18:51 ` kemal [this message]
2021-06-18 19:13 ` kemal
2021-06-19 14:20 ` cinap_lenrek
2021-06-20 14:56 ` cinap_lenrek
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CABO6shfTEKNjFdx4O1e_tU-XPn+bu7J=tE6GZF_7xXPDthRyZA@mail.gmail.com' \
--to=kemalinanc8@gmail.com \
--cc=9front@9front.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).