ssl3->hs.kea_def->kea == kea_ecdhe_ecdsa || ssl3->hs.kea_def->kea == kea_ecdhe_rsa ||
ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa || ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa ||
ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length){    ssl3CertNode *   c;    ssl3CertNode *   certs 	= NULL;    PRArenaPool *    arena 	= NULL;    ssl3State *      ssl3  	= ss->ssl3;    CERTCertificate *cert;    PRInt32          remaining  = 0;    PRInt32          size;    SECStatus        rv;    PRBool           isServer	= (PRBool)(!!ss->sec.isServer);    PRBool           trusted 	= PR_FALSE;    PRBool           isTLS;    SSL3AlertDescription desc	= bad_certificate;    int              errCode    = SSL_ERROR_RX_MALFORMED_CERTIFICATE;    SECItem          certItem;    SSL_TRC(3, ("%d: SSL3[%d]: handle certificate handshake",		SSL_GETPID(), ss->fd));    PORT_Assert( ssl_HaveRecvBufLock(ss) );    PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) );    if ((ssl3->hs.ws != wait_server_cert) &&	(ssl3->hs.ws != wait_client_cert)) {	desc    = unexpected_message;	errCode = SSL_ERROR_RX_UNEXPECTED_CERTIFICATE;	goto alert_loser;    }    if (ss->sec.peerCert != NULL) {	if (ss->sec.peerKey) {	    SECKEY_DestroyPublicKey(ss->sec.peerKey);	    ss->sec.peerKey = NULL;	}	CERT_DestroyCertificate(ss->sec.peerCert);	ss->sec.peerCert = NULL;    }    ssl3_CleanupPeerCerts(ssl3);    isTLS = (PRBool)(ssl3->prSpec->version > SSL_LIBRARY_VERSION_3_0);    /* It is reported that some TLS client sends a Certificate message    ** with a zero-length message body.  We'll treat that case like a    ** normal no_certificates message to maximize interoperability.    */    if (length) {	remaining = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length);	if (remaining < 0)	    goto loser;	/* fatal alert already sent by ConsumeHandshake. */	if ((PRUint32)remaining > length)	    goto decode_loser;    }    if (!remaining) {	if (!(isTLS && isServer))	    goto alert_loser;    	/* This is TLS's version of a no_certificate alert. */    	/* I'm a server. I've requested a client cert. He hasn't got one. */	rv = ssl3_HandleNoCertificate(ss);	if (rv != SECSuccess) {	    errCode = PORT_GetError();	    goto loser;	}	goto cert_block;    }    ssl3->peerCertArena = arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);    if ( arena == NULL ) {	goto loser;	/* don't send alerts on memory errors */    }    /* First get the peer cert. */    remaining -= 3;    if (remaining < 0)	goto decode_loser;    size = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length);    if (size <= 0)	goto loser;	/* fatal alert already sent by ConsumeHandshake. */    if (remaining < size)	goto decode_loser;    certItem.data = b;    certItem.len = size;    b      += size;    length -= size;    remaining -= size;    ss->sec.peerCert = CERT_NewTempCertificate(ss->dbHandle, &certItem, NULL,                                            PR_FALSE, PR_TRUE);    if (ss->sec.peerCert == NULL) {	/* We should report an alert if the cert was bad, but not if the	 * problem was just some local problem, like memory error.	 */	goto ambiguous_err;    }    /* Now get all of the CA certs. */    while (remaining > 0) {	remaining -= 3;	if (remaining < 0)	    goto decode_loser;	size = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length);	if (size <= 0)	    goto loser;	/* fatal alert already sent by ConsumeHandshake. */	if (remaining < size)	    goto decode_loser;	certItem.data = b;	certItem.len = size;	b      += size;	length -= size;	remaining -= size;	c = PORT_ArenaNew(arena, ssl3CertNode);	if (c == NULL) {	    goto loser;	/* don't send alerts on memory errors */	}	c->cert = CERT_NewTempCertificate(ss->dbHandle, &certItem, NULL,	                                  PR_FALSE, PR_TRUE);	if (c->cert == NULL) {	    goto ambiguous_err;	}	if (c->cert->trust)	    trusted = PR_TRUE;	c->next = certs;	certs = c;    }    if (remaining != 0)        goto decode_loser;    SECKEY_UpdateCertPQG(ss->sec.peerCert);    /*     * Ask caller-supplied callback function to validate cert chain.     */    rv = (SECStatus)(*ss->authCertificate)(ss->authCertificateArg, ss->fd,					   PR_TRUE, isServer);    if (rv) {	errCode = PORT_GetError();	if (!ss->handleBadCert) {	    goto bad_cert;	}	rv = (SECStatus)(*ss->handleBadCert)(ss->badCertArg, ss->fd);	if ( rv ) {	    if ( rv == SECWouldBlock ) {		/* someone will handle this connection asynchronously*/		SSL_DBG(("%d: SSL3[%d]: go to async cert handler",			 SSL_GETPID(), ss->fd));		ssl3->peerCertChain = certs;		certs               = NULL;		ssl_SetAlwaysBlock(ss);		goto cert_block;	    }	    /* cert is bad */	    goto bad_cert;	}	/* cert is good */    }    /* start SSL Step Up, if appropriate */    cert = ss->sec.peerCert;    if (!isServer &&    	ssl3_global_policy_some_restricted &&        ssl3->policy == SSL_ALLOWED &&	anyRestrictedEnabled(ss) &&	SECSuccess == CERT_VerifyCertNow(cert->dbhandle, cert,	                                 PR_FALSE, /* checkSig */				         certUsageSSLServerWithStepUp,/*XXX*/				         ss->authCertificateArg) ) {	ssl3->policy         = SSL_RESTRICTED;	ssl3->hs.rehandshake = PR_TRUE;    }    ss->sec.ci.sid->peerCert = CERT_DupCertificate(ss->sec.peerCert);    if (!ss->sec.isServer) {	/* set the server authentication and key exchange types and sizes	** from the value in the cert.  If the key exchange key is different,	** it will get fixed when we handle the server key exchange message.	*/	SECKEYPublicKey * pubKey  = CERT_ExtractPublicKey(cert);	ss->sec.authAlgorithm = ssl3->hs.kea_def->signKeyType;	ss->sec.keaType       = ssl3->hs.kea_def->exchKeyType;	if (pubKey) {	    ss->sec.keaKeyBits = ss->sec.authKeyBits =		SECKEY_PublicKeyStrengthInBits(pubKey);#ifdef NSS_ENABLE_ECC	    if (ss->sec.keaType == kt_ecdh) {		/* Get authKeyBits from signing key.		 * XXX The code below uses a quick approximation of		 * key size based on cert->signatureWrap.signature.data		 * (which contains the DER encoded signature). The field		 * cert->signatureWrap.signature.len contains the		 * length of the encoded signature in bits.		 */		if (ss->ssl3->hs.kea_def->kea == kea_ecdh_ecdsa) {		    ss->sec.authKeyBits = 			cert->signatureWrap.signature.data[3]*8;		    if (cert->signatureWrap.signature.data[4] == 0x00)			    ss->sec.authKeyBits -= 8;		    /* 		     * XXX: if cert is not signed by ecdsa we should		     * destroy pubKey and goto bad_cert		     */		} else if (ss->ssl3->hs.kea_def->kea == kea_ecdh_rsa) {		    ss->sec.authKeyBits = cert->signatureWrap.signature.len;		    /* 		     * XXX: if cert is not signed by rsa we should		     * destroy pubKey and goto bad_cert		     */		}	    }#endif /* NSS_ENABLE_ECC */	    SECKEY_DestroyPublicKey(pubKey); 	    pubKey = NULL;    	}    }    ssl3->peerCertChain = certs;  certs = NULL;  arena = NULL;cert_block:    if (ss->sec.isServer) {	ssl3->hs.ws = wait_client_key;    } else {	ssl3->hs.ws = wait_cert_request; /* disallow server_key_exchange */	if (ssl3->hs.kea_def->is_limited ||	    /* XXX OR server cert is signing only. */#ifdef NSS_ENABLE_ECC	    ssl3->hs.kea_def->kea == kea_ecdhe_ecdsa ||	    ssl3->hs.kea_def->kea == kea_ecdhe_rsa ||#endif /* NSS_ENABLE_ECC */	    ssl3->hs.kea_def->exchKeyType == kt_dh) {	    ssl3->hs.ws = wait_server_key; /* allow server_key_exchange */	}    }    /* rv must normally be equal to SECSuccess here.  If we called     * handleBadCert, it can also be SECWouldBlock.     */    return rv;ambiguous_err:    errCode = PORT_GetError();    switch (errCode) {    case PR_OUT_OF_MEMORY_ERROR:    case SEC_ERROR_BAD_DATABASE:    case SEC_ERROR_NO_MEMORY:	if (isTLS) {	    desc = internal_error;	    goto alert_loser;	}	goto loser;    }    /* fall through to bad_cert. */bad_cert:	/* caller has set errCode. */    switch (errCode) {    case SEC_ERROR_LIBRARY_FAILURE:     desc = unsupported_certificate; break;    case SEC_ERROR_EXPIRED_CERTIFICATE: desc = certificate_expired;     break;    case SEC_ERROR_REVOKED_CERTIFICATE: desc = certificate_revoked;     break;    case SEC_ERROR_INADEQUATE_KEY_USAGE:    case SEC_ERROR_INADEQUATE_CERT_TYPE:		                        desc = certificate_unknown;     break;    case SEC_ERROR_UNTRUSTED_CERT:		    desc = isTLS ? access_denied : certificate_unknown; break;    case SEC_ERROR_UNKNOWN_ISSUER:          case SEC_ERROR_UNTRUSTED_ISSUER:    		    desc = isTLS ? unknown_ca : certificate_unknown; break;    case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:		    desc = isTLS ? unknown_ca : certificate_expired; break;    case SEC_ERROR_CERT_NOT_IN_NAME_SPACE:    case SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID:    case SEC_ERROR_CA_CERT_INVALID:    case SEC_ERROR_BAD_SIGNATURE:    default:                            desc = bad_certificate;     break;    }    SSL_DBG(("%d: SSL3[%d]: peer certificate is no good: error=%d",	     SSL_GETPID(), ss->fd, errCode));    goto alert_loser;decode_loser:    desc = isTLS ? decode_error : bad_certificate;alert_loser:    (void)SSL3_SendAlert(ss, alert_fatal, desc);loser:    ssl3->peerCertChain = certs;  certs = NULL;  arena = NULL;    ssl3_CleanupPeerCerts(ssl3);    if (ss->sec.peerCert != NULL) {	CERT_DestroyCertificate(ss->sec.peerCert);	ss->sec.peerCert = NULL;    }    (void)ssl_MapLowLevelError(errCode);    return SECFailure;}