Skip to content

Instantly share code, notes, and snippets.

@agl
Created January 26, 2010 16:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save agl/286966 to your computer and use it in GitHub Desktop.
Save agl/286966 to your computer and use it in GitHub Desktop.
diff --git a/mozilla/security/nss/lib/ssl/ssl3con.c b/mozilla/security/nss/lib/ssl/ssl3con.c
index 8d4b05d..414707e 100644
--- a/mozilla/security/nss/lib/ssl/ssl3con.c
+++ b/mozilla/security/nss/lib/ssl/ssl3con.c
@@ -5607,7 +5607,36 @@ ssl3_RestartHandshakeAfterCertReq(sslSocket * ss,
return rv;
}
+static SSL3AlertDescription
+ssl3_CertErrorToAlert(PRBool isTLS, int errCode)
+{
+ switch (errCode) {
+ case SEC_ERROR_LIBRARY_FAILURE: return unsupported_certificate;
+ case SEC_ERROR_EXPIRED_CERTIFICATE: return certificate_expired;
+ case SEC_ERROR_REVOKED_CERTIFICATE: return certificate_revoked;
+ case SEC_ERROR_INADEQUATE_KEY_USAGE:
+ case SEC_ERROR_INADEQUATE_CERT_TYPE:
+ return certificate_unknown;
+ case SEC_ERROR_UNTRUSTED_CERT:
+ return isTLS ? access_denied : certificate_unknown;
+ case SEC_ERROR_UNKNOWN_ISSUER:
+ case SEC_ERROR_UNTRUSTED_ISSUER:
+ return isTLS ? unknown_ca : certificate_unknown;
+ case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
+ return isTLS ? unknown_ca : certificate_expired;
+ case PR_OUT_OF_MEMORY_ERROR:
+ case SEC_ERROR_BAD_DATABASE:
+ case SEC_ERROR_NO_MEMORY:
+ return internal_error;
+
+ 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: return bad_certificate;
+ }
+}
/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
* ssl3 Server Hello Done message.
@@ -5619,6 +5648,13 @@ ssl3_HandleServerHelloDone(sslSocket *ss)
SECStatus rv;
SSL3WaitState ws = ss->ssl3.hs.ws;
PRBool send_verify = PR_FALSE;
+ PRBool isServer = (PRBool)(!!ss->sec.isServer);
+ PRBool retWouldBlock = PR_FALSE;
+ SSL3AlertDescription desc = bad_certificate;
+ PRBool isTLS;
+ int errCode;
+
+ isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
SSL_TRC(3, ("%d: SSL3[%d]: handle server_hello_done handshake",
SSL_GETPID(), ss->fd));
@@ -5634,6 +5670,29 @@ ssl3_HandleServerHelloDone(sslSocket *ss)
return SECFailure;
}
+ /*
+ * Ask caller-supplied callback function to validate cert chain.
+ */
+ rv = (SECStatus)(*ss->authCertificate)(ss->authCertificateArg, ss->fd,
+ PR_TRUE, isServer);
+ if (rv) {
+ if (!ss->handleBadCert) {
+ goto bad_cert;
+ }
+ rv = (SECStatus)(*ss->handleBadCert)(ss->badCertArg, ss->fd);
+ if ( rv ) {
+ if ( rv != SECWouldBlock )
+ goto bad_cert;
+
+ /* someone will handle this connection asynchronously*/
+ SSL_DBG(("%d: SSL3[%d]: go to async cert handler",
+ SSL_GETPID(), ss->fd));
+ ssl_SetAlwaysBlock(ss);
+ retWouldBlock = PR_TRUE;
+ }
+ /* cert is good */
+ }
+
ssl_GetXmitBufLock(ss); /*******************************/
if (ss->ssl3.sendEmptyCert) {
@@ -5679,8 +5738,26 @@ ssl3_HandleServerHelloDone(sslSocket *ss)
ss->ssl3.hs.ws = wait_new_session_ticket;
else
ss->ssl3.hs.ws = wait_change_cipher;
+
+ if (retWouldBlock)
+ return SECWouldBlock;
return SECSuccess;
+bad_cert:
+ errCode = PORT_GetError();
+ desc = ssl3_CertErrorToAlert(isTLS, errCode);
+ SSL_DBG(("%d: SSL3[%d]: peer certificate is no good: error=%d",
+ SSL_GETPID(), ss->fd, errCode));
+ ssl3_CleanupPeerCerts(ss);
+ (void)ssl_MapLowLevelError(errCode);
+
+ /* internal_error is not a valid SSL3 alert */
+ if (desc != internal_error || isTLS)
+ (void)SSL3_SendAlert(ss, alert_fatal, desc);
+
+ /* We don't have the XmitBufLock when jumping to bad_cert */
+ return rv;
+
loser:
ssl_ReleaseXmitBufLock(ss);
return rv;
@@ -7637,7 +7714,7 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
CERTCertificate *cert;
PRInt32 remaining = 0;
PRInt32 size;
- SECStatus rv;
+ SECStatus rv = SECSuccess;
PRBool isServer = (PRBool)(!!ss->sec.isServer);
PRBool trusted = PR_FALSE;
PRBool isTLS;
@@ -7768,33 +7845,6 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
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));
- ss->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 &&
@@ -7872,47 +7922,11 @@ cert_block:
}
}
- /* 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;
- }
+ desc = ssl3_CertErrorToAlert(isTLS, errCode);
SSL_DBG(("%d: SSL3[%d]: peer certificate is no good: error=%d",
SSL_GETPID(), ss->fd, errCode));
@@ -7922,7 +7936,9 @@ decode_loser:
desc = isTLS ? decode_error : bad_certificate;
alert_loser:
- (void)SSL3_SendAlert(ss, alert_fatal, desc);
+ /* internal_error is not a valid SSL3 alert */
+ if (desc != internal_error || isTLS)
+ (void)SSL3_SendAlert(ss, alert_fatal, desc);
loser:
ss->ssl3.peerCertChain = certs; certs = NULL; arena = NULL;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment