Bug 698552: Add SSL_RestartAfterAuthCertificate to mozilla-central's copy of NSS_3_13_2_BETA1, r=kaie, r=honzab

This commit is contained in:
Brian Smith 2011-12-01 14:33:37 -08:00
parent 903bd33ecb
commit 9585597fca
13 changed files with 1869 additions and 217 deletions

View File

@ -217,6 +217,8 @@ static void Usage(const char *progName)
fprintf(stderr, "%-20s Disable TLS (SSL v3.1).\n", "-T");
fprintf(stderr, "%-20s Prints only payload data. Skips HTTP header.\n", "-S");
fprintf(stderr, "%-20s Client speaks first. \n", "-f");
fprintf(stderr, "%-20s Use synchronous certificate validation "
"(required for SSL2)\n", "-O");
fprintf(stderr, "%-20s Override bad server cert. Make it OK.\n", "-o");
fprintf(stderr, "%-20s Disable SSL socket locking.\n", "-s");
fprintf(stderr, "%-20s Verbose progress reporting.\n", "-v");
@ -293,6 +295,16 @@ disableAllSSLCiphers(void)
}
}
typedef struct
{
PRBool shouldPause; /* PR_TRUE if we should use asynchronous peer cert
* authentication */
PRBool isPaused; /* PR_TRUE if libssl is waiting for us to validate the
* peer's certificate and restart the handshake. */
void * dbHandle; /* Certificate database handle to use while
* authenticating the peer's certificate. */
} ServerCertAuth;
/*
* Callback is called when incoming certificate is not valid.
* Returns SECSuccess to accept the cert anyway, SECFailure to reject.
@ -307,6 +319,20 @@ ownBadCertHandler(void * arg, PRFileDesc * socket)
return SECSuccess; /* override, say it's OK. */
}
static SECStatus
ownAuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig,
PRBool isServer)
{
ServerCertAuth * serverCertAuth = (ServerCertAuth *) arg;
FPRINTF(stderr, "using asynchronous certificate validation\n", progName);
PORT_Assert(serverCertAuth->shouldPause);
PORT_Assert(!serverCertAuth->isPaused);
serverCertAuth->isPaused = PR_TRUE;
return SECWouldBlock;
}
SECStatus
own_GetClientAuthData(void * arg,
PRFileDesc * socket,
@ -498,11 +524,37 @@ separateReqHeader(const PRFileDesc* outFd, const char* buf, const int nb,
Usage(progName); \
}
static SECStatus
restartHandshakeAfterServerCertIfNeeded(PRFileDesc * fd,
ServerCertAuth * serverCertAuth,
PRBool override)
{
SECStatus rv;
if (!serverCertAuth->isPaused)
return SECSuccess;
FPRINTF(stderr, "%s: handshake was paused by auth certificate hook\n",
progName);
serverCertAuth->isPaused = PR_FALSE;
rv = SSL_AuthCertificate(serverCertAuth->dbHandle, fd, PR_TRUE, PR_FALSE);
if (rv != SECSuccess && override) {
rv = ownBadCertHandler(NULL, fd);
}
if (rv != SECSuccess) {
return rv;
}
rv = SSL_RestartHandshakeAfterAuthCertificate(fd);
return rv;
}
int main(int argc, char **argv)
{
PRFileDesc * s;
PRFileDesc * std_out;
CERTCertDBHandle * handle;
char * host = NULL;
char * certDir = NULL;
char * nickname = NULL;
@ -530,6 +582,7 @@ int main(int argc, char **argv)
PRBool clientSpeaksFirst = PR_FALSE;
PRBool wrStarted = PR_FALSE;
PRBool skipProtoHeader = PR_FALSE;
ServerCertAuth serverCertAuth;
int headerSeparatorPtrnId = 0;
int error = 0;
PRUint16 portno = 443;
@ -539,6 +592,10 @@ int main(int argc, char **argv)
PLOptStatus optstatus;
PRStatus prStatus;
serverCertAuth.shouldPause = PR_TRUE;
serverCertAuth.isPaused = PR_FALSE;
serverCertAuth.dbHandle = NULL;
progName = strrchr(argv[0], '/');
if (!progName)
progName = strrchr(argv[0], '\\');
@ -553,7 +610,7 @@ int main(int argc, char **argv)
}
optstate = PL_CreateOptState(argc, argv,
"23BSTW:a:c:d:fgh:m:n:op:qr:suvw:xz");
"23BOSTW:a:c:d:fgh:m:n:op:qr:suvw:xz");
while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
switch (optstate->option) {
case '?':
@ -565,6 +622,8 @@ int main(int argc, char **argv)
case 'B': bypassPKCS11 = 1; break;
case 'O': serverCertAuth.shouldPause = PR_FALSE; break;
case 'S': skipProtoHeader = PR_TRUE; break;
case 'T': disableTLS = 1; break;
@ -650,14 +709,8 @@ int main(int argc, char **argv)
rv = NSS_Init(certDir);
if (rv != SECSuccess) {
SECU_PrintError(progName, "unable to open cert database");
#if 0
rv = CERT_OpenVolatileCertDB(handle);
CERT_SetDefaultCertDB(handle);
#else
return 1;
#endif
}
handle = CERT_GetDefaultCertDB();
/* set the policy bits true for all the cipher suites. */
if (useExportPolicy)
@ -876,7 +929,13 @@ int main(int argc, char **argv)
SSL_SetPKCS11PinArg(s, &pwdata);
SSL_AuthCertificateHook(s, SSL_AuthCertificate, (void *)handle);
serverCertAuth.dbHandle = CERT_GetDefaultCertDB();
if (serverCertAuth.shouldPause) {
SSL_AuthCertificateHook(s, ownAuthCertificate, &serverCertAuth);
} else {
SSL_AuthCertificateHook(s, SSL_AuthCertificate, serverCertAuth.dbHandle);
}
if (override) {
SSL_BadCertHook(s, ownBadCertHandler, NULL);
}
@ -984,6 +1043,14 @@ int main(int argc, char **argv)
char buf[4000]; /* buffer for stdin */
int nb; /* num bytes read from stdin. */
rv = restartHandshakeAfterServerCertIfNeeded(s, &serverCertAuth,
override);
if (rv != SECSuccess) {
error = 254; /* 254 (usually) means "handshake failed" */
SECU_PrintError(progName, "authentication of server cert failed");
goto done;
}
pollset[SSOCK_FD].out_flags = 0;
pollset[STDIN_FD].out_flags = 0;
@ -1042,6 +1109,15 @@ int main(int argc, char **argv)
nb -= cc;
if (nb <= 0)
break;
rv = restartHandshakeAfterServerCertIfNeeded(s,
&serverCertAuth, override);
if (rv != SECSuccess) {
error = 254; /* 254 (usually) means "handshake failed" */
SECU_PrintError(progName, "authentication of server cert failed");
goto done;
}
pollset[SSOCK_FD].in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
pollset[SSOCK_FD].out_flags = 0;
FPRINTF(stderr,

View File

@ -411,3 +411,9 @@ ER3(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID, (SSL_ERROR_BASE + 116),
ER3(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2, (SSL_ERROR_BASE + 117),
"SSL feature not supported for SSL 2.0 connections.")
ER3(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SERVERS, (SSL_ERROR_BASE + 118),
"SSL feature not supported for servers.")
ER3(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_CLIENTS, (SSL_ERROR_BASE + 119),
"SSL feature not supported for clients.")

View File

@ -169,6 +169,7 @@ NSSSSL_GetVersion;
SSL_SetNextProtoCallback;
SSL_SetNextProtoNego;
SSL_GetNextProto;
SSL_RestartHandshakeAfterAuthCertificate;
;+ local:
;+ *;
;+};

View File

@ -339,6 +339,19 @@ SSL_IMPORT CERTCertificate *SSL_PeerCertificate(PRFileDesc *fd);
** Authenticate certificate hook. Called when a certificate comes in
** (because of SSL_REQUIRE_CERTIFICATE in SSL_Enable) to authenticate the
** certificate.
**
** The authenticate certificate hook must return SECSuccess to indicate the
** certificate is valid, SECFailure to indicate the certificate is invalid,
** or SECWouldBlock if the application will authenticate the certificate
** asynchronously.
**
** If the authenticate certificate hook returns SECFailure, then the bad cert
** hook will be called. The bad cert handler is NEVER called if the
** authenticate certificate hook returns SECWouldBlock.
**
** See the documentation for SSL_RestartHandshakeAfterAuthCertificate for more
** information about the asynchronous behavior that occurs when the
** authenticate certificate hook returns SECWouldBlock.
*/
typedef SECStatus (PR_CALLBACK *SSLAuthCertificate)(void *arg, PRFileDesc *fd,
PRBool checkSig,
@ -442,6 +455,15 @@ SSL_IMPORT SECStatus SSL_SetPKCS11PinArg(PRFileDesc *fd, void *a);
** This is a callback for dealing with server certs that are not authenticated
** by the client. The client app can decide that it actually likes the
** cert by some external means and restart the connection.
**
** The bad cert hook must return SECSuccess to override the result of the
** authenticate certificate hook, SECFailure if the certificate should still be
** considered invalid, or SECWouldBlock if the application will authenticate
** the certificate asynchronously.
**
** See the documentation for SSL_RestartHandshakeAfterAuthCertificate for more
** information about the asynchronous behavior that occurs when the bad cert
** hook returns SECWouldBlock.
*/
typedef SECStatus (PR_CALLBACK *SSLBadCertHandler)(void *arg, PRFileDesc *fd);
SSL_IMPORT SECStatus SSL_BadCertHook(PRFileDesc *fd, SSLBadCertHandler f,
@ -740,6 +762,53 @@ extern PRBool NSSSSL_VersionCheck(const char *importedVersion);
*/
extern const char *NSSSSL_GetVersion(void);
/* Restart an SSL connection that was paused to do asynchronous certificate
* chain validation (when the auth certificate hook or bad cert handler
* returned SECWouldBlock).
*
* Currently, this function works only for the client role of a connection; it
* does not work for the server role.
*
* The application MUST call SSL_RestartHandshakeAfterAuthCertificate after it
* has successfully validated the peer's certificate to continue the SSL
* handshake.
*
* The application MUST NOT call SSL_RestartHandshakeAfterAuthCertificate when
* certificate validation fails; instead, it should just close the connection.
*
* This function will not complete the entire handshake. The application must
* call SSL_ForceHandshake, PR_Recv, PR_Send, etc. after calling this function
* to force the handshake to complete.
*
* libssl will wait for the peer's certificate to be authenticated before
* calling the handshake callback, sending a client certificate,
* sending any application data, or returning any application data to the
* application (on the first handshake on a connection only).
*
* However, libssl may send and receive handshake messages while waiting for
* the application to call SSL_RestartHandshakeAfterAuthCertificate, and it may
* call other callbacks (e.g, the client auth data hook) before
* SSL_RestartHandshakeAfterAuthCertificate has been called.
*
* An application that uses this asynchronous mechanism will usually have lower
* handshake latency if it has to do public key operations on the certificate
* chain during the authentication, especially if it does so in parallel on
* another thread. However, if the application can authenticate the peer's
* certificate quickly then it may be more efficient to use the synchronous
* mechanism (i.e. returning SECFailure/SECSuccess instead of SECWouldBlock
* from the authenticate certificate hook).
*
* Be careful about converting an application from synchronous cert validation
* to asynchronous certificate validation. A naive conversion is likely to
* result in deadlocks; e.g. the application will wait in PR_Poll for network
* I/O on the connection while all network I/O on the connection is blocked
* waiting for this function to be called.
*
* Returns SECFailure on failure, SECSuccess on success. Never returns
* SECWouldBlock.
*/
SSL_IMPORT SECStatus SSL_RestartHandshakeAfterAuthCertificate(PRFileDesc *fd);
SEC_END_PROTOS
#endif /* __ssl_h_ */

View File

@ -5649,70 +5649,18 @@ 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 makes a
* copy of the private key, so the caller remains responsible
* for destroying its copy 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;
if (MSB(ss->version) == MSB(SSL_LIBRARY_VERSION_3_0)) {
/* 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.clientCertChain = certChain;
if (key == NULL) {
(void)SSL3_SendAlert(ss, alert_warning, no_certificate);
ss->ssl3.clientPrivateKey = NULL;
} else {
ss->ssl3.clientPrivateKey = SECKEY_CopyPrivateKey(key);
}
ssl_GetRecvBufLock(ss);
if (ss->ssl3.hs.msgState.buf != NULL) {
rv = ssl3_HandleRecord(ss, NULL, &ss->gs.buf);
}
ssl_ReleaseRecvBufLock(ss);
}
}
return rv;
}
PRBool
ssl3_CanFalseStart(sslSocket *ss) {
PRBool rv;
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
/* XXX: does not take into account whether we are waiting for
* SSL_RestartHandshakeAfterAuthCertificate or
* SSL_RestartHandshakeAfterCertReq. If/when that is done, this function
* could return different results each time it would be called.
*/
ssl_GetSpecReadLock(ss);
rv = ss->opt.enableFalseStart &&
!ss->sec.isServer &&
@ -5726,6 +5674,8 @@ ssl3_CanFalseStart(sslSocket *ss) {
return rv;
}
static SECStatus ssl3_SendClientSecondRound(sslSocket *ss);
/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
* ssl3 Server Hello Done message.
* Caller must hold Handshake and RecvBuf locks.
@ -5735,7 +5685,6 @@ ssl3_HandleServerHelloDone(sslSocket *ss)
{
SECStatus rv;
SSL3WaitState ws = ss->ssl3.hs.ws;
PRBool send_verify = PR_FALSE;
SSL_TRC(3, ("%d: SSL3[%d]: handle server_hello_done handshake",
SSL_GETPID(), ss->fd));
@ -5751,6 +5700,64 @@ ssl3_HandleServerHelloDone(sslSocket *ss)
return SECFailure;
}
rv = ssl3_SendClientSecondRound(ss);
return rv;
}
/* Called from ssl3_HandleServerHelloDone and
* ssl3_RestartHandshakeAfterServerCert.
*
* Caller must hold Handshake and RecvBuf locks.
*/
static SECStatus
ssl3_SendClientSecondRound(sslSocket *ss)
{
SECStatus rv;
PRBool sendClientCert;
PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
sendClientCert = !ss->ssl3.sendEmptyCert &&
ss->ssl3.clientCertChain != NULL &&
ss->ssl3.clientPrivateKey != NULL;
/* We must wait for the server's certificate to be authenticated before
* sending the client certificate in order to disclosing the client
* certificate to an attacker that does not have a valid cert for the
* domain we are connecting to.
*
* XXX: We should do the same for the NPN extension, but for that we
* need an option to give the application the ability to leak the NPN
* information to get better performance.
*
* During the initial handshake on a connection, we never send/receive
* application data until we have authenticated the server's certificate;
* i.e. we have fully authenticated the handshake before using the cipher
* specs agreed upon for that handshake. During a renegotiation, we may
* continue sending and receiving application data during the handshake
* interleaved with the handshake records. If we were to send the client's
* second round for a renegotiation before the server's certificate was
* authenticated, then the application data sent/received after this point
* would be using cipher spec that hadn't been authenticated. By waiting
* until the server's certificate has been authenticated during
* renegotiations, we ensure that renegotiations have the same property
* as initial handshakes; i.e. we have fully authenticated the handshake
* before using the cipher specs agreed upon for that handshake for
* application data.
*/
if (ss->ssl3.hs.restartTarget) {
PR_NOT_REACHED("unexpected ss->ssl3.hs.restartTarget");
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
if (ss->ssl3.hs.authCertificatePending &&
(sendClientCert || ss->ssl3.sendEmptyCert || ss->firstHsDone)) {
ss->ssl3.hs.restartTarget = ssl3_SendClientSecondRound;
return SECWouldBlock;
}
ssl_GetXmitBufLock(ss); /*******************************/
if (ss->ssl3.sendEmptyCert) {
@ -5760,10 +5767,7 @@ ssl3_HandleServerHelloDone(sslSocket *ss)
if (rv != SECSuccess) {
goto loser; /* error code is set. */
}
} else
if (ss->ssl3.clientCertChain != NULL &&
ss->ssl3.clientPrivateKey != NULL) {
send_verify = PR_TRUE;
} else if (sendClientCert) {
rv = ssl3_SendCertificate(ss);
if (rv != SECSuccess) {
goto loser; /* error code is set. */
@ -5775,17 +5779,21 @@ ssl3_HandleServerHelloDone(sslSocket *ss)
goto loser; /* err is set. */
}
if (send_verify) {
if (sendClientCert) {
rv = ssl3_SendCertificateVerify(ss);
if (rv != SECSuccess) {
goto loser; /* err is set. */
}
}
rv = ssl3_SendChangeCipherSpecs(ss);
if (rv != SECSuccess) {
goto loser; /* err code was set. */
}
/* XXX: If the server's certificate hasn't been authenticated by this
* point, then we may be leaking this NPN message to an attacker.
*/
if (!ss->firstHsDone) {
rv = ssl3_SendNextProto(ss);
if (rv != SECSuccess) {
@ -7814,8 +7822,6 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
{
ssl3CertNode * c;
ssl3CertNode * lastCert = NULL;
ssl3CertNode * certs = NULL;
PRArenaPool * arena = NULL;
PRInt32 remaining = 0;
PRInt32 size;
SECStatus rv;
@ -7872,11 +7878,11 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
errCode = PORT_GetError();
goto loser;
}
goto cert_block;
goto server_no_cert;
}
ss->ssl3.peerCertArena = arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if ( arena == NULL ) {
ss->ssl3.peerCertArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (ss->ssl3.peerCertArena == NULL) {
goto loser; /* don't send alerts on memory errors */
}
@ -7926,7 +7932,7 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
length -= size;
remaining -= size;
c = PORT_ArenaNew(arena, ssl3CertNode);
c = PORT_ArenaNew(ss->ssl3.peerCertArena, ssl3CertNode);
if (c == NULL) {
goto loser; /* don't send alerts on memory errors */
}
@ -7944,7 +7950,7 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
if (lastCert) {
lastCert->next = c;
} else {
certs = c;
ss->ssl3.peerCertChain = c;
}
lastCert = c;
}
@ -7954,6 +7960,8 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
SECKEY_UpdateCertPQG(ss->sec.peerCert);
ss->ssl3.hs.authCertificatePending = PR_FALSE;
/*
* Ask caller-supplied callback function to validate cert chain.
*/
@ -7961,24 +7969,26 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
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));
ss->ssl3.peerCertChain = certs;
certs = NULL;
ssl3_SetAlwaysBlock(ss);
goto cert_block;
if (rv != SECWouldBlock) {
if (ss->handleBadCert) {
rv = (*ss->handleBadCert)(ss->badCertArg, ss->fd);
}
/* cert is bad */
}
if (rv == SECWouldBlock) {
if (ss->sec.isServer) {
errCode = SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SERVERS;
rv = SECFailure;
goto loser;
}
ss->ssl3.hs.authCertificatePending = PR_TRUE;
rv = SECSuccess;
}
if (rv != SECSuccess) {
goto bad_cert;
}
/* cert is good */
}
ss->sec.ci.sid->peerCert = CERT_DupCertificate(ss->sec.peerCert);
@ -8026,14 +8036,7 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
SECKEY_DestroyPublicKey(pubKey);
pubKey = NULL;
}
}
ss->ssl3.peerCertChain = certs; certs = NULL; arena = NULL;
cert_block:
if (ss->sec.isServer) {
ss->ssl3.hs.ws = wait_client_key;
} else {
ss->ssl3.hs.ws = wait_cert_request; /* disallow server_key_exchange */
if (ss->ssl3.hs.kea_def->is_limited ||
/* XXX OR server cert is signing only. */
@ -8044,11 +8047,17 @@ cert_block:
ss->ssl3.hs.kea_def->exchKeyType == kt_dh) {
ss->ssl3.hs.ws = wait_server_key; /* allow server_key_exchange */
}
} else {
server_no_cert:
ss->ssl3.hs.ws = wait_client_key;
}
/* rv must normally be equal to SECSuccess here. If we called
* handleBadCert, it can also be SECWouldBlock.
*/
PORT_Assert(rv == SECSuccess);
if (rv != SECSuccess) {
errCode = SEC_ERROR_LIBRARY_FAILURE;
rv = SECFailure;
goto loser;
}
return rv;
ambiguous_err:
@ -8099,7 +8108,6 @@ alert_loser:
(void)SSL3_SendAlert(ss, alert_fatal, desc);
loser:
ss->ssl3.peerCertChain = certs; certs = NULL; arena = NULL;
ssl3_CleanupPeerCerts(ss);
if (ss->sec.peerCert != NULL) {
@ -8110,43 +8118,49 @@ loser:
return SECFailure;
}
static SECStatus ssl3_FinishHandshake(sslSocket *ss);
/* restart an SSL connection that we stopped to run certificate dialogs
** XXX Need to document here how an application marks a cert to show that
** the application has accepted it (overridden CERT_VerifyCert).
*
* XXX This code only works on the initial handshake on a connection, XXX
* It does not work on a subsequent handshake (redo).
*
* Return value: XXX
*
* Caller holds 1stHandshakeLock.
/* Caller must hold 1stHandshakeLock.
*/
int
ssl3_RestartHandshakeAfterServerCert(sslSocket *ss)
SECStatus
ssl3_RestartHandshakeAfterAuthCertificate(sslSocket *ss)
{
int rv = SECSuccess;
SECStatus rv;
if (MSB(ss->version) != MSB(SSL_LIBRARY_VERSION_3_0)) {
SET_ERROR_CODE
return SECFailure;
}
if (!ss->ssl3.initialized) {
SET_ERROR_CODE
return SECFailure;
PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss));
if (ss->sec.isServer) {
PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SERVERS);
return SECFailure;
}
if (ss->handshake != NULL) {
ss->handshake = ssl_GatherRecord1stHandshake;
ss->sec.ci.sid->peerCert = CERT_DupCertificate(ss->sec.peerCert);
ssl_GetRecvBufLock(ss);
ssl_GetSSL3HandshakeLock(ss);
ssl_GetRecvBufLock(ss);
if (ss->ssl3.hs.msgState.buf != NULL) {
rv = ssl3_HandleRecord(ss, NULL, &ss->gs.buf);
}
ssl_ReleaseRecvBufLock(ss);
if (!ss->ssl3.hs.authCertificatePending) {
PORT_SetError(PR_INVALID_STATE_ERROR);
rv = SECFailure;
} else {
ss->ssl3.hs.authCertificatePending = PR_FALSE;
if (ss->ssl3.hs.restartTarget != NULL) {
sslRestartTarget target = ss->ssl3.hs.restartTarget;
ss->ssl3.hs.restartTarget = NULL;
rv = target(ss);
/* Even if we blocked here, we have accomplished enough to claim
* success. Any remaining work will be taken care of by subsequent
* calls to SSL_ForceHandshake/PR_Send/PR_Read/etc.
*/
if (rv == SECWouldBlock) {
rv = SECSuccess;
}
} else {
rv = SECSuccess;
}
}
ssl_ReleaseSSL3HandshakeLock(ss);
ssl_ReleaseRecvBufLock(ss);
return rv;
}
@ -8499,9 +8513,6 @@ xmit_loser:
return rv;
}
/* The first handshake is now completed. */
ss->handshake = NULL;
ss->firstHsDone = PR_TRUE;
ss->gs.writeOffset = 0;
ss->gs.readOffset = 0;
@ -8551,10 +8562,42 @@ xmit_loser:
/* If the wrap failed, we don't cache the sid.
* The connection continues normally however.
*/
if (rv == SECSuccess) {
(*ss->sec.cache)(sid);
}
ss->ssl3.hs.cacheSID = rv == SECSuccess;
}
if (ss->ssl3.hs.authCertificatePending) {
if (ss->ssl3.hs.restartTarget) {
PR_NOT_REACHED("ssl3_HandleFinished: unexpected restartTarget");
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
ss->ssl3.hs.restartTarget = ssl3_FinishHandshake;
return SECWouldBlock;
}
rv = ssl3_FinishHandshake(ss);
return rv;
}
SECStatus
ssl3_FinishHandshake(sslSocket * ss)
{
SECStatus rv;
PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
PORT_Assert( ss->ssl3.hs.restartTarget == NULL );
/* The first handshake is now completed. */
ss->handshake = NULL;
ss->firstHsDone = PR_TRUE;
if (ss->sec.ci.sid->cached == never_cached &&
!ss->opt.noCache && ss->sec.cache && ss->ssl3.hs.cacheSID) {
(*ss->sec.cache)(ss->sec.ci.sid);
}
ss->ssl3.hs.ws = idle_handshake;
/* Do the handshake callback for sslv3 here, if we cannot false start. */

View File

@ -192,21 +192,53 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
do {
/* bring in the next sslv3 record. */
rv = ssl3_GatherData(ss, &ss->gs, flags);
if (rv <= 0) {
return rv;
}
/* decipher it, and handle it if it's a handshake.
* If it's application data, ss->gs.buf will not be empty upon return.
* If it's a change cipher spec, alert, or handshake message,
* ss->gs.buf.len will be 0 when ssl3_HandleRecord returns SECSuccess.
*/
cText.type = (SSL3ContentType)ss->gs.hdr[0];
cText.version = (ss->gs.hdr[1] << 8) | ss->gs.hdr[2];
cText.buf = &ss->gs.inbuf;
rv = ssl3_HandleRecord(ss, &cText, &ss->gs.buf);
/* Without this, we may end up wrongly reporting
* SSL_ERROR_RX_UNEXPECTED_* errors if we receive any records from the
* peer while we are waiting to be restarted.
*/
ssl_GetSSL3HandshakeLock(ss);
rv = ss->ssl3.hs.restartTarget == NULL ? SECSuccess : SECFailure;
ssl_ReleaseSSL3HandshakeLock(ss);
if (rv != SECSuccess) {
PORT_SetError(PR_WOULD_BLOCK_ERROR);
return (int) SECFailure;
}
/* Treat an empty msgState like a NULL msgState. (Most of the time
* when ssl3_HandleHandshake returns SECWouldBlock, it leaves
* behind a non-NULL but zero-length msgState).
* Test: async_cert_restart_server_sends_hello_request_first_in_separate_record
*/
if (ss->ssl3.hs.msgState.buf != NULL) {
if (ss->ssl3.hs.msgState.len == 0) {
ss->ssl3.hs.msgState.buf = NULL;
}
}
if (ss->ssl3.hs.msgState.buf != NULL) {
/* ssl3_HandleHandshake previously returned SECWouldBlock and the
* as-yet-unprocessed plaintext of that previous handshake record.
* We need to process it now before we overwrite it with the next
* handshake record.
*/
rv = ssl3_HandleRecord(ss, NULL, &ss->gs.buf);
} else {
/* bring in the next sslv3 record. */
rv = ssl3_GatherData(ss, &ss->gs, flags);
if (rv <= 0) {
return rv;
}
/* decipher it, and handle it if it's a handshake.
* If it's application data, ss->gs.buf will not be empty upon return.
* If it's a change cipher spec, alert, or handshake message,
* ss->gs.buf.len will be 0 when ssl3_HandleRecord returns SECSuccess.
*/
cText.type = (SSL3ContentType)ss->gs.hdr[0];
cText.version = (ss->gs.hdr[1] << 8) | ss->gs.hdr[2];
cText.buf = &ss->gs.inbuf;
rv = ssl3_HandleRecord(ss, &cText, &ss->gs.buf);
}
if (rv < 0) {
return ss->recvdCloseNotify ? 0 : rv;
}

View File

@ -208,6 +208,8 @@ SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY = (SSL_ERROR_BASE + 115),
SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID = (SSL_ERROR_BASE + 116),
SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2 = (SSL_ERROR_BASE + 117),
SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SERVERS = (SSL_ERROR_BASE + 118),
SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_CLIENTS = (SSL_ERROR_BASE + 119),
SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
} SSLErrorCodes;

View File

@ -750,6 +750,8 @@ struct TLSExtensionDataStr {
PRUint32 sniNameArrSize;
};
typedef SECStatus (*sslRestartTarget)(sslSocket *);
/*
** This is the "hs" member of the "ssl3" struct.
** This entire struct is protected by ssl3HandshakeLock
@ -789,6 +791,13 @@ const ssl3CipherSuiteDef *suite_def;
#ifdef NSS_ENABLE_ECC
PRUint32 negotiatedECCurves; /* bit mask */
#endif /* NSS_ENABLE_ECC */
PRBool authCertificatePending;
/* Which function should SSL_RestartHandshake* call if we're blocked?
* One of NULL, ssl3_SendClientSecondRound, or ssl3_FinishHandshake. */
sslRestartTarget restartTarget;
/* Shared state between ssl3_HandleFinished and ssl3_FinishHandshake */
PRBool cacheSID;
} SSL3HandshakeState;
@ -1340,7 +1349,6 @@ extern SECStatus ssl3_MasterKeyDeriveBypass( ssl3CipherSpec * pwSpec,
/* These functions are called from secnav, even though they're "private". */
extern int ssl2_SendErrorMessage(struct sslSocketStr *ss, int error);
extern int SSL_RestartHandshakeAfterServerCert(struct sslSocketStr *ss);
extern int SSL_RestartHandshakeAfterCertReq(struct sslSocketStr *ss,
CERTCertificate *cert,
SECKEYPrivateKey *key,
@ -1350,12 +1358,7 @@ extern void ssl_FreeSocket(struct sslSocketStr *ssl);
extern SECStatus SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level,
SSL3AlertDescription desc);
extern SECStatus ssl3_RestartHandshakeAfterCertReq(sslSocket * ss,
CERTCertificate * cert,
SECKEYPrivateKey * key,
CERTCertificateList *certChain);
extern int ssl3_RestartHandshakeAfterServerCert(sslSocket *ss);
extern SECStatus ssl3_RestartHandshakeAfterAuthCertificate(sslSocket *ss);
/*
* for dealing with SSL 3.0 clients sending SSL 2.0 format hellos

View File

@ -1463,29 +1463,8 @@ SSL_CertDBHandleSet(PRFileDesc *fd, CERTCertDBHandle *dbHandle)
return SECSuccess;
}
/*
* 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 makes a
* copy of the private key, so the caller remains responsible
* for destroying its copy 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).
/* DO NOT USE. This function was exported in ssl.def with the wrong signature;
* this implementation exists to maintain link-time compatibility.
*/
int
SSL_RestartHandshakeAfterCertReq(sslSocket * ss,
@ -1493,46 +1472,47 @@ SSL_RestartHandshakeAfterCertReq(sslSocket * ss,
SECKEYPrivateKey * key,
CERTCertificateList *certChain)
{
int ret;
ssl_Get1stHandshakeLock(ss); /************************************/
if (ss->version >= SSL_LIBRARY_VERSION_3_0) {
ret = ssl3_RestartHandshakeAfterCertReq(ss, cert, key, certChain);
} else {
PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2);
ret = SECFailure;
}
ssl_Release1stHandshakeLock(ss); /************************************/
return ret;
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
return -1;
}
/* restart an SSL connection that we stopped to run certificate dialogs
** XXX Need to document here how an application marks a cert to show that
** the application has accepted it (overridden CERT_VerifyCert).
*
* XXX This code only works on the initial handshake on a connection, XXX
* It does not work on a subsequent handshake (redo).
*
* Return value: XXX
*/
/* DO NOT USE. This function was exported in ssl.def with the wrong signature;
* this implementation exists to maintain link-time compatibility.
*/
int
SSL_RestartHandshakeAfterServerCert(sslSocket *ss)
SSL_RestartHandshakeAfterServerCert(sslSocket * ss)
{
int rv = SECSuccess;
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
return -1;
}
ssl_Get1stHandshakeLock(ss);
/* See documentation in ssl.h */
SECStatus
SSL_RestartHandshakeAfterAuthCertificate(PRFileDesc *fd)
{
SECStatus rv = SECSuccess;
sslSocket *ss = ssl_FindSocket(fd);
if (ss->version >= SSL_LIBRARY_VERSION_3_0) {
rv = ssl3_RestartHandshakeAfterServerCert(ss);
if (!ss) {
SSL_DBG(("%d: SSL[%d]: bad socket in SSL_RestartHandshakeAfterPeerCert",
SSL_GETPID(), fd));
return SECFailure;
}
ssl_Get1stHandshakeLock(ss);
if (!ss->ssl3.initialized) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
} else if (ss->version < SSL_LIBRARY_VERSION_3_0) {
PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2);
rv = SECFailure;
} else {
PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2);
rv = SECFailure;
rv = ssl3_RestartHandshakeAfterAuthCertificate(ss);
}
ssl_Release1stHandshakeLock(ss);
return rv;
}

