PORT_Assert( ssl_Have1stHandshakeLock(ss) );
PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
ssl2_HandleMessage(sslSocket *ss){    PRUint8 *        data;    PRUint8 *        cid;    unsigned         len, certType, certLen, responseLen;    int              rv;    int              rv2;    PORT_Assert( ssl_Have1stHandshakeLock(ss) );    ssl_GetRecvBufLock(ss);    data = ss->gs.buf.buf + ss->gs.recordOffset;    if (ss->gs.recordLen < 1) {	goto bad_peer;    }    SSL_TRC(3, ("%d: SSL[%d]: received %d message",		SSL_GETPID(), ss->fd, data[0]));    DUMP_MSG(29, (ss, data, ss->gs.recordLen));    switch (data[0]) {    case SSL_MT_CLIENT_FINISHED:	if (ss->sec.ci.elements & CIS_HAVE_FINISHED) {	    SSL_DBG(("%d: SSL[%d]: dup client-finished message",		     SSL_GETPID(), ss->fd));	    goto bad_peer;	}	/* See if nonce matches */	len = ss->gs.recordLen - 1;	cid = data + 1;	if ((len != sizeof(ss->sec.ci.connectionID)) ||	    (PORT_Memcmp(ss->sec.ci.connectionID, cid, len) != 0)) {	    SSL_DBG(("%d: SSL[%d]: bad connection-id", SSL_GETPID(), ss->fd));	    PRINT_BUF(5, (ss, "sent connection-id",			  ss->sec.ci.connectionID, 			  sizeof(ss->sec.ci.connectionID)));	    PRINT_BUF(5, (ss, "rcvd connection-id", cid, len));	    goto bad_peer;	}	SSL_TRC(5, ("%d: SSL[%d]: got client finished, waiting for 0x%d",		    SSL_GETPID(), ss->fd, 		    ss->sec.ci.requiredElements ^ ss->sec.ci.elements));	ss->sec.ci.elements |= CIS_HAVE_FINISHED;	break;    case SSL_MT_SERVER_FINISHED:	if (ss->sec.ci.elements & CIS_HAVE_FINISHED) {	    SSL_DBG(("%d: SSL[%d]: dup server-finished message",		     SSL_GETPID(), ss->fd));	    goto bad_peer;	}	if (ss->gs.recordLen - 1 != SSL2_SESSIONID_BYTES) {	    SSL_DBG(("%d: SSL[%d]: bad server-finished message, len=%d",		     SSL_GETPID(), ss->fd, ss->gs.recordLen));	    goto bad_peer;	}	ssl2_ClientRegSessionID(ss, data+1);	SSL_TRC(5, ("%d: SSL[%d]: got server finished, waiting for 0x%d",		    SSL_GETPID(), ss->fd, 		    ss->sec.ci.requiredElements ^ ss->sec.ci.elements));	ss->sec.ci.elements |= CIS_HAVE_FINISHED;	break;    case SSL_MT_REQUEST_CERTIFICATE:	len = ss->gs.recordLen - 2;	if ((len < SSL_MIN_CHALLENGE_BYTES) ||	    (len > SSL_MAX_CHALLENGE_BYTES)) {	    /* Bad challenge */	    SSL_DBG(("%d: SSL[%d]: bad cert request message: code len=%d",		     SSL_GETPID(), ss->fd, len));	    goto bad_peer;	}		/* save auth request info */	ss->sec.ci.authType           = data[1];	ss->sec.ci.serverChallengeLen = len;	PORT_Memcpy(ss->sec.ci.serverChallenge, data + 2, len);		rv = ssl2_HandleRequestCertificate(ss);	if (rv == SECWouldBlock) {	    SSL_TRC(3, ("%d: SSL[%d]: async cert request",			SSL_GETPID(), ss->fd));	    /* someone is handling this asynchronously */	    ssl_ReleaseRecvBufLock(ss);	    return SECWouldBlock;	}	if (rv) {	    SET_ERROR_CODE	    goto loser;	}	break;    case SSL_MT_CLIENT_CERTIFICATE:	if (!ss->authCertificate) {	    /* Server asked for authentication and can't handle it */	    PORT_SetError(SSL_ERROR_BAD_SERVER);	    goto loser;	}	if (ss->gs.recordLen < SSL_HL_CLIENT_CERTIFICATE_HBYTES) {	    SET_ERROR_CODE	    goto loser;	}	certType    = data[1];	certLen     = (data[2] << 8) | data[3];	responseLen = (data[4] << 8) | data[5];	if (certType != SSL_CT_X509_CERTIFICATE) {	    PORT_SetError(SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE);	    goto loser;	}	if (certLen + responseLen + SSL_HL_CLIENT_CERTIFICATE_HBYTES 	    > ss->gs.recordLen) {	    /* prevent overflow crash. */	    rv = SECFailure;	} else	rv = ssl2_HandleClientCertificate(ss, data[1],		data + SSL_HL_CLIENT_CERTIFICATE_HBYTES,		certLen,		data + SSL_HL_CLIENT_CERTIFICATE_HBYTES + certLen,		responseLen);	if (rv) {	    rv2 = ssl2_SendErrorMessage(ss, SSL_PE_BAD_CERTIFICATE);	    SET_ERROR_CODE	    goto loser;	}	ss->sec.ci.elements |= CIS_HAVE_CERTIFICATE;	break;    case SSL_MT_ERROR:	rv = (data[1] << 8) | data[2];	SSL_TRC(2, ("%d: SSL[%d]: got error message, error=0x%x",		    SSL_GETPID(), ss->fd, rv));	/* Convert protocol error number into API error number */	switch (rv) {	  case SSL_PE_NO_CYPHERS:	    rv = SSL_ERROR_NO_CYPHER_OVERLAP;	    break;	  case SSL_PE_NO_CERTIFICATE:	    rv = SSL_ERROR_NO_CERTIFICATE;	    break;	  case SSL_PE_BAD_CERTIFICATE:	    rv = SSL_ERROR_BAD_CERTIFICATE;	    break;	  case SSL_PE_UNSUPPORTED_CERTIFICATE_TYPE:	    rv = SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE;	    break;	  default:	    goto bad_peer;	}	/* XXX make certificate-request optionally fail... */	PORT_SetError(rv);	goto loser;    default:	SSL_DBG(("%d: SSL[%d]: unknown message %d",		 SSL_GETPID(), ss->fd, data[0]));	goto loser;    }    SSL_TRC(3, ("%d: SSL[%d]: handled %d message, required=0x%x got=0x%x",		SSL_GETPID(), ss->fd, data[0],		ss->sec.ci.requiredElements, ss->sec.ci.elements));    rv = ssl2_TryToFinish(ss);    if (rv != SECSuccess) 	goto loser;    ss->gs.recordLen = 0;    ssl_ReleaseRecvBufLock(ss);    if (ss->handshake == 0) {	return SECSuccess;    }    ss->handshake     = ssl_GatherRecord1stHandshake;    ss->nextHandshake = ssl2_HandleMessage;    return ssl2_TriggerNextMessage(ss);  bad_peer:    PORT_SetError(ss->sec.isServer ? SSL_ERROR_BAD_CLIENT : SSL_ERROR_BAD_SERVER);    /* FALL THROUGH */  loser:    ssl_ReleaseRecvBufLock(ss);    return SECFailure;}