PORT_Assert( ssl_Have1stHandshakeLock(ss) );  if (!ss->enableSSL2) {
PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );  if (!ss->opt.enableSSL2) {
ssl2_HandleServerHelloMessage(sslSocket *ss){    sslSessionID *   sid;    PRUint8 *        cert;    PRUint8 *        cs;    PRUint8 *        data;    SECStatus        rv;     int              needed, sidHit, certLen, csLen, cidLen, certType, err;    PORT_Assert( ssl_Have1stHandshakeLock(ss) );    if (!ss->enableSSL2) {	PORT_SetError(SSL_ERROR_SSL2_DISABLED);	return SECFailure;    }    ssl_GetRecvBufLock(ss);    PORT_Assert(ss->sec.ci.sid != 0);    sid = ss->sec.ci.sid;    data = ss->gs.buf.buf + ss->gs.recordOffset;    DUMP_MSG(29, (ss, data, ss->gs.recordLen));    /* Make sure first message has some data and is the server hello message */    if ((ss->gs.recordLen < SSL_HL_SERVER_HELLO_HBYTES)	|| (data[0] != SSL_MT_SERVER_HELLO)) {	if ((data[0] == SSL_MT_ERROR) && (ss->gs.recordLen == 3)) {	    err = (data[1] << 8) | data[2];	    if (err == SSL_PE_NO_CYPHERS) {		PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);		goto loser;	    }	}	goto bad_server;    }    sidHit      = data[1];    certType    = data[2];    ss->version = (data[3] << 8) | data[4];    certLen     = (data[5] << 8) | data[6];    csLen       = (data[7] << 8) | data[8];    cidLen      = (data[9] << 8) | data[10];    cert        = data + SSL_HL_SERVER_HELLO_HBYTES;    cs          = cert + certLen;    SSL_TRC(5,	    ("%d: SSL[%d]: server-hello, hit=%d vers=%x certLen=%d csLen=%d cidLen=%d",	     SSL_GETPID(), ss->fd, sidHit, ss->version, certLen,	     csLen, cidLen));    if (ss->version != SSL_LIBRARY_VERSION_2) {        if (ss->version < SSL_LIBRARY_VERSION_2) {	  SSL_TRC(3, ("%d: SSL[%d]: demoting self (%x) to server version (%x)",		      SSL_GETPID(), ss->fd, SSL_LIBRARY_VERSION_2,		      ss->version));	} else {	  SSL_TRC(1, ("%d: SSL[%d]: server version is %x (we are %x)",		    SSL_GETPID(), ss->fd, ss->version, SSL_LIBRARY_VERSION_2));	  /* server claims to be newer but does not follow protocol */	  PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION);	  goto loser;	}    }    if ((SSL_HL_SERVER_HELLO_HBYTES + certLen + csLen + cidLen                                                   > ss->gs.recordLen)	|| (csLen % 3) != 0   	/* || cidLen < SSL_CONNECTIONID_BYTES || cidLen > 32  */	) {	goto bad_server;    }    /* Save connection-id.    ** This code only saves the first 16 byte of the connectionID.    ** If the connectionID is shorter than 16 bytes, it is zero-padded.    */    if (cidLen < sizeof ss->sec.ci.connectionID)	memset(ss->sec.ci.connectionID, 0, sizeof ss->sec.ci.connectionID);    cidLen = PR_MIN(cidLen, sizeof ss->sec.ci.connectionID);    PORT_Memcpy(ss->sec.ci.connectionID, cs + csLen, cidLen);    /* See if session-id hit */    needed = CIS_HAVE_MASTER_KEY | CIS_HAVE_FINISHED | CIS_HAVE_VERIFY;    if (sidHit) {	if (certLen || csLen) {	    /* Uh oh - bogus server */	    SSL_DBG(("%d: SSL[%d]: client, huh? hit=%d certLen=%d csLen=%d",		     SSL_GETPID(), ss->fd, sidHit, certLen, csLen));	    goto bad_server;	}	/* Total winner. */	SSL_TRC(1, ("%d: SSL[%d]: client, using nonce for peer=0x%08x "		    "port=0x%04x",		    SSL_GETPID(), ss->fd, ss->sec.ci.peer, ss->sec.ci.port));	ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);        ss->sec.authAlgorithm = sid->authAlgorithm;	ss->sec.authKeyBits   = sid->authKeyBits;	ss->sec.keaType       = sid->keaType;	ss->sec.keaKeyBits    = sid->keaKeyBits;	rv = ssl2_CreateSessionCypher(ss, sid, PR_TRUE);	if (rv != SECSuccess) {	    goto loser;	}    } else {	if (certType != SSL_CT_X509_CERTIFICATE) {	    PORT_SetError(SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE);	    goto loser;	}	if (csLen == 0) {	    PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);	    SSL_DBG(("%d: SSL[%d]: no cipher overlap",		     SSL_GETPID(), ss->fd));	    goto loser;	}	if (certLen == 0) {	    SSL_DBG(("%d: SSL[%d]: client, huh? certLen=%d csLen=%d",		     SSL_GETPID(), ss->fd, certLen, csLen));	    goto bad_server;	}	if (sid->cached != never_cached) {	    /* Forget our session-id - server didn't like it */	    SSL_TRC(7, ("%d: SSL[%d]: server forgot me, uncaching session-id",			SSL_GETPID(), ss->fd));	    (*ss->sec.uncache)(sid);	    ssl_FreeSID(sid);	    ss->sec.ci.sid = sid = (sslSessionID*) PORT_ZAlloc(sizeof(sslSessionID));	    if (!sid) {		goto loser;	    }	    sid->references = 1;	    sid->addr = ss->sec.ci.peer;	    sid->port = ss->sec.ci.port;	}	/* decode the server's certificate */	rv = ssl2_ClientHandleServerCert(ss, cert, certLen);	if (rv != SECSuccess) {	    if (PORT_GetError() == SSL_ERROR_BAD_CERTIFICATE) {		(void) ssl2_SendErrorMessage(ss, SSL_PE_BAD_CERTIFICATE);	    }	    goto loser;	}	/* Setup new session cipher */	rv = ssl2_ClientSetupSessionCypher(ss, cs, csLen);	if (rv != SECSuccess) {	    if (PORT_GetError() == SSL_ERROR_BAD_CERTIFICATE) {		(void) ssl2_SendErrorMessage(ss, SSL_PE_BAD_CERTIFICATE);	    }	    goto loser;	}    }    /* Build up final list of required elements */    ss->sec.ci.elements         = CIS_HAVE_MASTER_KEY;    ss->sec.ci.requiredElements = needed;  if (!sidHit) {    /* verify the server's certificate. if sidHit, don't check signatures */    rv = (* ss->authCertificate)(ss->authCertificateArg, ss->fd, 				 (PRBool)(!sidHit), PR_FALSE);    if (rv) {	if (ss->handleBadCert) {	    rv = (*ss->handleBadCert)(ss->badCertArg, ss->fd);	    if ( rv ) {		if ( rv == SECWouldBlock ) {		    /* someone will handle this connection asynchronously*/		    SSL_DBG(("%d: SSL[%d]: go to async cert handler",			     SSL_GETPID(), ss->fd));		    ssl_ReleaseRecvBufLock(ss);		    ssl_SetAlwaysBlock(ss);		    return SECWouldBlock;		}		/* cert is bad */		SSL_DBG(("%d: SSL[%d]: server certificate is no good: error=%d",			 SSL_GETPID(), ss->fd, PORT_GetError()));		goto loser;	    }	    /* cert is good */	} else {	    SSL_DBG(("%d: SSL[%d]: server certificate is no good: error=%d",		     SSL_GETPID(), ss->fd, PORT_GetError()));	    goto loser;	}    }  }    /*    ** At this point we have a completed session key and our session    ** cipher is setup and ready to go. Switch to encrypted write routine    ** as all future message data is to be encrypted.    */    ssl2_UseEncryptedSendFunc(ss);    rv = ssl2_TryToFinish(ss);    if (rv != SECSuccess) 	goto loser;    ss->gs.recordLen = 0;    ssl_ReleaseRecvBufLock(ss);    if (ss->handshake == 0) {	return SECSuccess;    }    SSL_TRC(5, ("%d: SSL[%d]: got server-hello, required=0x%d got=0x%x",		SSL_GETPID(), ss->fd, ss->sec.ci.requiredElements, 		ss->sec.ci.elements));    ss->handshake     = ssl_GatherRecord1stHandshake;    ss->nextHandshake = ssl2_HandleVerifyMessage;    return SECSuccess;  bad_server:    PORT_SetError(SSL_ERROR_BAD_SERVER);    /* FALL THROUGH */  loser:    ssl_ReleaseRecvBufLock(ss);    return SECFailure;}