View File

@ -308,6 +308,16 @@ ssl_cov()
EXP=$?
echo "${testname}" | grep "SSL2" > /dev/null
SSL2=$?
if [ "${SSL2}" -eq 0 ] ; then
# We cannot use asynchronous cert verification with SSL2
SSL2_FLAGS=-O
else
# Do not enable SSL2 for non-SSL2-specific tests. SSL2 is disabled by
# default in libssl but it is enabled by default in tstclnt; we want
# to test the libssl default whenever possible.
SSL2_FLAGS=-2
fi
if [ "$NORM_EXT" = "Extended Test" -a "${SSL2}" -eq 0 ] ; then
echo "$SCRIPTNAME: skipping $testname for $NORM_EXT"
@ -350,11 +360,11 @@ ssl_cov()
fi
fi
echo "tstclnt -p ${PORT} -h ${HOSTADDR} -c ${param} ${TLS_FLAG} ${CLIENT_OPTIONS} \\"
echo "tstclnt -p ${PORT} -h ${HOSTADDR} -c ${param} ${TLS_FLAG} ${SSL2_FLAGS} ${CLIENT_OPTIONS} \\"
echo " -f -d ${P_R_CLIENTDIR} -v -w nss < ${REQUEST_FILE}"
rm ${TMP}/$HOST.tmp.$$ 2>/dev/null
${PROFTOOL} ${BINDIR}/tstclnt -p ${PORT} -h ${HOSTADDR} -c ${param} ${TLS_FLAG} ${CLIENT_OPTIONS} -f \
${PROFTOOL} ${BINDIR}/tstclnt -p ${PORT} -h ${HOSTADDR} -c ${param} ${TLS_FLAG} ${SSL2_FLAGS} ${CLIENT_OPTIONS} -f \
-d ${P_R_CLIENTDIR} -v -w nss < ${REQUEST_FILE} \
>${TMP}/$HOST.tmp.$$ 2>&1
ret=$?

