diff -up ./lib/ssl/ssl3con.c.moz-1314604 ./lib/ssl/ssl3con.c --- ./lib/ssl/ssl3con.c.moz-1314604 2016-11-07 21:30:40.035272554 +0100 +++ ./lib/ssl/ssl3con.c 2016-11-07 21:31:14.876273952 +0100 @@ -6196,6 +6196,7 @@ sendDHClientKeyExchange(sslSocket * ss, if (pms == NULL) { ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + rv = SECFailure; goto loser; } @@ -6939,7 +6940,6 @@ ssl3_HandleServerKeyExchange(sslSocket * SECItem dh_Ys = {siBuffer, NULL, 0}; unsigned dh_p_bits; unsigned dh_g_bits; - unsigned dh_Ys_bits; PRInt32 minDH; rv = ssl3_ConsumeHandshakeVariable(ss, &dh_p, 2, &b, &length); @@ -6968,9 +6968,10 @@ ssl3_HandleServerKeyExchange(sslSocket * if (rv != SECSuccess) { goto loser; /* malformed. */ } - dh_Ys_bits = SECKEY_BigIntegerBitLength(&dh_Ys); - if (dh_Ys_bits > dh_p_bits || dh_Ys_bits <= 1) - goto alert_loser; + if (!ssl_IsValidDHEShare(&dh_p, &dh_Ys)) { + errCode = SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY; + goto alert_loser; + } if (isTLS12) { rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length, &sigAndHash); @@ -9906,6 +9907,12 @@ ssl3_HandleDHClientKeyExchange(sslSocket goto loser; } + if (!ssl_IsValidDHEShare(&srvrPubKey->u.dh.prime, + &clntPubKey.u.dh.publicValue)) { + PORT_SetError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + return SECFailure; + } + isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); if (isTLS) target = CKM_TLS_MASTER_KEY_DERIVE_DH; diff -up ./lib/ssl/sslimpl.h.moz-1314604 ./lib/ssl/sslimpl.h --- ./lib/ssl/sslimpl.h.moz-1314604 2016-11-07 21:30:40.028272553 +0100 +++ ./lib/ssl/sslimpl.h 2016-11-07 21:30:40.047272554 +0100 @@ -1647,6 +1647,7 @@ int ssl3_GatherCompleteHandshake(sslSock extern SECStatus ssl3_CreateRSAStepDownKeys(sslSocket *ss); extern SECStatus ssl3_SelectDHParams(sslSocket *ss); +extern PRBool ssl_IsValidDHEShare(const SECItem *dh_p, const SECItem *dh_Ys); #ifndef NSS_DISABLE_ECC extern void ssl3_FilterECCipherSuitesByServerCerts(sslSocket *ss); diff -up ./lib/ssl/sslsock.c.moz-1314604 ./lib/ssl/sslsock.c --- ./lib/ssl/sslsock.c.moz-1314604 2016-11-07 21:30:40.040272554 +0100 +++ ./lib/ssl/sslsock.c 2016-11-07 21:30:40.048272554 +0100 @@ -1462,6 +1462,54 @@ SSL_DHEGroupPrefSet(PRFileDesc *fd, return SECSuccess; } +/* This validates dh_Ys against the group prime. */ +PRBool +ssl_IsValidDHEShare(const SECItem *dh_p, const SECItem *dh_Ys) +{ + unsigned int size_p = SECKEY_BigIntegerBitLength(dh_p); + unsigned int size_y = SECKEY_BigIntegerBitLength(dh_Ys); + unsigned int commonPart; + int cmp; + + if (dh_p->len == 0 || dh_Ys->len == 0) { + return PR_FALSE; + } + + /* Check that the prime is at least odd. */ + if ((dh_p->data[dh_p->len - 1] & 0x01) == 0) { + return PR_FALSE; + } + /* dh_Ys can't be 1, or bigger than dh_p. */ + if (size_y <= 1 || size_y > size_p) { + return PR_FALSE; + } + /* If dh_Ys is shorter, then it's definitely smaller than p-1. */ + if (size_y < size_p) { + return PR_TRUE; + } + + /* Compare the common part of each, minus the final octet. */ + commonPart = (size_p + 7) / 8; + PORT_Assert(commonPart <= dh_Ys->len); + PORT_Assert(commonPart <= dh_p->len); + cmp = PORT_Memcmp(dh_Ys->data + dh_Ys->len - commonPart, + dh_p->data + dh_p->len - commonPart, commonPart - 1); + if (cmp < 0) { + return PR_TRUE; + } + if (cmp > 0) { + return PR_FALSE; + } + + /* The last octet of the prime is the only thing that is different and that + * has to be two greater than the share, otherwise we have Ys == p - 1, + * and that means small subgroups. */ + if (dh_Ys->data[dh_Ys->len - 1] >= (dh_p->data[dh_p->len - 1] - 1)) { + return PR_FALSE; + } + + return PR_TRUE; +} PRCallOnceType gWeakDHParamsRegisterOnce; int gWeakDHParamsRegisterError;