Bug 542832 - SSL_RestartHandshakeAfterServerCert is broken, patch by Brian Smith, r=rrelyea

git-svn-id: svn://10.0.0.236/trunk@263388 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
kaie%kuix.de
2012-02-11 13:27:07 +00:00
parent 24031fa098
commit 7f0fbbdd65
2 changed files with 107 additions and 11 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,47 @@ separateReqHeader(const PRFileDesc* outFd, const char* buf, const int nb,
Usage(progName); \
}
static SECStatus
restartHandshakeAfterServerCertIfNeeded(PRFileDesc * fd,
ServerCertAuth * serverCertAuth,
PRBool override)
{
SECStatus rv;
PRErrorCode status;
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) {
status = PR_GetError();
if (status == 0) {
PR_NOT_REACHED("SSL_AuthCertificate return SECFailure without "
"setting error code.");
status = PR_INVALID_STATE_ERROR;
} else if (override) {
rv = ownBadCertHandler(NULL, fd);
}
}
if (rv == SECSuccess) {
status = 0;
}
if (SSL_AuthCertificateComplete(fd, status) != SECSuccess) {
rv = SECFailure;
}
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 +592,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 +602,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 +620,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 +632,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 +719,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 +939,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 +1053,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 +1119,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

@@ -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=$?