| 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 */
 | 
|  	}
 | 
|      }
 | 
| 
 |