PORT_Assert( ssl_Have1stHandshakeLock(ss) );
PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
ssl2_ClientSetupSessionCypher(sslSocket *ss, PRUint8 *cs, int csLen){    sslSessionID *    sid;    PRUint8 *         ca;	/* points to iv data, or NULL if none. */    PRUint8 *         ekbuf 		= 0;    CERTCertificate * cert 		= 0;    SECKEYPublicKey * serverKey 	= 0;    unsigned          modulusLen 	= 0;    SECStatus         rv;    int               cipher;    int               keyLen;	/* cipher symkey size in bytes. */    int               ckLen;	/* publicly reveal this many bytes of key. */    int               caLen;	/* length of IV data at *ca.	*/    int               nc;    unsigned char *eblock;	/* holds unencrypted PKCS#1 formatted key. */    SECItem           rek;	/* holds portion of symkey to be encrypted. */    PRUint8           keyData[SSL_MAX_MASTER_KEY_BYTES];    PRUint8           iv     [8];    PORT_Assert( ssl_Have1stHandshakeLock(ss) );    eblock = NULL;    sid = ss->sec.ci.sid;    PORT_Assert(sid != 0);    cert = ss->sec.peerCert;        serverKey = CERT_ExtractPublicKey(cert);    if (!serverKey) {	SSL_DBG(("%d: SSL[%d]: extract public key failed: error=%d",		 SSL_GETPID(), ss->fd, PORT_GetError()));	PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);	rv = SECFailure;	goto loser2;    }    ss->sec.authAlgorithm = ssl_sign_rsa;    ss->sec.keaType       = ssl_kea_rsa;    ss->sec.keaKeyBits    = \    ss->sec.authKeyBits   = SECKEY_PublicKeyStrengthInBits(serverKey);    /* Choose a compatible cipher with the server */    nc = csLen / 3;    cipher = ssl2_ChooseSessionCypher(ss, nc, cs, &keyLen);    if (cipher < 0) {	/* ssl2_ChooseSessionCypher has set error code. */	ssl2_SendErrorMessage(ss, SSL_PE_NO_CYPHERS);	goto loser;    }    /* Generate the random keys */    PK11_GenerateRandom(keyData, sizeof(keyData));    /*    ** Next, carve up the keys into clear and encrypted portions. The    ** clear data is taken from the start of keyData and the encrypted    ** portion from the remainder. Note that each of these portions is    ** carved in half, one half for the read-key and one for the    ** write-key.    */    ca = 0;    /* We know that cipher is a legit value here, because      * ssl2_ChooseSessionCypher doesn't return bogus values.     */    ckLen = ssl_Specs[cipher].pubLen;	/* cleartext key length. */    caLen = ssl_Specs[cipher].ivLen;	/* IV length.		*/    if (caLen) {	PORT_Assert(sizeof iv >= caLen);    	PK11_GenerateRandom(iv, caLen);	ca = iv;    }    /* Fill in session-id */    rv = ssl2_FillInSID(sid, cipher, keyData, keyLen,		   ca, caLen, keyLen << 3, (keyLen - ckLen) << 3,		   ss->sec.authAlgorithm, ss->sec.authKeyBits,		   ss->sec.keaType,       ss->sec.keaKeyBits);    if (rv != SECSuccess) {	goto loser;    }    SSL_TRC(1, ("%d: SSL[%d]: client, using %s cipher, clear=%d total=%d",		SSL_GETPID(), ss->fd, ssl_cipherName[cipher],		ckLen<<3, keyLen<<3));    /* Now setup read and write ciphers */    rv = ssl2_CreateSessionCypher(ss, sid, PR_TRUE);    if (rv != SECSuccess) {	goto loser;    }    /*    ** Fill in the encryption buffer with some random bytes. Then     ** copy in the portion of the session key we are encrypting.    */    modulusLen = SECKEY_PublicKeyStrength(serverKey);    rek.data   = keyData + ckLen;    rek.len    = keyLen  - ckLen;    eblock = ssl_FormatSSL2Block(modulusLen, &rek);    if (eblock == NULL)     	goto loser;    /* Set up the padding for version 2 rollback detection. */    /* XXX We should really use defines here */    if (ss->enableSSL3 || ss->enableTLS) {	PORT_Assert((modulusLen - rek.len) > 12);	PORT_Memset(eblock + modulusLen - rek.len - 8 - 1, 0x03, 8);    }    ekbuf = (PRUint8*) PORT_Alloc(modulusLen);    if (!ekbuf) 	goto loser;    PRINT_BUF(10, (ss, "master key encryption block:",		   eblock, modulusLen));    /* Encrypt ekitem */    rv = PK11_PubEncryptRaw(serverKey, ekbuf, eblock, modulusLen,						ss->pkcs11PinArg);    if (rv)     	goto loser;    /*  Now we have everything ready to send */    rv = ssl2_SendSessionKeyMessage(ss, cipher, keyLen << 3, ca, caLen,			       keyData, ckLen, ekbuf, modulusLen);    if (rv != SECSuccess) {	goto loser;    }    rv = SECSuccess;    goto done;  loser:    rv = SECFailure;  loser2:  done:    PORT_Memset(keyData, 0, sizeof(keyData));    PORT_ZFree(ekbuf, modulusLen);    PORT_ZFree(eblock, modulusLen);    SECKEY_DestroyPublicKey(serverKey);    return rv;}