PORT_Assert( ssl_Have1stHandshakeLock(ss) ); PORT_Assert( ssl_HaveRecvBufLock(ss)   );
PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss)   );
ssl2_ChooseSessionCypher(sslSocket *ss,                          int        hc,    /* number of cs's in hs. */		         PRUint8 *  hs,    /* server hello's cipher suites. */		         int *      pKeyLen) /* out: sym key size in bytes. */{    PRUint8 *       ms;    unsigned int    i;    int             bestKeySize;    int             bestRealKeySize;    int             bestCypher;    int             keySize;    int             realKeySize;    PRUint8 *       ohs               = hs;    PORT_Assert( ssl_Have1stHandshakeLock(ss) );    PORT_Assert( ssl_HaveRecvBufLock(ss)   );    if (!ss->cipherSpecs) {	ssl2_ConstructCipherSpecs(ss);    }    if (!ss->preferredCipher) {	const PRUint8 * preferred = implementedCipherSuites;    	unsigned int    allowed = ss->allowedByPolicy & ss->chosenPreference &	                       SSL_CB_IMPLEMENTED;	if (allowed) {	    for (i = ssl2_NUM_SUITES_IMPLEMENTED; i > 0; --i) {		if (0 != (allowed & (1U << preferred[0]))) {		    ss->preferredCipher = preferred;		    break;		}		preferred += 3;	    }	}    }    /*    ** Scan list of ciphers recieved from peer and look for a match in    ** our list.      *  Note: Our list may contain SSL v3 ciphers.      *  We MUST NOT match on any of those.      *  Fortunately, this is easy to detect because SSLv3 ciphers have zero    *  in the first byte, and none of the SSLv2 ciphers do.    */    bestKeySize = bestRealKeySize = 0;    bestCypher = -1;    while (--hc >= 0) {	for (i = 0, ms = ss->cipherSpecs; i < ss->sizeCipherSpecs; i += 3, ms += 3) {	    if ((hs[0] == ss->preferredCipher[0]) &&		(hs[1] == ss->preferredCipher[1]) &&		(hs[2] == ss->preferredCipher[2]) &&		 hs[0] != 0) {		/* Pick this cipher immediately! */		*pKeyLen = (((hs[1] << 8) | hs[2]) + 7) >> 3;		return hs[0];	    }	    if ((hs[0] == ms[0]) && (hs[1] == ms[1]) && (hs[2] == ms[2]) &&	         hs[0] != 0) {		/* Found a match */		/* Use secret keySize to determine which cipher is best */		realKeySize = (hs[1] << 8) | hs[2];		switch (hs[0]) {		  case SSL_CK_RC4_128_EXPORT40_WITH_MD5:		  case SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5:		    keySize = 40;		    break;		  default:		    keySize = realKeySize;		    break;		}		if (keySize > bestKeySize) {		    bestCypher = hs[0];		    bestKeySize = keySize;		    bestRealKeySize = realKeySize;		}	    }	}	hs += 3;    }    if (bestCypher < 0) {	/*	** No overlap between server and client. Re-examine server list	** to see what kind of ciphers it does support so that we can set	** the error code appropriately.	*/	if ((ohs[0] == SSL_CK_RC4_128_WITH_MD5) ||	    (ohs[0] == SSL_CK_RC2_128_CBC_WITH_MD5)) {	    PORT_SetError(SSL_ERROR_US_ONLY_SERVER);	} else if ((ohs[0] == SSL_CK_RC4_128_EXPORT40_WITH_MD5) ||		   (ohs[0] == SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5)) {	    PORT_SetError(SSL_ERROR_EXPORT_ONLY_SERVER);	} else {	    PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);	}	SSL_DBG(("%d: SSL[%d]: no cipher overlap", SSL_GETPID(), ss->fd));	goto loser;    }    *pKeyLen = (bestRealKeySize + 7) >> 3;    return bestCypher;  loser:    return -1;}