diff -pu a/nss/lib/ssl/ssl3con.c b/nss/lib/ssl/ssl3con.c --- a/nss/lib/ssl/ssl3con.c 2013-07-31 12:44:31.987362835 -0700 +++ b/nss/lib/ssl/ssl3con.c 2013-07-31 12:44:50.987642452 -0700 @@ -6756,6 +6756,85 @@ done: return rv; } +/* + * attempt to restart the handshake after asynchronously handling + * a request for the client's certificate. + * + * inputs: + * cert Client cert chosen by application. + * Note: ssl takes this reference, and does not bump the + * reference count. The caller should drop its reference + * without calling CERT_DestroyCert after calling this function. + * + * key Private key associated with cert. This function takes + * ownership of the private key, so the caller should drop its + * reference without destroying the private key after this + * function returns. + * + * certChain DER-encoded certs, client cert and its signers. + * Note: ssl takes this reference, and does not copy the chain. + * The caller should drop its reference without destroying the + * chain. SSL will free the chain when it is done with it. + * + * Return value: XXX + * + * XXX This code only works on the initial handshake on a connection, XXX + * It does not work on a subsequent handshake (redo). + * + * Caller holds 1stHandshakeLock. + */ +SECStatus +ssl3_RestartHandshakeAfterCertReq(sslSocket * ss, + CERTCertificate * cert, + SECKEYPrivateKey * key, + CERTCertificateList *certChain) +{ + SECStatus rv = SECSuccess; + + /* XXX This code only works on the initial handshake on a connection, + ** XXX It does not work on a subsequent handshake (redo). + */ + if (ss->handshake != 0) { + ss->handshake = ssl_GatherRecord1stHandshake; + ss->ssl3.clientCertificate = cert; + ss->ssl3.clientPrivateKey = key; + ss->ssl3.clientCertChain = certChain; + if (!cert || !key || !certChain) { + /* we are missing the key, cert, or cert chain */ + if (ss->ssl3.clientCertificate) { + CERT_DestroyCertificate(ss->ssl3.clientCertificate); + ss->ssl3.clientCertificate = NULL; + } + if (ss->ssl3.clientPrivateKey) { + SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); + ss->ssl3.clientPrivateKey = NULL; + } + if (ss->ssl3.clientCertChain != NULL) { + CERT_DestroyCertificateList(ss->ssl3.clientCertChain); + ss->ssl3.clientCertChain = NULL; + } + if (ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0) { + ss->ssl3.sendEmptyCert = PR_TRUE; + } else { + (void)SSL3_SendAlert(ss, alert_warning, no_certificate); + } + } + } else { + if (cert) { + CERT_DestroyCertificate(cert); + } + if (key) { + SECKEY_DestroyPrivateKey(key); + } + if (certChain) { + CERT_DestroyCertificateList(certChain); + } + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + rv = SECFailure; + } + return rv; +} + PRBool ssl3_CanFalseStart(sslSocket *ss) { PRBool rv; diff -pu a/nss/lib/ssl/ssl.h b/nss/lib/ssl/ssl.h --- a/nss/lib/ssl/ssl.h 2013-07-31 12:44:31.987362835 -0700 +++ b/nss/lib/ssl/ssl.h 2013-07-31 12:44:50.987642452 -0700 @@ -366,6 +366,11 @@ SSL_IMPORT SECStatus SSL_ForceHandshake( SSL_IMPORT SECStatus SSL_ForceHandshakeWithTimeout(PRFileDesc *fd, PRIntervalTime timeout); +SSL_IMPORT SECStatus SSL_RestartHandshakeAfterCertReq(PRFileDesc *fd, + CERTCertificate *cert, + SECKEYPrivateKey *key, + CERTCertificateList *certChain); + /* ** Query security status of socket. *on is set to one if security is ** enabled. *keySize will contain the stream key size used. *issuer will diff -pu a/nss/lib/ssl/sslimpl.h b/nss/lib/ssl/sslimpl.h --- a/nss/lib/ssl/sslimpl.h 2013-07-31 12:44:31.997362988 -0700 +++ b/nss/lib/ssl/sslimpl.h 2013-07-31 12:44:50.987642452 -0700 @@ -1513,16 +1513,17 @@ extern SECStatus ssl3_MasterKeyDeriveBy /* These functions are called from secnav, even though they're "private". */ extern int ssl2_SendErrorMessage(struct sslSocketStr *ss, int error); -extern int SSL_RestartHandshakeAfterCertReq(struct sslSocketStr *ss, - CERTCertificate *cert, - SECKEYPrivateKey *key, - CERTCertificateList *certChain); extern sslSocket *ssl_FindSocket(PRFileDesc *fd); extern void ssl_FreeSocket(struct sslSocketStr *ssl); extern SECStatus SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc); extern SECStatus ssl3_DecodeError(sslSocket *ss); +extern SECStatus ssl3_RestartHandshakeAfterCertReq(sslSocket * ss, + CERTCertificate * cert, + SECKEYPrivateKey * key, + CERTCertificateList *certChain); + extern SECStatus ssl3_AuthCertificateComplete(sslSocket *ss, PRErrorCode error); /* diff -pu a/nss/lib/ssl/sslsecur.c b/nss/lib/ssl/sslsecur.c --- a/nss/lib/ssl/sslsecur.c 2013-07-31 12:28:39.283413269 -0700 +++ b/nss/lib/ssl/sslsecur.c 2013-07-31 12:44:50.987642452 -0700 @@ -1436,17 +1436,70 @@ SSL_CertDBHandleSet(PRFileDesc *fd, CERT return SECSuccess; } -/* DO NOT USE. This function was exported in ssl.def with the wrong signature; - * this implementation exists to maintain link-time compatibility. +/* + * attempt to restart the handshake after asynchronously handling + * a request for the client's certificate. + * + * inputs: + * cert Client cert chosen by application. + * Note: ssl takes this reference, and does not bump the + * reference count. The caller should drop its reference + * without calling CERT_DestroyCertificate after calling this + * function. + * + * key Private key associated with cert. This function takes + * ownership of the private key, so the caller should drop its + * reference without destroying the private key after this + * function returns. + * + * certChain Chain of signers for cert. + * Note: ssl takes this reference, and does not copy the chain. + * The caller should drop its reference without destroying the + * chain. SSL will free the chain when it is done with it. + * + * Return value: XXX + * + * XXX This code only works on the initial handshake on a connection, XXX + * It does not work on a subsequent handshake (redo). */ -int -SSL_RestartHandshakeAfterCertReq(sslSocket * ss, +SECStatus +SSL_RestartHandshakeAfterCertReq(PRFileDesc * fd, CERTCertificate * cert, SECKEYPrivateKey * key, CERTCertificateList *certChain) { - PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); - return -1; + sslSocket * ss = ssl_FindSocket(fd); + SECStatus ret; + + if (!ss) { + SSL_DBG(("%d: SSL[%d]: bad socket in SSL_RestartHandshakeAfterCertReq", + SSL_GETPID(), fd)); + if (cert) { + CERT_DestroyCertificate(cert); + } + if (key) { + SECKEY_DestroyPrivateKey(key); + } + if (certChain) { + CERT_DestroyCertificateList(certChain); + } + return SECFailure; + } + + ssl_Get1stHandshakeLock(ss); /************************************/ + + if (ss->version >= SSL_LIBRARY_VERSION_3_0) { + ret = ssl3_RestartHandshakeAfterCertReq(ss, cert, key, certChain); + } else { + if (certChain != NULL) { + CERT_DestroyCertificateList(certChain); + } + PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2); + ret = SECFailure; + } + + ssl_Release1stHandshakeLock(ss); /************************************/ + return ret; } /* DO NOT USE. This function was exported in ssl.def with the wrong signature;