ref: 17a67eeb652ebc76f6fc9f7f7bbed501187d24e1
parent: 7b3334775edcfe43fc6ff44955b09dc294d96974
author: cinap_lenrek <[email protected]>
date: Thu Apr 21 22:33:29 EDT 2016
libsec: implement server side SCSV preventing silly client fallbacks silly clients (web*) reconnect when the handshake failed with a lower protocol version, which allows downgrade attacks (POODLE). but instead of stopping this madness, they invented a new magic TLSID to indicate to the server that this connection attempt is a retry, and rely on the server to notice and stop them from sabotaging themselfs.
--- a/sys/src/libsec/port/tlshand.c
+++ b/sys/src/libsec/port/tlshand.c
@@ -211,6 +211,7 @@
EProtocolVersion = 70,
EInsufficientSecurity = 71,
EInternalError = 80,
+ EInappropriateFallback = 86,
EUserCanceled = 90,
ENoRenegotiation = 100,
EUnknownPSKidentity = 115,
@@ -295,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
@@ -446,6 +449,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);
@@ -708,7 +712,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");
@@ -2019,10 +2027,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);
}
@@ -2163,15 +2171,14 @@
static int
okCipher(Ints *cv, int ispsk)
{
- int i, j, c;
+ 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)
continue;
- for(j = 0; j < cv->len; j++)
- if(cv->data[j] == c)
- return c;
+ if(lookupid(cv, c) >= 0)
+ return c;
}
return -1;
}
@@ -2179,13 +2186,12 @@
static int
okCompression(Bytes *cv)
{
- int i, j, c;
+ int i, c;
for(i = 0; i < nelem(compressors); i++) {
c = compressors[i];
- for(j = 0; j < cv->len; j++)
- if(cv->data[j] == c)
- return c;
+ if(memchr(cv->data, c, cv->len) != nil)
+ return c;
}
return -1;
}
@@ -3096,4 +3102,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;
}