View File

@ -1,2 +1,7 @@
This directory contains patches that were added locally
on top of the NSS release.
bug-542832-ssl-restart-4.patch and bug-542832-ssl-restart-tstclnt-4.patch were
added so that we could test the new PSM SSL threading code (bug 674147) and
SPDY (bug 528288). These patches will be removed when the NSS 3.13.2 release
that includes them is imported into mozilla-central.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,349 @@
Index: mozilla/security/nss/cmd/tstclnt/tstclnt.c
===================================================================
RCS file: /cvsroot/mozilla/security/nss/cmd/tstclnt/tstclnt.c,v
retrieving revision 1.64
diff -u -8 -p -r1.64 tstclnt.c
--- mozilla/security/nss/cmd/tstclnt/tstclnt.c 6 Oct 2011 22:42:33 -0000 1.64
+++ mozilla/security/nss/cmd/tstclnt/tstclnt.c 16 Nov 2011 08:24:12 -0000
@@ -212,16 +212,18 @@ static void Usage(const char *progName)
"-n nickname");
fprintf(stderr,
"%-20s Bypass PKCS11 layer for SSL encryption and MACing.\n", "-B");
fprintf(stderr, "%-20s Disable SSL v2.\n", "-2");
fprintf(stderr, "%-20s Disable SSL v3.\n", "-3");
fprintf(stderr, "%-20s Disable TLS (SSL v3.1).\n", "-T");
fprintf(stderr, "%-20s Prints only payload data. Skips HTTP header.\n", "-S");
fprintf(stderr, "%-20s Client speaks first. \n", "-f");
+ fprintf(stderr, "%-20s Use synchronous certificate validation "
+ "(required for SSL2)\n", "-O");
fprintf(stderr, "%-20s Override bad server cert. Make it OK.\n", "-o");
fprintf(stderr, "%-20s Disable SSL socket locking.\n", "-s");
fprintf(stderr, "%-20s Verbose progress reporting.\n", "-v");
fprintf(stderr, "%-20s Use export policy.\n", "-x");
fprintf(stderr, "%-20s Ping the server and then exit.\n", "-q");
fprintf(stderr, "%-20s Renegotiate N times (resuming session if N>1).\n", "-r N");
fprintf(stderr, "%-20s Enable the session ticket extension.\n", "-u");
fprintf(stderr, "%-20s Enable compression.\n", "-z");
@@ -288,30 +290,54 @@ disableAllSSLCiphers(void)
fprintf(stderr,
"SSL_CipherPrefSet didn't like value 0x%04x (i = %d): %s\n",
suite, i, SECU_Strerror(err));
exit(2);
}
}
}
+typedef struct
+{
+ PRBool shouldPause; /* PR_TRUE if we should use asynchronous peer cert
+ * authentication */
+ PRBool isPaused; /* PR_TRUE if libssl is waiting for us to validate the
+ * peer's certificate and restart the handshake. */
+ void * dbHandle; /* Certificate database handle to use while
+ * authenticating the peer's certificate. */
+} ServerCertAuth;
+
/*
* Callback is called when incoming certificate is not valid.
* Returns SECSuccess to accept the cert anyway, SECFailure to reject.
*/
static SECStatus
ownBadCertHandler(void * arg, PRFileDesc * socket)
{
PRErrorCode err = PR_GetError();
/* can log invalid cert here */
fprintf(stderr, "Bad server certificate: %d, %s\n", err,
SECU_Strerror(err));
return SECSuccess; /* override, say it's OK. */
}
+static SECStatus
+ownAuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig,
+ PRBool isServer)
+{
+ ServerCertAuth * serverCertAuth = (ServerCertAuth *) arg;
+
+ FPRINTF(stderr, "using asynchronous certificate validation\n", progName);
+
+ PORT_Assert(serverCertAuth->shouldPause);
+ PORT_Assert(!serverCertAuth->isPaused);
+ serverCertAuth->isPaused = PR_TRUE;
+ return SECWouldBlock;
+}
+
SECStatus
own_GetClientAuthData(void * arg,
PRFileDesc * socket,
struct CERTDistNamesStr * caNames,
struct CERTCertificateStr ** pRetCert,
struct SECKEYPrivateKeyStr **pRetKey)
{
if (verbose > 1) {
@@ -493,21 +519,47 @@ separateReqHeader(const PRFileDesc* outF
} else if (((c) >= 'a') && ((c) <= 'f')) { \
i = (c) - 'a' + 10; \
} else if (((c) >= 'A') && ((c) <= 'F')) { \
i = (c) - 'A' + 10; \
} else { \
Usage(progName); \
}
+static SECStatus
+restartHandshakeAfterServerCertIfNeeded(PRFileDesc * fd,
+ ServerCertAuth * serverCertAuth,
+ PRBool override)
+{
+ SECStatus rv;
+
+ if (!serverCertAuth->isPaused)
+ return SECSuccess;
+
+ FPRINTF(stderr, "%s: handshake was paused by auth certificate hook\n",
+ progName);
+
+ serverCertAuth->isPaused = PR_FALSE;
+ rv = SSL_AuthCertificate(serverCertAuth->dbHandle, fd, PR_TRUE, PR_FALSE);
+ if (rv != SECSuccess && override) {
+ rv = ownBadCertHandler(NULL, fd);
+ }
+ if (rv != SECSuccess) {
+ return rv;
+ }
+
+ rv = SSL_RestartHandshakeAfterAuthCertificate(fd);
+
+ return rv;
+}
+
int main(int argc, char **argv)
{
PRFileDesc * s;
PRFileDesc * std_out;
- CERTCertDBHandle * handle;
char * host = NULL;
char * certDir = NULL;
char * nickname = NULL;
char * cipherString = NULL;
char * tmp;
int multiplier = 0;
SECStatus rv;
PRStatus status;
@@ -525,51 +577,58 @@ int main(int argc, char **argv)
int enableFalseStart = 0;
PRSocketOptionData opt;
PRNetAddr addr;
PRPollDesc pollset[2];
PRBool pingServerFirst = PR_FALSE;
PRBool clientSpeaksFirst = PR_FALSE;
PRBool wrStarted = PR_FALSE;
PRBool skipProtoHeader = PR_FALSE;
+ ServerCertAuth serverCertAuth;
int headerSeparatorPtrnId = 0;
int error = 0;
PRUint16 portno = 443;
char * hs1SniHostName = NULL;
char * hs2SniHostName = NULL;
PLOptState *optstate;
PLOptStatus optstatus;
PRStatus prStatus;
+ serverCertAuth.shouldPause = PR_TRUE;
+ serverCertAuth.isPaused = PR_FALSE;
+ serverCertAuth.dbHandle = NULL;
+
progName = strrchr(argv[0], '/');
if (!progName)
progName = strrchr(argv[0], '\\');
progName = progName ? progName+1 : argv[0];
tmp = PR_GetEnv("NSS_DEBUG_TIMEOUT");
if (tmp && tmp[0]) {
int sec = PORT_Atoi(tmp);
if (sec > 0) {
maxInterval = PR_SecondsToInterval(sec);
}
}
optstate = PL_CreateOptState(argc, argv,
- "23BSTW:a:c:d:fgh:m:n:op:qr:suvw:xz");
+ "23BOSTW:a:c:d:fgh:m:n:op:qr:suvw:xz");
while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
switch (optstate->option) {
case '?':
default : Usage(progName); break;
case '2': disableSSL2 = 1; break;
case '3': disableSSL3 = 1; break;
case 'B': bypassPKCS11 = 1; break;
+ case 'O': serverCertAuth.shouldPause = PR_FALSE; break;
+
case 'S': skipProtoHeader = PR_TRUE; break;
case 'T': disableTLS = 1; break;
case 'a': if (!hs1SniHostName) {
hs1SniHostName = PORT_Strdup(optstate->value);
} else if (!hs2SniHostName) {
hs2SniHostName = PORT_Strdup(optstate->value);
@@ -645,24 +704,18 @@ int main(int argc, char **argv)
} else {
char *certDirTmp = certDir;
certDir = SECU_ConfigDirectory(certDirTmp);
PORT_Free(certDirTmp);
}
rv = NSS_Init(certDir);
if (rv != SECSuccess) {
SECU_PrintError(progName, "unable to open cert database");
-#if 0
- rv = CERT_OpenVolatileCertDB(handle);
- CERT_SetDefaultCertDB(handle);
-#else
return 1;
-#endif
}
- handle = CERT_GetDefaultCertDB();
/* set the policy bits true for all the cipher suites. */
if (useExportPolicy)
NSS_SetExportPolicy();
else
NSS_SetDomesticPolicy();
/* all the SSL2 and SSL3 cipher suites are enabled by default. */
@@ -871,17 +924,23 @@ int main(int argc, char **argv)
rv = SSL_OptionSet(s, SSL_ENABLE_FALSE_START, enableFalseStart);
if (rv != SECSuccess) {
SECU_PrintError(progName, "error enabling false start");
return 1;
}
SSL_SetPKCS11PinArg(s, &pwdata);
- SSL_AuthCertificateHook(s, SSL_AuthCertificate, (void *)handle);
+ serverCertAuth.dbHandle = CERT_GetDefaultCertDB();
+
+ if (serverCertAuth.shouldPause) {
+ SSL_AuthCertificateHook(s, ownAuthCertificate, &serverCertAuth);
+ } else {
+ SSL_AuthCertificateHook(s, SSL_AuthCertificate, serverCertAuth.dbHandle);
+ }
if (override) {
SSL_BadCertHook(s, ownBadCertHandler, NULL);
}
SSL_GetClientAuthDataHook(s, own_GetClientAuthData, (void *)nickname);
SSL_HandshakeCallback(s, handshakeCallback, hs2SniHostName);
if (hs1SniHostName) {
SSL_SetURL(s, hs1SniHostName);
} else {
@@ -979,16 +1038,24 @@ int main(int argc, char **argv)
** socket, read data from socket and write to stdout.
*/
FPRINTF(stderr, "%s: ready...\n", progName);
while (pollset[SSOCK_FD].in_flags | pollset[STDIN_FD].in_flags) {
char buf[4000]; /* buffer for stdin */
int nb; /* num bytes read from stdin. */
+ rv = restartHandshakeAfterServerCertIfNeeded(s, &serverCertAuth,
+ override);
+ if (rv != SECSuccess) {
+ error = 254; /* 254 (usually) means "handshake failed" */
+ SECU_PrintError(progName, "authentication of server cert failed");
+ goto done;
+ }
+
pollset[SSOCK_FD].out_flags = 0;
pollset[STDIN_FD].out_flags = 0;
FPRINTF(stderr, "%s: about to call PR_Poll !\n", progName);
filesReady = PR_Poll(pollset, npds, PR_INTERVAL_NO_TIMEOUT);
if (filesReady < 0) {
SECU_PrintError(progName, "select failed");
error = 1;
@@ -1037,16 +1104,25 @@ int main(int argc, char **argv)
goto done;
}
cc = 0;
}
bufp += cc;
nb -= cc;
if (nb <= 0)
break;
+
+ rv = restartHandshakeAfterServerCertIfNeeded(s,
+ &serverCertAuth, override);
+ if (rv != SECSuccess) {
+ error = 254; /* 254 (usually) means "handshake failed" */
+ SECU_PrintError(progName, "authentication of server cert failed");
+ goto done;
+ }
+
pollset[SSOCK_FD].in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
pollset[SSOCK_FD].out_flags = 0;
FPRINTF(stderr,
"%s: about to call PR_Poll on writable socket !\n",
progName);
cc = PR_Poll(pollset, 1, PR_INTERVAL_NO_TIMEOUT);
FPRINTF(stderr,
"%s: PR_Poll returned with writable socket !\n",
Index: mozilla/security/nss/tests/ssl/ssl.sh
===================================================================
RCS file: /cvsroot/mozilla/security/nss/tests/ssl/ssl.sh,v
retrieving revision 1.106
diff -u -8 -p -r1.106 ssl.sh
--- mozilla/security/nss/tests/ssl/ssl.sh 29 Jan 2010 22:36:25 -0000 1.106
+++ mozilla/security/nss/tests/ssl/ssl.sh 16 Nov 2011 08:24:14 -0000
@@ -303,16 +303,26 @@ ssl_cov()
exec < ${SSLCOV}
while read ectype tls param testname
do
echo "${testname}" | grep "EXPORT" > /dev/null
EXP=$?
echo "${testname}" | grep "SSL2" > /dev/null
SSL2=$?
+
+ if [ "${SSL2}" -eq 0 ] ; then
+ # We cannot use asynchronous cert verification with SSL2
+ SSL2_FLAGS=-O
+ else
+ # Do not enable SSL2 for non-SSL2-specific tests. SSL2 is disabled by
+ # default in libssl but it is enabled by default in tstclnt; we want
+ # to test the libssl default whenever possible.
+ SSL2_FLAGS=-2
+ fi
if [ "$NORM_EXT" = "Extended Test" -a "${SSL2}" -eq 0 ] ; then
echo "$SCRIPTNAME: skipping $testname for $NORM_EXT"
elif [ "$ectype" = "ECC" -a -z "$NSS_ENABLE_ECC" ] ; then
echo "$SCRIPTNAME: skipping $testname (ECC only)"
elif [ "$SERVER_MODE" = "fips" -o "$CLIENT_MODE" = "fips" ] && [ "$SSL2" -eq 0 -o "$EXP" -eq 0 ] ; then
echo "$SCRIPTNAME: skipping $testname (non-FIPS only)"
elif [ "`echo $ectype | cut -b 1`" != "#" ] ; then
@@ -345,21 +355,21 @@ ssl_cov()
is_selfserv_alive
else
kill_selfserv
start_selfserv
mixed=0
fi
fi
- echo "tstclnt -p ${PORT} -h ${HOSTADDR} -c ${param} ${TLS_FLAG} ${CLIENT_OPTIONS} \\"
+ echo "tstclnt -p ${PORT} -h ${HOSTADDR} -c ${param} ${TLS_FLAG} ${SSL2_FLAGS} ${CLIENT_OPTIONS} \\"
echo " -f -d ${P_R_CLIENTDIR} -v -w nss < ${REQUEST_FILE}"
rm ${TMP}/$HOST.tmp.$$ 2>/dev/null
- ${PROFTOOL} ${BINDIR}/tstclnt -p ${PORT} -h ${HOSTADDR} -c ${param} ${TLS_FLAG} ${CLIENT_OPTIONS} -f \
+ ${PROFTOOL} ${BINDIR}/tstclnt -p ${PORT} -h ${HOSTADDR} -c ${param} ${TLS_FLAG} ${SSL2_FLAGS} ${CLIENT_OPTIONS} -f \
-d ${P_R_CLIENTDIR} -v -w nss < ${REQUEST_FILE} \
>${TMP}/$HOST.tmp.$$ 2>&1
ret=$?
cat ${TMP}/$HOST.tmp.$$
rm ${TMP}/$HOST.tmp.$$ 2>/dev/null
html_msg $ret 0 "${testname}" \
"produced a returncode of $ret, expected is 0"
fi