PORT_Free(suites.data);
ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length){    sslSessionID *      sid      = NULL;    ssl3State *         ssl3;    PRInt32		tmp;    unsigned int        i;    int                 j;    SECStatus           rv;    int                 errCode  = SSL_ERROR_RX_MALFORMED_CLIENT_HELLO;    SSL3AlertDescription desc    = illegal_parameter;    SSL3ProtocolVersion version;    SECItem             sidBytes = {siBuffer, NULL, 0};    SECItem             suites   = {siBuffer, NULL, 0};    SECItem             comps    = {siBuffer, NULL, 0};    PRBool              haveSpecWriteLock = PR_FALSE;    PRBool              haveXmitBufLock   = PR_FALSE;    SSL_TRC(3, ("%d: SSL3[%d]: handle client_hello handshake",    	SSL_GETPID(), ss->fd));    PORT_Assert( ssl_HaveRecvBufLock(ss) );    PORT_Assert( ssl_HaveSSL3HandshakeLock(ss));    /* Get peer name of client */    rv = ssl_GetPeerInfo(ss);    if (rv != SECSuccess) {	return rv;		/* error code is set. */    }    rv = ssl3_InitState(ss);    if (rv != SECSuccess) {	return rv;		/* ssl3_InitState has set the error code. */    }    ssl3 = ss->ssl3;    if ((ssl3->hs.ws != wait_client_hello) &&	(ssl3->hs.ws != idle_handshake)) {	desc    = unexpected_message;	errCode = SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO;	goto alert_loser;    }    tmp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);    if (tmp < 0)	goto loser;		/* malformed, alert already sent */    ss->clientHelloVersion = version = (SSL3ProtocolVersion)tmp;    rv = ssl3_NegotiateVersion(ss, version);    if (rv != SECSuccess) {    	desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version : handshake_failure;	errCode = SSL_ERROR_NO_CYPHER_OVERLAP;	goto alert_loser;    }    /* grab the client random data. */    rv = ssl3_ConsumeHandshake(	ss, &ssl3->hs.client_random, SSL3_RANDOM_LENGTH, &b, &length);    if (rv != SECSuccess) {	goto loser;		/* malformed */    }    /* grab the client's SID, if present. */    rv = ssl3_ConsumeHandshakeVariable(ss, &sidBytes, 1, &b, &length);    if (rv != SECSuccess) {	goto loser;		/* malformed */    }    if (sidBytes.len > 0 && !ss->noCache) {	SSL_TRC(7, ("%d: SSL3[%d]: server, lookup client session-id for 0x%08x%08x%08x%08x",                    SSL_GETPID(), ss->fd, ss->sec.ci.peer.pr_s6_addr32[0],		    ss->sec.ci.peer.pr_s6_addr32[1], 		    ss->sec.ci.peer.pr_s6_addr32[2],		    ss->sec.ci.peer.pr_s6_addr32[3]));	if (ssl_sid_lookup) {	    sid = (*ssl_sid_lookup)(&ss->sec.ci.peer, sidBytes.data, 	                            sidBytes.len, ss->dbHandle);    	} else {	    errCode = SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED;	    goto loser;	}    }    SECITEM_FreeItem(&sidBytes, PR_FALSE);    /* grab the list of cipher suites. */    rv = ssl3_ConsumeHandshakeVariable(ss, &suites, 2, &b, &length);    if (rv != SECSuccess) {	goto loser;		/* malformed */    }    /* grab the list of compression methods. */    rv = ssl3_ConsumeHandshakeVariable(ss, &comps, 1, &b, &length);    if (rv != SECSuccess) {	goto loser;		/* malformed */    }    /* It's OK for length to be non-zero here.     * Non-zero length means that some new protocol revision has extended     * the client hello message.     */    desc = handshake_failure;    if (sid != NULL) {	/* We've found a session cache entry for this client.	 * Now, if we're going to require a client-auth cert,	 * and we don't already have this client's cert in the session cache,	 * and this is the first handshake on this connection (not a redo),	 * then drop this old cache entry and start a new session.	 */	if ((sid->peerCert == NULL) && ss->requestCertificate &&	    ((ss->requireCertificate == SSL_REQUIRE_ALWAYS) ||	     (ss->requireCertificate == SSL_REQUIRE_NO_ERROR) ||	     ((ss->requireCertificate == SSL_REQUIRE_FIRST_HANDSHAKE) 	      && !ss->firstHsDone))) {	    ++ssl3stats.hch_sid_cache_not_ok;	    ss->sec.uncache(sid);	    ssl_FreeSID(sid);	    sid = NULL;	}    }    /* Look for a matching cipher suite. */    j = ssl3_config_match_init(ss);    if (j <= 0) {		/* no ciphers are working/supported by PK11 */    	errCode = PORT_GetError();	/* error code is already set. */	goto alert_loser;    }    /* If we already have a session for this client, be sure to pick the    ** same cipher suite we picked before.    ** This is not a loop, despite appearances.    */    if (sid) do {	ssl3CipherSuiteCfg *suite = ss->cipherSuites;	for (j = ssl_V3_SUITES_IMPLEMENTED; j > 0; --j, ++suite) {	    if (suite->cipher_suite == sid->u.ssl3.cipherSuite)		break;	}	if (!j)	    break;	if (!config_match(suite, ssl3->policy, PR_TRUE))	    break;	for (i = 0; i < suites.len; i += 2) {	    if ((suites.data[i]     == MSB(suite->cipher_suite)) &&	        (suites.data[i + 1] == LSB(suite->cipher_suite))) {		ssl3->hs.cipher_suite = suite->cipher_suite;		ssl3->hs.suite_def =		    ssl_LookupCipherSuiteDef(ssl3->hs.cipher_suite);		goto suite_found;	    }	}    } while (0);    /* Select a cipher suite.    ** NOTE: This suite selection algorithm should be the same as the one in    ** ssl3_HandleV2ClientHello().      */    for (j = 0; j < ssl_V3_SUITES_IMPLEMENTED; j++) {	ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j];	if (!config_match(suite, ssl3->policy, PR_TRUE))	    continue;	for (i = 0; i < suites.len; i += 2) {	    if ((suites.data[i]     == MSB(suite->cipher_suite)) &&	        (suites.data[i + 1] == LSB(suite->cipher_suite))) {		ssl3->hs.cipher_suite = suite->cipher_suite;		ssl3->hs.suite_def =		    ssl_LookupCipherSuiteDef(ssl3->hs.cipher_suite);		goto suite_found;	    }	}    }    errCode = SSL_ERROR_NO_CYPHER_OVERLAP;    goto alert_loser;suite_found:    /* Look for a matching compression algorithm. */    for (i = 0; i < comps.len; i++) {	for (j = 0; j < compressionMethodsCount; j++) {	    if (comps.data[i] == compressions[j]) {		ssl3->hs.compression = (SSL3CompressionMethod)compressions[j];		goto compression_found;	    }	}    }    errCode = SSL_ERROR_NO_COMPRESSION_OVERLAP;    				/* null compression must be supported */    goto alert_loser;compression_found:    PORT_Free(suites.data);    suites.data = NULL;    PORT_Free(comps.data);    comps.data = NULL;    ss->sec.send = ssl3_SendApplicationData;    /* If there are any failures while processing the old sid,     * we don't consider them to be errors.  Instead, We just behave     * as if the client had sent us no sid to begin with, and make a new one.     */    if (sid != NULL) do {	PK11SymKey *    wrapKey; 	/* wrapping key */	SECItem         wrappedKey;  	/* wrapped key */	ssl3CipherSpec *pwSpec;	CK_FLAGS        keyFlags      = 0;	if (sid->version != ss->version  ||	    sid->u.ssl3.cipherSuite != ssl3->hs.cipher_suite) {	    break;	/* not an error */	}	if (ss->sec.ci.sid) {	    ss->sec.uncache(ss->sec.ci.sid);	    PORT_Assert(ss->sec.ci.sid != sid);  /* should be impossible, but ... */	    if (ss->sec.ci.sid != sid) {		ssl_FreeSID(ss->sec.ci.sid);	    }	    ss->sec.ci.sid = NULL;	}	/* we need to resurrect the master secret.... */	ssl_GetSpecWriteLock(ss);  haveSpecWriteLock = PR_TRUE;	pwSpec = ssl3->pwSpec;	wrapKey = getWrappingKey(ss, NULL, sid->u.ssl3.exchKeyType,	                         sid->u.ssl3.masterWrapMech, ss->pkcs11PinArg);	if (!wrapKey) {	    /* we have a SID cache entry, but no wrapping key for it??? */	    break;	}	if (ss->version > SSL_LIBRARY_VERSION_3_0) {	/* isTLS */	    keyFlags = CKF_SIGN | CKF_VERIFY;	}        wrappedKey.data = sid->u.ssl3.keys.wrapped_master_secret;	wrappedKey.len  = sid->u.ssl3.keys.wrapped_master_secret_len;	/* unwrap the master secret. */	pwSpec->master_secret =	    PK11_UnwrapSymKeyWithFlags(wrapKey, sid->u.ssl3.masterWrapMech, 	    		NULL, &wrappedKey, CKM_SSL3_MASTER_KEY_DERIVE,			CKA_DERIVE, sizeof(SSL3MasterSecret), keyFlags);	PK11_FreeSymKey(wrapKey);	if (pwSpec->master_secret == NULL) {	    break;	/* not an error */	}	ss->sec.ci.sid = sid;	if (sid->peerCert != NULL) {	    ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);	}	/*	 * Old SID passed all tests, so resume this old session.	 *	 * XXX make sure compression still matches	 */	++ssl3stats.hch_sid_cache_hits;	ssl3->hs.isResuming = PR_TRUE;        ss->sec.authAlgorithm = sid->authAlgorithm;	ss->sec.authKeyBits   = sid->authKeyBits;	ss->sec.keaType       = sid->keaType;	ss->sec.keaKeyBits    = sid->keaKeyBits;	/* server sids don't remember the server cert we previously sent,	** but they do remember the kea type we originally used, so we	** can locate it again, provided that the current ssl socket	** has had its server certs configured the same as the previous one.	*/	ss->sec.localCert     = 		CERT_DupCertificate(ss->serverCerts[sid->keaType].serverCert);	ssl_GetXmitBufLock(ss); haveXmitBufLock = PR_TRUE;	rv = ssl3_SendServerHello(ss);	if (rv != SECSuccess) {	    errCode = PORT_GetError();	    goto loser;	}	if (haveSpecWriteLock) {	    ssl_ReleaseSpecWriteLock(ss);	    haveSpecWriteLock = PR_FALSE;	}	/* NULL value for PMS signifies re-use of the old MS */	rv = ssl3_InitPendingCipherSpec(ss,  NULL);	if (rv != SECSuccess) {	    errCode = PORT_GetError();	    goto loser;	}	rv = ssl3_SendChangeCipherSpecs(ss);	if (rv != SECSuccess) {	    errCode = PORT_GetError();	    goto loser;	}	rv = ssl3_SendFinished(ss, 0);	ssl3->hs.ws = wait_change_cipher;	if (rv != SECSuccess) {	    errCode = PORT_GetError();	    goto loser;	}	if (haveXmitBufLock) {	    ssl_ReleaseXmitBufLock(ss);	    haveXmitBufLock = PR_FALSE;	}        return SECSuccess;    } while (0);    if (haveSpecWriteLock) {	ssl_ReleaseSpecWriteLock(ss);	haveSpecWriteLock = PR_FALSE;    }    if (sid) { 	/* we had a sid, but it's no longer valid, free it */	++ssl3stats.hch_sid_cache_not_ok;	ss->sec.uncache(sid);	ssl_FreeSID(sid);	sid = NULL;    }    ++ssl3stats.hch_sid_cache_misses;    sid = ssl3_NewSessionID(ss, PR_TRUE);    if (sid == NULL) {	errCode = PORT_GetError();	goto loser;	/* memory error is set. */    }    ss->sec.ci.sid = sid;    ssl3->hs.isResuming = PR_FALSE;    ssl_GetXmitBufLock(ss);    rv = ssl3_SendServerHelloSequence(ss);    ssl_ReleaseXmitBufLock(ss);    if (rv != SECSuccess) {	errCode = PORT_GetError();	goto loser;    }    if (haveXmitBufLock) {	ssl_ReleaseXmitBufLock(ss);	haveXmitBufLock = PR_FALSE;    }    return SECSuccess;alert_loser:    if (haveSpecWriteLock) {	ssl_ReleaseSpecWriteLock(ss);	haveSpecWriteLock = PR_FALSE;    }    (void)SSL3_SendAlert(ss, alert_fatal, desc);    /* FALLTHRU */loser:    if (haveSpecWriteLock) {	ssl_ReleaseSpecWriteLock(ss);	haveSpecWriteLock = PR_FALSE;    }    if (sidBytes.data != NULL) SECITEM_FreeItem(&sidBytes, PR_FALSE);    if (suites.data   != NULL) SECITEM_FreeItem(&suites,   PR_FALSE);    if (comps.data    != NULL) SECITEM_FreeItem(&comps,    PR_FALSE);    if (haveXmitBufLock) {	ssl_ReleaseXmitBufLock(ss);	haveXmitBufLock = PR_FALSE;    }    PORT_SetError(errCode);    return SECFailure;}