| Index: net/third_party/nss/ssl/ssl3con.c
|
| diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c
|
| index f5c08800547f672f719672a433d8d04229b3d17a..21caea40b9f3ed211f1881a54c4d557874eb4571 100644
|
| --- a/net/third_party/nss/ssl/ssl3con.c
|
| +++ b/net/third_party/nss/ssl/ssl3con.c
|
| @@ -118,6 +118,9 @@ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = {
|
| #endif /* NSS_ENABLE_ECC */
|
| { TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
|
| { TLS_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
|
| + { TLS_SRP_SHA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
|
| + { TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
|
| + { TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
|
|
|
| #ifdef NSS_ENABLE_ECC
|
| { TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
|
| @@ -141,11 +144,15 @@ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = {
|
| { SSL_RSA_WITH_RC4_128_MD5, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE},
|
| { SSL_RSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
|
| { TLS_RSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
|
| + { TLS_SRP_SHA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
|
| + { TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
|
| + { TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
|
|
|
| #ifdef NSS_ENABLE_ECC
|
| { TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
|
| { TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
|
| #endif /* NSS_ENABLE_ECC */
|
| + { TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
|
| { SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
|
| { SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
|
| #ifdef NSS_ENABLE_ECC
|
| @@ -154,6 +161,8 @@ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = {
|
| #endif /* NSS_ENABLE_ECC */
|
| { SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE},
|
| { SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE},
|
| + { TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
|
| + { TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
|
|
|
|
|
| { SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
|
| @@ -283,6 +292,9 @@ static const ssl3KEADef kea_defs[] =
|
| {kea_dh_anon, kt_dh, sign_null, PR_FALSE, 0, PR_FALSE},
|
| {kea_dh_anon_export, kt_dh, sign_null, PR_TRUE, 512, PR_FALSE},
|
| {kea_rsa_fips, kt_rsa, sign_rsa, PR_FALSE, 0, PR_TRUE },
|
| + {kea_srp, kt_srp, sign_null, PR_FALSE, 0, PR_FALSE},
|
| + {kea_srp_rsa, kt_srp, sign_rsa, PR_FALSE, 0, PR_FALSE},
|
| + {kea_srp_dss, kt_srp, sign_dsa, PR_FALSE, 0, PR_FALSE},
|
| #ifdef NSS_ENABLE_ECC
|
| {kea_ecdh_ecdsa, kt_ecdh, sign_ecdsa, PR_FALSE, 0, PR_FALSE},
|
| {kea_ecdhe_ecdsa, kt_ecdh, sign_ecdsa, PR_FALSE, 0, PR_FALSE},
|
| @@ -344,6 +356,21 @@ static const ssl3CipherSuiteDef cipher_suite_defs[] =
|
|
|
|
|
| /* New TLS cipher suites */
|
| + {TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_srp},
|
| + {TLS_SRP_SHA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_srp},
|
| + {TLS_SRP_SHA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_srp},
|
| + {TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA,
|
| + cipher_3des, mac_sha, kea_srp_rsa},
|
| + {TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA,
|
| + cipher_3des, mac_sha, kea_srp_dss},
|
| + {TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
|
| + cipher_aes_128, mac_sha, kea_srp_rsa},
|
| + {TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
|
| + cipher_aes_128, mac_sha, kea_srp_dss},
|
| + {TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA,
|
| + cipher_aes_256, mac_sha, kea_srp_rsa},
|
| + {TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA,
|
| + cipher_aes_256, mac_sha, kea_srp_dss},
|
| {TLS_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_rsa},
|
| {TLS_DHE_DSS_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_dhe_dss},
|
| {TLS_DHE_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_dhe_rsa},
|
| @@ -420,7 +447,8 @@ static const CK_MECHANISM_TYPE kea_alg_defs[] = {
|
| CKM_RSA_PKCS,
|
| CKM_DH_PKCS_DERIVE,
|
| CKM_KEA_KEY_DERIVE,
|
| - CKM_ECDH1_DERIVE
|
| + CKM_ECDH1_DERIVE,
|
| + CKM_NSS_SRP_DERIVE
|
| };
|
|
|
| typedef struct SSLCipher2MechStr {
|
| @@ -695,12 +723,27 @@ ssl3_config_match_init(sslSocket *ss)
|
| }
|
| #endif /* NSS_ENABLE_ECC */
|
|
|
| + /* XXX this should be merged with switch(kea) from above */
|
| + switch (cipher_def->key_exchange_alg) {
|
| + case kea_srp_rsa:
|
| + svrAuth = ss->serverCerts + kt_rsa;
|
| + break;
|
| + case kea_srp_dss:
|
| + svrAuth = ss->serverCerts + kt_null; /* don't ask me..*/
|
| + break;
|
| + default:
|
| + svrAuth = ss->serverCerts + exchKeyType;
|
| + break;
|
| + }
|
| +
|
| +
|
| /* Mark the suites that are backed by real tokens, certs and keys */
|
| suite->isPresent = (PRBool)
|
| (((exchKeyType == kt_null) ||
|
| ((!isServer || (svrAuth->serverKeyPair &&
|
| svrAuth->SERVERKEY &&
|
| - svrAuth->serverCertChain)) &&
|
| + svrAuth->serverCertChain) ||
|
| + cipher_def->key_exchange_alg == kea_srp) &&
|
| PK11_TokenExists(kea_alg_defs[exchKeyType]))) &&
|
| ((cipher_alg == calg_null) || PK11_TokenExists(cipher_mech)));
|
| if (suite->isPresent)
|
| @@ -1080,6 +1123,57 @@ ssl3_ComputeExportRSAKeyHash(SECItem modulus, SECItem publicExponent,
|
| return rv;
|
| }
|
|
|
| +/* Caller must set hiLevel error code.
|
| + * Called from ssl3_SendSRPServerKeyExchange */
|
| +static SECStatus
|
| +ssl3_ComputeSRPKeyHash(SECItem *N, SECItem *g, SECItem *s, SECItem *B,
|
| + SSL3Random *client_rand, SSL3Random *server_rand,
|
| + SSL3Hashes *hashes, PRBool bypassPKCS11)
|
| +{
|
| + PRUint8 * hashBuf;
|
| + PRUint8 * pBuf;
|
| + SECStatus rv = SECFailure;
|
| + unsigned int bufLen;
|
| +
|
| + bufLen = 2*SSL3_RANDOM_LENGTH + N->len + 2 + g->len + 2
|
| + + s->len + 1 + B->len + 2;
|
| +
|
| + hashBuf = PORT_Alloc(bufLen);
|
| + if (!hashBuf) {
|
| + return SECFailure;
|
| + }
|
| +
|
| + memcpy(hashBuf, client_rand, SSL3_RANDOM_LENGTH);
|
| + pBuf = hashBuf + SSL3_RANDOM_LENGTH;
|
| + memcpy(pBuf, server_rand, SSL3_RANDOM_LENGTH);
|
| + pBuf += SSL3_RANDOM_LENGTH;
|
| + pBuf[0] = (PRUint8)(N->len >> 8);
|
| + pBuf[1] = (PRUint8)(N->len);
|
| + pBuf+=2;
|
| + memcpy(pBuf, N->data, N->len);
|
| + pBuf += N->len;
|
| + pBuf[0] = (PRUint8)(g->len >> 8);
|
| + pBuf[1] = (PRUint8)(g->len);
|
| + pBuf+=2;
|
| + memcpy(pBuf, g->data, g->len);
|
| + pBuf += g->len;
|
| + pBuf[0] = (PRUint8)(s->len);
|
| + pBuf+=1;
|
| + memcpy(pBuf, s->data, s->len);
|
| + pBuf += s->len;
|
| + pBuf[0] = (PRUint8)(B->len >> 8);
|
| + pBuf[1] = (PRUint8)(B->len);
|
| + pBuf+=2;
|
| + memcpy(pBuf, B->data, B->len);
|
| + pBuf += B->len;
|
| +
|
| + rv = ssl3_ComputeCommonKeyHash(hashBuf, bufLen, hashes, bypassPKCS11);
|
| +
|
| + if (hashBuf)
|
| + PORT_Free(hashBuf);
|
| + return rv;
|
| +}
|
| +
|
| /* Caller must set hiLevel error code. */
|
| /* Called from ssl3_HandleServerKeyExchange. */
|
| static SECStatus
|
| @@ -2663,6 +2757,8 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf)
|
| error = SSL_ERROR_BAD_CERT_STATUS_RESPONSE_ALERT; break;
|
| case bad_certificate_hash_value:
|
| error = SSL_ERROR_BAD_CERT_HASH_VALUE_ALERT; break;
|
| + case unknown_psk_identity:
|
| + error = SSL_ERROR_UNKNOWN_PSK_IDENTITY_ALERT; break;
|
| default: error = SSL_ERROR_RX_UNKNOWN_ALERT; break;
|
| }
|
| if (level == alert_fatal) {
|
| @@ -2828,7 +2924,8 @@ ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms)
|
| * data into a 48-byte value.
|
| */
|
| PRBool isDH = (PRBool) ((ss->ssl3.hs.kea_def->exchKeyType == kt_dh) ||
|
| - (ss->ssl3.hs.kea_def->exchKeyType == kt_ecdh));
|
| + (ss->ssl3.hs.kea_def->exchKeyType == kt_ecdh) ||
|
| + (ss->ssl3.hs.kea_def->exchKeyType == kt_srp));
|
| SECStatus rv = SECFailure;
|
| CK_MECHANISM_TYPE master_derive;
|
| CK_MECHANISM_TYPE key_derive;
|
| @@ -4733,8 +4830,241 @@ loser:
|
| return rv;
|
| }
|
|
|
| +/* Read srp values from datastream and verify the signature
|
| + * if requiried by cipher. Save parameters to ss->sec.peerKey.
|
| + *
|
| + * called from ssl3_HandleServerKeyExchange
|
| + */
|
| +static SECStatus
|
| +ssl3_HandleSRPServerKeyExchange(sslSocket *ss, SSL3Opaque *b,
|
| + PRUint32 length) {
|
| +
|
| + SECItem signature = {siBuffer, NULL, 0};
|
| + PRArenaPool *arena = NULL;
|
| + SECKEYPublicKey *peerKey = NULL;
|
| + SECStatus rv;
|
| + SSL3Hashes hashes;
|
| + SECItem srp_N, srp_g, srp_s, srp_ppub;
|
| + int errCode;
|
| +
|
| + rv = ssl3_ConsumeHandshakeVariable(ss, &srp_N, 2, &b, &length);
|
| + if (rv != SECSuccess) {
|
| + goto loser; /* malformed. */
|
| + }
|
| + rv = ssl3_ConsumeHandshakeVariable(ss, &srp_g, 2, &b, &length);
|
| + if (rv != SECSuccess) {
|
| + goto loser; /* malformed. */
|
| + }
|
| + rv = ssl3_ConsumeHandshakeVariable(ss, &srp_s, 1, &b, &length);
|
| + if (rv != SECSuccess) {
|
| + goto loser; /* malformed. */
|
| + }
|
| + rv = ssl3_ConsumeHandshakeVariable(ss, &srp_ppub, 2, &b, &length);
|
| + if (rv != SECSuccess) {
|
| + goto loser; /* malformed. */
|
| + }
|
| +
|
| + if (ss->ssl3.hs.kea_def->kea != kea_srp) { /* there MUST be a signature */
|
| + rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length);
|
| + if (rv != SECSuccess) {
|
| + goto loser; /* malformed. */
|
| + }
|
| + rv = ssl3_ComputeSRPKeyHash(&srp_N, &srp_g, &srp_s, &srp_ppub,
|
| + &ss->ssl3.hs.client_random,
|
| + &ss->ssl3.hs.server_random,
|
| + &hashes, ss->opt.bypassPKCS11);
|
| + if (rv != SECSuccess) {
|
| + errCode = ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
|
| + goto alert_loser;
|
| + }
|
| + rv = ssl3_VerifySignedHashes(&hashes, ss->sec.peerCert, &signature,
|
| + PR_TRUE, ss->pkcs11PinArg);
|
| + if (rv != SECSuccess) {
|
| + errCode = ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
|
| + goto alert_loser;
|
| + }
|
| + }
|
| +
|
| + /* all ok, save and return */
|
| + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
| + if (arena == NULL) {
|
| + return SECFailure;
|
| + }
|
| + ss->sec.peerKey = peerKey = PORT_ArenaZNew(arena, SECKEYPublicKey);
|
| + if (peerKey == NULL) {
|
| + return SECFailure;
|
| + }
|
| + peerKey->arena = arena;
|
| + peerKey->keyType = srpKey;
|
| + peerKey->pkcs11Slot = NULL;
|
| + peerKey->pkcs11ID = CK_INVALID_HANDLE;
|
| +
|
| + if (SECITEM_CopyItem(arena, &peerKey->u.srp.N, &srp_N) ||
|
| + SECITEM_CopyItem(arena, &peerKey->u.srp.g, &srp_g) ||
|
| + SECITEM_CopyItem(arena, &peerKey->u.srp.s, &srp_s) ||
|
| + SECITEM_CopyItem(arena, &peerKey->u.srp.ppub, &srp_ppub)) {
|
| + return SECFailure;
|
| + }
|
| + return SECSuccess;
|
| +
|
| +alert_loser:
|
| + (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
|
| +loser:
|
| + PORT_SetError(errCode);
|
| + return SECFailure;
|
| +}
|
| +
|
| +/* Calculate ClientKeyExchange and Pre-Master-Secret via SRP_GenKeys(),
|
| + * then send ClientKeyExchange and derive SSL master key
|
| + *
|
| + * called from ssl3_SendClientKeyExchange()
|
| + */
|
| +static SECStatus
|
| +ssl3_SendSRPClientKeyExchange(sslSocket *ss, SECKEYPublicKey * pubKey) {
|
| +
|
| + SECKEYSRPParams *srpParam;
|
| + SECStatus rv;
|
| +
|
| + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
|
| + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
|
| +
|
| + srpParam = PORT_ZAlloc(sizeof(SECKEYSRPParams));
|
| + if (!srpParam) {
|
| + ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
|
| + goto loser;
|
| + }
|
| +
|
| + /* PW-Callback overrides SSL_SetUserLogin. If both fail to
|
| + * provide a password, the token must know it or fail. */
|
| + if (ss->getUserPasswd) {
|
| + if (!ss->sec.userPasswd)
|
| + ss->sec.userPasswd = SECITEM_AllocItem(NULL,NULL,0);
|
| + SECITEM_FreeItem(ss->sec.userPasswd, PR_FALSE);
|
| + ss->getUserPasswd(ss->fd, ss->sec.userPasswd, ss->getUserPasswdArg);
|
| + }
|
| + if (ss->sec.userPasswd) {
|
| + srpParam->secret.data = ss->sec.userPasswd->data;
|
| + srpParam->secret.len = ss->sec.userPasswd->len;
|
| + ss->sec.userPasswd = NULL;
|
| + }
|
|
|
| + /* calculate client key pair and PMS, then send key exchange data */
|
| + if (ss->opt.bypassPKCS11) {
|
| + SECItem pms = {0, NULL, 0};
|
| + SRPPrivateKey *prvKey;
|
| + SRPKeyPairParams keyPairParam;
|
| + keyPairParam.N.data = pubKey->u.srp.N.data;
|
| + keyPairParam.N.len = pubKey->u.srp.N.len;
|
| + keyPairParam.g.data = pubKey->u.srp.g.data;
|
| + keyPairParam.g.len = pubKey->u.srp.g.len;
|
| + keyPairParam.secret.data = srpParam->secret.data;
|
| + keyPairParam.secret.len = srpParam->secret.len;
|
| +
|
| + rv = SRP_NewClientKeyPair(&prvKey, &keyPairParam);
|
| + if (rv != SECSuccess) goto loser; /* err set by SRP_ClientDerive */
|
| +
|
| + SRPDeriveParams deriveParam;
|
| + deriveParam.N.data = pubKey->u.srp.N.data;
|
| + deriveParam.N.len = pubKey->u.srp.N.len;
|
| + deriveParam.g.data = pubKey->u.srp.g.data;
|
| + deriveParam.g.len = pubKey->u.srp.g.len;
|
| + deriveParam.s.data = pubKey->u.srp.s.data;
|
| + deriveParam.s.len = pubKey->u.srp.s.len;
|
| + deriveParam.u.data = ss->sec.userName->data;
|
| + deriveParam.u.len = ss->sec.userName->len;
|
| + deriveParam.ppub.data= pubKey->u.srp.ppub.data;
|
| + deriveParam.ppub.len = pubKey->u.srp.ppub.len;
|
| +
|
| +
|
| + if (SECSuccess != SRP_ClientDerive(prvKey, &deriveParam, &pms)) {
|
| + goto derive_fail;
|
| + }
|
| +
|
| + /* client key exchange data */
|
| + rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange,
|
| + prvKey->pubKey.len + 2);
|
| + if (rv != SECSuccess) goto loser; /* err set by ssl3_AppendHandshake* */
|
| + rv = ssl3_AppendHandshakeVariable(ss, prvKey->pubKey.data,
|
| + prvKey->pubKey.len, 2);
|
| + if (rv != SECSuccess) goto loser; /* err set by ssl3_AppendHandshake* */
|
| +
|
| + /* init pending cipher spec*/
|
| + rv = ssl3_MasterKeyDeriveBypass(ss->ssl3.pwSpec,
|
| + (unsigned char *)&ss->ssl3.hs.client_random,
|
| + (unsigned char *)&ss->ssl3.hs.server_random,
|
| + &pms, PR_TRUE, PR_FALSE);
|
| + if (rv != SECSuccess) {
|
| + ss->ssl3.pwSpec->msItem.data = ss->ssl3.pwSpec->raw_master_secret;
|
| + ss->ssl3.pwSpec->msItem.len = SSL3_MASTER_SECRET_LENGTH;
|
| + PK11_GenerateRandom(ss->ssl3.pwSpec->msItem.data,
|
| + SSL3_MASTER_SECRET_LENGTH);
|
| + }
|
| + rv = ssl3_InitPendingCipherSpec(ss, NULL);
|
| +
|
| + SECITEM_FreeItem(&pms, PR_FALSE);
|
| + PORT_FreeArena(prvKey->arena, PR_TRUE);
|
| + } else { /* PK11 path */
|
| + PK11SymKey *pms = NULL;
|
| + SECKEYPrivateKey *prvKey = NULL;
|
| + SECKEYPublicKey *newPub = NULL;
|
| +
|
| + srpParam->N.data = pubKey->u.srp.N.data;
|
| + srpParam->N.len = pubKey->u.srp.N.len;
|
| + srpParam->g.data = pubKey->u.srp.g.data;
|
| + srpParam->g.len = pubKey->u.srp.g.len;
|
| + srpParam->s.data = pubKey->u.srp.s.data;
|
| + srpParam->s.len = pubKey->u.srp.s.len;
|
| + srpParam->u.data = ss->sec.userName->data;
|
| + srpParam->u.len = ss->sec.userName->len;
|
| +
|
| + /* The token handles (missing) info supplied in srpParam
|
| + * The template not actually involved in key generation,
|
| + * but it's important in the server key exchange */
|
| +
|
| + prvKey = SECKEY_CreateSRPPrivateKey(srpParam, &newPub, PR_FALSE, NULL);
|
| + if (!prvKey) {
|
| + ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
|
| + rv = SECFailure;
|
| + goto loser;
|
| + }
|
| + SECITEM_CopyItem(newPub->arena, &newPub->u.srp.ppub, &pubKey->u.srp.ppub);
|
| +
|
| + /* Now all data is in newPub and prvKey, compute pms with them */
|
| + pms = PK11_PubDerive(prvKey, newPub, PR_FALSE, NULL, NULL,
|
| + CKM_NSS_SRP_DERIVE, CKM_TLS_MASTER_KEY_DERIVE, CKF_DERIVE, 0, NULL);
|
|
|
| + if (!pms) {
|
| + goto derive_fail;
|
| + }
|
| +
|
| + /* init pending cipher spec*/
|
| + rv = ssl3_InitPendingCipherSpec(ss, pms);
|
| +
|
| +
|
| + /* client key exchange data */
|
| + rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange,
|
| + newPub->u.srp.pub.len + 2);
|
| + if (rv != SECSuccess) goto loser; /* err set by ssl3_AppendHandshake* */
|
| + rv = ssl3_AppendHandshakeVariable(ss, newPub->u.srp.pub.data,
|
| + newPub->u.srp.pub.len, 2);
|
| + if (rv != SECSuccess) goto loser; /* err set by ssl3_AppendHandshake* */
|
| +
|
| + if (pms) PK11_FreeSymKey(pms);
|
| + SECKEY_DestroyPublicKey(newPub);
|
| + } /* end of PK11 path */
|
| +
|
| +loser:
|
| + SECITEM_ZfreeItem(ss->sec.userPasswd, PR_TRUE);
|
| + PORT_Free(srpParam);
|
| + /* caller frees pubKey */
|
| + return rv;
|
| +derive_fail:
|
| + if (PORT_GetError() == SEC_ERROR_SRP_UNSUPPORTED_GROUP)
|
| + SSL3_SendAlert(ss, alert_fatal, insufficient_security);
|
| + if (PORT_GetError() == SEC_ERROR_SRP_ILLEGAL_PARAMETER)
|
| + SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
|
| + return SECFailure;
|
| +}
|
|
|
|
|
| /* Called from ssl3_HandleServerHelloDone(). */
|
| @@ -4794,7 +5124,9 @@ ssl3_SendClientKeyExchange(sslSocket *ss)
|
| rv = ssl3_SendECDHClientKeyExchange(ss, serverKey);
|
| break;
|
| #endif /* NSS_ENABLE_ECC */
|
| -
|
| + case kt_srp:
|
| + rv = ssl3_SendSRPClientKeyExchange(ss, serverKey);
|
| + break;
|
| default:
|
| /* got an unknown or unsupported Key Exchange Algorithm. */
|
| SEND_ALERT
|
| @@ -5284,7 +5616,8 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| desc = unexpected_message;
|
| goto alert_loser;
|
| }
|
| - if (ss->sec.peerCert == NULL) {
|
| + if (ss->sec.peerCert == NULL &&
|
| + ss->ssl3.hs.suite_def->key_exchange_alg != kea_srp) {
|
| errCode = SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH;
|
| desc = unexpected_message;
|
| goto alert_loser;
|
| @@ -5473,6 +5806,13 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| rv = ssl3_HandleECDHServerKeyExchange(ss, b, length);
|
| return rv;
|
| #endif /* NSS_ENABLE_ECC */
|
| + case kt_srp:
|
| + rv = ssl3_HandleSRPServerKeyExchange(ss, b, length);
|
| + if (rv != SECSuccess) {
|
| + errCode = ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
|
| + goto alert_loser;
|
| + }
|
| + return rv;
|
|
|
| default:
|
| desc = handshake_failure;
|
| @@ -6034,16 +6374,20 @@ ssl3_SendServerHelloSequence(sslSocket *ss)
|
| if (rv != SECSuccess) {
|
| return rv; /* err code is set. */
|
| }
|
| - rv = ssl3_SendCertificate(ss);
|
| - if (rv != SECSuccess) {
|
| - return rv; /* error code is set. */
|
| - }
|
| /* We have to do this after the call to ssl3_SendServerHello,
|
| * because kea_def is set up by ssl3_SendServerHello().
|
| */
|
| kea_def = ss->ssl3.hs.kea_def;
|
| ss->ssl3.hs.usedStepDownKey = PR_FALSE;
|
|
|
| +
|
| + if (kea_def->kea != kea_srp) { /* SRP auth only */
|
| + rv = ssl3_SendCertificate(ss);
|
| + if (rv != SECSuccess) {
|
| + return rv; /* error code is set. */
|
| + }
|
| + }
|
| +
|
| if (kea_def->is_limited && kea_def->exchKeyType == kt_rsa) {
|
| /* see if we can legally use the key in the cert. */
|
| int keyLen; /* bytes */
|
| @@ -6075,6 +6419,11 @@ ssl3_SendServerHelloSequence(sslSocket *ss)
|
| return rv; /* err code was set. */
|
| }
|
| #endif /* NSS_ENABLE_ECC */
|
| + } else if ( kea_def->exchKeyType == kt_srp ) {
|
| + rv = ssl3_SendServerKeyExchange(ss);
|
| + if (rv != SECSuccess) {
|
| + return rv; /* err code was set. */
|
| + }
|
| }
|
|
|
| if (ss->opt.requestCertificate) {
|
| @@ -7099,6 +7448,195 @@ ssl3_SendServerHello(sslSocket *ss)
|
| return SECSuccess;
|
| }
|
|
|
| +/* ssl3_SendSRPServerKeyExchange()
|
| + * called by ssl3_SendServerKeyExchange()
|
| + *
|
| + * - make sure we got a userid in the srp client hello extension
|
| + * - retrieve verifier and parameters for the user via callback func
|
| + * - if user nonexistant, CB makes something up if it wants to
|
| + * - continue by creating and sending the SRP key exchange data:
|
| + *
|
| + * N, g, s, v = <read from password file>
|
| + * b = random()
|
| + * k = SHA1(N | PAD(g))
|
| + * B = k*v + g^b % N
|
| + * send (N,g,s,B)
|
| + *
|
| + * save values b,v,N for calculation of pms in ssl3_HandleSRPClientKeyExchange
|
| + */
|
| +
|
| +SECStatus
|
| +ssl3_SendSRPServerKeyExchange(sslSocket *ss) {
|
| +
|
| + int bytes = 0;
|
| + const ssl3KEADef *kea_def = ss->ssl3.hs.kea_def;
|
| + SECItem signed_hash = {siBuffer, NULL, 0};
|
| + SECStatus rv = SECFailure;
|
| + SECKEYSRPPublicKey *srp = NULL;
|
| + SECKEYPublicKey *pubKey = NULL;
|
| + SECKEYPrivateKey *prvKey = NULL;
|
| + SECKEYSRPParams *srpParams;
|
| + SSL3Hashes hashes;
|
| +
|
| + /* send error if no userid was supplied in Client Hello */
|
| + if (!ss->sec.userName || !ss->sec.userName->data)
|
| + goto unknown_id;
|
| +
|
| + /* Ask application for SRP parameters for specified username.
|
| + * Information provided via callback overrides data set on token.
|
| + * If no params provided, the token must supply them or fail.
|
| + * Callback may fail for nonexistant user.
|
| + */
|
| +
|
| + srpParams = PORT_ZAlloc(sizeof(SECKEYSRPParams));
|
| + if (!srpParams) goto no_memory;
|
| +
|
| + srpParams->u.data = ss->sec.userName->data;
|
| + srpParams->u.len = ss->sec.userName->len;
|
| +
|
| + if (ss->getSRPParams) {
|
| + rv = ss->getSRPParams(ss->fd, srpParams, ss->getSRPParamsArg);
|
| + if (rv != SECSuccess) {
|
| + SECITEM_FreeItem(&srpParams->N, PR_FALSE);
|
| + SECITEM_FreeItem(&srpParams->g, PR_FALSE);
|
| + SECITEM_FreeItem(&srpParams->s, PR_FALSE);
|
| + SECITEM_ZfreeItem(&srpParams->secret, PR_FALSE);
|
| + PORT_Free(srpParams);
|
| + goto unknown_id;
|
| + }
|
| + }
|
| +
|
| + /* create SRP server key pair */
|
| + if (ss->opt.bypassPKCS11) {
|
| + /* srpParams, keyPairParams are temporary. pubKey and prvKey have
|
| + * own arenas and are saved for ssl3_HandleSRPClientKeyExchange */
|
| + SRPPrivateKey *srpPrv;
|
| + SRPKeyPairParams keyPairParams;
|
| +
|
| + PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
| + if (!arena) goto no_memory;
|
| +
|
| + keyPairParams.N.data = srpParams->N.data;
|
| + keyPairParams.N.len = srpParams->N.len;
|
| + keyPairParams.g.data = srpParams->g.data;
|
| + keyPairParams.g.len = srpParams->g.len;
|
| + keyPairParams.secret.data = srpParams->secret.data;
|
| + keyPairParams.secret.len = srpParams->secret.len;
|
| +
|
| + rv = SRP_NewServerKeyPair(&srpPrv, &keyPairParams);
|
| + if (rv != SECSuccess) {
|
| + ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
|
| + return rv;
|
| + }
|
| + prvKey = (SECKEYPrivateKey *)srpPrv;
|
| +
|
| + /* create pubKey from temporary stuff */
|
| + pubKey = PORT_ArenaZAlloc(arena, sizeof(SECKEYPublicKey));
|
| + if (!pubKey) goto no_memory;
|
| + pubKey->arena = arena;
|
| + srp = &pubKey->u.srp;
|
| +
|
| + SECITEM_CopyItem(arena, &srp->N, &srpParams->N);
|
| + SECITEM_CopyItem(arena, &srp->g, &srpParams->g);
|
| + SECITEM_CopyItem(arena, &srp->s, &srpParams->s);
|
| + SECITEM_CopyItem(arena, &srp->u, &srpParams->u);
|
| + SECITEM_CopyItem(arena, &srp->pub, &srpPrv->pubKey);
|
| +
|
| + } else {
|
| +
|
| + /* input: srpParams, output: prvKey = b,B,v, pubKey = N,g,s,u,B */
|
| + prvKey = SECKEY_CreateSRPPrivateKey(srpParams, &pubKey, PR_TRUE, NULL);
|
| + if (!prvKey) {
|
| + ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
|
| + rv = SECFailure;
|
| + goto cleanup;
|
| + }
|
| + srp = &pubKey->u.srp;
|
| + }
|
| +
|
| + /* send N,g,s,B as ServerKeyExchange to Client */
|
| + /* optionally include signature for additional DSS/RSA auth */
|
| +
|
| + if (kea_def->kea != kea_srp) { /* we need a RSA/DSA signature */
|
| + rv = ssl3_ComputeSRPKeyHash(&srp->N, &srp->g, &srp->s, &srp->pub,
|
| + &ss->ssl3.hs.client_random,
|
| + &ss->ssl3.hs.server_random,
|
| + &hashes, ss->opt.bypassPKCS11);
|
| + if (rv != SECSuccess) {
|
| + ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
|
| + goto loser;
|
| + }
|
| + /* look if we have a certificate for selected algo */
|
| + if (kea_def->kea == kea_srp_rsa)
|
| + bytes = kt_rsa;
|
| + else
|
| + bytes = kt_null;
|
| +
|
| + if (!(&ss->serverCerts[bytes])) {
|
| + /* ciphersuite signing algo does not match supplied certificate */
|
| + PORT_SetError(SSL_ERROR_CERT_KEA_MISMATCH);
|
| + return SECFailure;
|
| + }
|
| + rv = ssl3_SignHashes(&hashes, ss->serverCerts[bytes].SERVERKEY,
|
| + &signed_hash, PR_TRUE);
|
| + bytes = 2 + signed_hash.len;
|
| + }
|
| +
|
| + bytes += srp->N.len + srp->g.len + srp->s.len + srp->pub.len + 7;
|
| +
|
| + rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, bytes);
|
| + if (rv != SECSuccess)
|
| + return rv; /* err set by AppendHandshake. */
|
| +
|
| + rv = ssl3_AppendHandshakeVariable(ss, srp->N.data, srp->N.len, 2);
|
| + if (rv != SECSuccess)
|
| + return rv; /* err set by AppendHandshake. */
|
| +
|
| + rv = ssl3_AppendHandshakeVariable(ss, srp->g.data, srp->g.len, 2);
|
| + if (rv != SECSuccess)
|
| + return rv; /* err set by AppendHandshake. */
|
| +
|
| + rv = ssl3_AppendHandshakeVariable(ss, srp->s.data, srp->s.len, 1);
|
| + if (rv != SECSuccess)
|
| + return rv; /* err set by AppendHandshake. */
|
| +
|
| + rv = ssl3_AppendHandshakeVariable(ss, srp->pub.data, srp->pub.len, 2);
|
| + if (rv != SECSuccess)
|
| + return rv; /* err set by AppendHandshake. */
|
| +
|
| + if (kea_def->kea != kea_srp) {
|
| + rv = ssl3_AppendHandshakeVariable(ss, signed_hash.data,
|
| + signed_hash.len, 2);
|
| + if (rv != SECSuccess) {
|
| + return rv; /* err set by AppendHandshake. */
|
| + }
|
| + SECITEM_FreeItem(&signed_hash, PR_FALSE);
|
| + }
|
| +
|
| + /* save prvKey / pubKey for use in HandleSRPClientExchange
|
| + * XXX in bypassPK11, prvKey is no PK11 object and must be casted */
|
| + ssl3KeyPair *srpPair = ssl3_NewKeyPair(prvKey, pubKey);
|
| + ss->serverCerts[kt_srp].serverKeyPair = srpPair;
|
| +
|
| +cleanup:
|
| + SECITEM_FreeItem(&srpParams->N, PR_FALSE);
|
| + SECITEM_FreeItem(&srpParams->g, PR_FALSE);
|
| + SECITEM_FreeItem(&srpParams->s, PR_FALSE);
|
| + SECITEM_ZfreeItem(&srpParams->secret, PR_FALSE);
|
| + if (srpParams) PORT_Free(srpParams);
|
| + return rv;
|
| +loser:
|
| + PORT_SetError(SSL_ERROR_INTERNAL_ERROR_ALERT);
|
| + (void)SSL3_SendAlert(ss, alert_fatal, internal_error);
|
| + return SECFailure;
|
| +unknown_id:
|
| + PORT_SetError(SSL_ERROR_UNKNOWN_PSK_IDENTITY_ALERT);
|
| + (void)SSL3_SendAlert(ss, alert_fatal, unknown_psk_identity);
|
| + return SECFailure;
|
| +no_memory:
|
| + ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
|
| + return SECFailure;
|
| +}
|
|
|
| static SECStatus
|
| ssl3_SendServerKeyExchange(sslSocket *ss)
|
| @@ -7183,7 +7721,9 @@ const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def;
|
| return rv;
|
| }
|
| #endif /* NSS_ENABLE_ECC */
|
| -
|
| + case kt_srp:
|
| + rv = ssl3_SendSRPServerKeyExchange(ss);
|
| + return rv;
|
| case kt_dh:
|
| case kt_null:
|
| default:
|
| @@ -7536,6 +8076,101 @@ double_bypass:
|
| return SECSuccess;
|
| }
|
|
|
| +/*
|
| + * extract SRP value A from ClientKeyExchange
|
| + * calculate pre-master-secret and init cipher specs
|
| + *
|
| + * called by ssl3_HandleClientKeyExchange
|
| + */
|
| +SECStatus
|
| +ssl3_HandleSRPClientKeyExchange(sslSocket *ss, SSL3Opaque *b,
|
| + PRUint32 length) {
|
| +
|
| + SECItem ppub; /* peers public key ('A') */
|
| + sslServerCerts sc;
|
| + SECStatus rv = SECFailure;
|
| + SECKEYPublicKey *pubKey = NULL;
|
| +
|
| +
|
| + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
|
| + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
|
| +
|
| + rv = ssl3_ConsumeHandshakeVariable(ss, &ppub, 2, &b, &length);
|
| + if (rv != SECSuccess) {
|
| + PORT_SetError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
|
| + return SECFailure;
|
| + }
|
| +
|
| + sc = ss->serverCerts[kt_srp];
|
| + pubKey = sc.serverKeyPair->pubKey;
|
| +
|
| + SECITEM_CopyItem(pubKey->arena, &pubKey->u.srp.ppub, &ppub);
|
| +
|
| + if (ss->opt.bypassPKCS11) {
|
| + SRPPrivateKey *prvKey = NULL;
|
| + SECItem pms = { 0, NULL, 0 };
|
| + SRPDeriveParams param;
|
| +
|
| + prvKey = (SRPPrivateKey *)sc.serverKeyPair->privKey;
|
| +
|
| + param.N.data = pubKey->u.srp.N.data;
|
| + param.N.len = pubKey->u.srp.N.len;
|
| + param.g.data = pubKey->u.srp.g.data;
|
| + param.g.len = pubKey->u.srp.g.len;
|
| + param.ppub.data = pubKey->u.srp.ppub.data;
|
| + param.ppub.len = pubKey->u.srp.ppub.len;
|
| +
|
| + if (SECSuccess != SRP_ServerDerive(prvKey, ¶m, &pms))
|
| + goto derive_fail;
|
| +
|
| + ssl_GetSpecWriteLock(ss);
|
| + /* create MS out of MS, bypassing PKCS11 */
|
| + rv = ssl3_MasterKeyDeriveBypass(ss->ssl3.pwSpec,
|
| + (unsigned char *)&ss->ssl3.hs.client_random,
|
| + (unsigned char *)&ss->ssl3.hs.server_random,
|
| + &pms, PR_TRUE, PR_FALSE);
|
| + if (rv != SECSuccess) {
|
| + ss->ssl3.pwSpec->msItem.data = ss->ssl3.pwSpec->raw_master_secret;
|
| + ss->ssl3.pwSpec->msItem.len = SSL3_MASTER_SECRET_LENGTH;
|
| + PK11_GenerateRandom(ss->ssl3.pwSpec->msItem.data, ss->ssl3.pwSpec->msItem.len);
|
| + }
|
| +
|
| + rv = ssl3_InitPendingCipherSpec(ss, NULL);
|
| +
|
| + SECITEM_ZfreeItem(&pms, PR_FALSE);
|
| + PORT_FreeArena(prvKey->arena, PR_TRUE); /* XXX FreeArena does not zeroize! */
|
| + sc.serverKeyPair->privKey = NULL;
|
| +
|
| + } else {
|
| + SECKEYPrivateKey *prvKey = NULL;
|
| + PK11SymKey *pms = NULL; /* pre-master secret */
|
| +
|
| + prvKey = sc.serverKeyPair->privKey;
|
| +
|
| + /* Calculate PMS based on clntKey and public params */
|
| + pms = PK11_PubDerive(prvKey, pubKey, PR_TRUE, NULL, NULL,
|
| + CKM_NSS_SRP_DERIVE, CKM_TLS_MASTER_KEY_DERIVE, CKF_DERIVE, 0, NULL);
|
| +
|
| + if (!pms) {
|
| + goto derive_fail;
|
| + }
|
| +
|
| + ssl_GetSpecWriteLock(ss);
|
| + /* derive master secret from pms */
|
| + rv = ssl3_InitPendingCipherSpec(ss, pms);
|
| + ssl_ReleaseSpecWriteLock(ss);
|
| +
|
| + PK11_FreeSymKey(pms);
|
| + /*SECKEY_DestroyPrivateKey(prvKey);*/
|
| + }
|
| +
|
| + return rv;
|
| +derive_fail:
|
| + if (PORT_GetError() == SEC_ERROR_SRP_ILLEGAL_PARAMETER)
|
| + SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
|
| + return rv;
|
| +}
|
| +
|
|
|
| /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
|
| * ssl3 ClientKeyExchange message from the remote client
|
| @@ -7608,7 +8243,8 @@ skip:
|
| serverKey = serverKeyPair->privKey;
|
| }
|
|
|
| - if (serverKey == NULL) {
|
| + /* XXX hack, figure out this serverKey thing..*/
|
| + if (serverKey == NULL && kea_def->exchKeyType != kt_srp) {
|
| SEND_ALERT
|
| PORT_SetError(SSL_ERROR_NO_SERVER_KEY_FOR_ALG);
|
| return SECFailure;
|
| @@ -7649,7 +8285,12 @@ skip:
|
| }
|
| break;
|
| #endif /* NSS_ENABLE_ECC */
|
| -
|
| + case kt_srp:
|
| + rv = ssl3_HandleSRPClientKeyExchange(ss, b, length);
|
| + if (rv != SECSuccess) {
|
| + return SECFailure; /* error code set */
|
| + }
|
| + break;
|
| default:
|
| (void) ssl3_HandshakeFailure(ss);
|
| PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
|
| @@ -7823,8 +8464,12 @@ ssl3_SendCertificate(sslSocket *ss)
|
| * using EC certificates.
|
| */
|
| if ((ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa) ||
|
| - (ss->ssl3.hs.kea_def->kea == kea_dhe_rsa)) {
|
| + (ss->ssl3.hs.kea_def->kea == kea_dhe_rsa) ||
|
| + (ss->ssl3.hs.kea_def->kea == kea_srp_rsa)) {
|
| certIndex = kt_rsa;
|
| + } else if
|
| + (ss->ssl3.hs.kea_def->kea == kea_srp_dss) {
|
| + certIndex = kt_null;
|
| } else {
|
| certIndex = ss->ssl3.hs.kea_def->exchKeyType;
|
| }
|
| @@ -8244,7 +8889,9 @@ cert_block:
|
| ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa ||
|
| ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa ||
|
| #endif /* NSS_ENABLE_ECC */
|
| - ss->ssl3.hs.kea_def->exchKeyType == kt_dh) {
|
| + ss->ssl3.hs.kea_def->exchKeyType == kt_dh ||
|
| + ss->ssl3.hs.kea_def->kea == kea_srp_dss ||
|
| + ss->ssl3.hs.kea_def->kea == kea_srp_rsa) {
|
| ss->ssl3.hs.ws = wait_server_key; /* allow server_key_exchange */
|
| }
|
| }
|
|
|