Skip to content

Commit

Permalink
Bug 1672291 libpkix OCSP failures on SHA1 self-signed root certs whe…
Browse files Browse the repository at this point in the history
…n SHA1 signatures are disabled.

When libpkix is checking an OCSP cert, it can't use the passed in set of trust anchors as a base because only the single root that signed the leaf can sign the OCSP request. As a result it actually checks the signature of the self-signed root when processing an OCSP request. This fails of the root cert signature is invalid for any reason (including it's a sha1 self-signed root cert and we've disabled sha1 signatures (say, by policy)).

Further investigation indicates the difference between our classic code and the current code is the classic code only checks OCSP responses on leaf certs. In the real world, those responses are signed by intermediate certificates (who won't have sha1 signed certificates anymore), so our signature processing works just fine. pkix checks OCSP on the intermediate certificates as well, which are signed by the root cert. In this case the root cert is a chain of 1, and is effectively a leaf. This patch updates the OCSP response code to not check the signatures on the single cert if that cert is a selfsigned root cert. This requires bug 391476 so we still do the other validation checking on the certs (making sure it's trusted as a CA).
  • Loading branch information
rjrelyea committed Oct 23, 2020
1 parent fd5907a commit 097a456
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 5 deletions.
5 changes: 1 addition & 4 deletions lib/certhigh/certvfypkix.c
Expand Up @@ -411,7 +411,7 @@ cert_ProcessingParamsSetKeyAndCertUsage(
static PKIX_Error *
cert_CreatePkixProcessingParams(
CERTCertificate *cert,
PRBool checkSig, /* not used yet. See bug 391476 */
PRBool checkSig,
PRTime time,
void *wincx,
PRBool useArena,
Expand Down Expand Up @@ -441,15 +441,12 @@ cert_CreatePkixProcessingParams(

*pplContext = plContext;

#ifdef PKIX_NOTDEF
/* Functions should be implemented in patch for 390532 */
PKIX_CHECK(
pkix_pl_NssContext_SetCertSignatureCheck(checkSig,
(PKIX_PL_NssContext *)plContext),
PKIX_NSSCONTEXTSETCERTSIGNCHECKFAILED);

#endif /* PKIX_NOTDEF */

PKIX_CHECK(
PKIX_ProcessingParams_Create(&procParams, plContext),
PKIX_PROCESSINGPARAMSCREATEFAILED);
Expand Down
70 changes: 70 additions & 0 deletions lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.c
Expand Up @@ -54,6 +54,7 @@ PKIX_PL_NssContext_Create(
context->crlReloadDelay = PKIX_DEFAULT_CRL_RELOAD_DELAY_SECONDS;
context->badDerCrlReloadDelay =
PKIX_DEFAULT_BAD_CRL_RELOAD_DELAY_SECONDS;
context->certSignatureCheck = PKIX_TRUE;
context->chainVerifyCallback.isChainValid = NULL;
context->chainVerifyCallback.isChainValidArg = NULL;
*pNssContext = context;
Expand Down Expand Up @@ -160,6 +161,75 @@ pkix_pl_NssContext_SetCertUsage(
PKIX_RETURN(CONTEXT);
}

/*
* FUNCTION: pkix_pl_NssContext_GetCertSignatureCheck
* DESCRIPTION:
*
* This function obtains the platform-dependent flag to turn on or off
* signature checks.
*
* PARAMETERS:
* "nssContext"
* The address of the context object whose wincx parameter is to be
* obtained. Must be non-NULL.
* "pCheckSig"
* The address where the result is stored. Must be non-NULL.
* THREAD SAFETY:
* Thread Safe (see Thread Safety Definitions in Programmer's Guide)
* RETURNS:
* Returns NULL if the function succeeds.
* Returns a Fatal Error if the function fails in an unrecoverable way.
*/
PKIX_Error *
pkix_pl_NssContext_GetCertSignatureCheck(
PKIX_PL_NssContext *nssContext,
PKIX_Boolean *pCheckSig)
{
void *plContext = NULL;

PKIX_ENTER(CONTEXT, "pkix_pl_NssContext_GetCertUsage");
PKIX_NULLCHECK_TWO(nssContext, pCheckSig);

*pCheckSig = nssContext->certSignatureCheck;

PKIX_RETURN(CONTEXT);
}

/*
* FUNCTION: pkix_pl_NssContext_SetCertSignatureCheck
* DESCRIPTION:
*
* This function sets the check signature flag in
* the context object pointed to by "nssContext" to the value provided in
* "checkSig".
*
* PARAMETERS:
* "checkSig"
* Boolean that tells whether or not to check the signatues on certs.
* "nssContext"
* The address of the context object whose wincx parameter is to be
* obtained. Must be non-NULL.
* THREAD SAFETY:
* Thread Safe (see Thread Safety Definitions in Programmer's Guide)
* RETURNS:
* Returns NULL if the function succeeds.
* Returns a Fatal Error if the function fails in an unrecoverable way.
*/
PKIX_Error *
pkix_pl_NssContext_SetCertSignatureCheck(
PKIX_Boolean checkSig,
PKIX_PL_NssContext *nssContext)
{
void *plContext = NULL;

PKIX_ENTER(CONTEXT, "pkix_pl_NssContext_SetCertUsage");
PKIX_NULLCHECK_ONE(nssContext);

nssContext->certSignatureCheck = checkSig;

PKIX_RETURN(CONTEXT);
}

/*
* FUNCTION: pkix_pl_NssContext_GetWincx
* DESCRIPTION:
Expand Down
9 changes: 9 additions & 0 deletions lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.h
Expand Up @@ -27,6 +27,7 @@ struct PKIX_PL_NssContextStruct {
PRTime crlReloadDelay;
PRTime badDerCrlReloadDelay;
CERTChainVerifyCallback chainVerifyCallback;
PKIX_Boolean certSignatureCheck;
};

PKIX_Error *
Expand All @@ -38,6 +39,14 @@ PKIX_Error *
pkix_pl_NssContext_SetCertUsage
(SECCertificateUsage certUsage, PKIX_PL_NssContext *nssContext);

PKIX_Error *
pkix_pl_NssContext_GetCertSignatureCheck
(PKIX_PL_NssContext *nssContext, PKIX_Boolean *pCheckSig);

PKIX_Error *
pkix_pl_NssContext_SetCertSignatureCheck
(PKIX_Boolean checkSig, PKIX_PL_NssContext *nssContext);

PKIX_Error *
pkix_pl_NssContext_GetWincx(PKIX_PL_NssContext *nssContext, void **pWincx);

Expand Down
10 changes: 10 additions & 0 deletions lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c
Expand Up @@ -2811,14 +2811,23 @@ PKIX_PL_Cert_VerifySignature(
PKIX_PL_Cert *cachedCert = NULL;
PKIX_Error *verifySig = NULL;
PKIX_Error *cachedSig = NULL;
PKIX_Error *checkSig = NULL;
SECStatus status;
PKIX_Boolean certEqual = PKIX_FALSE;
PKIX_Boolean certInHash = PKIX_FALSE;
PKIX_Boolean checkCertSig = PKIX_TRUE;
void* wincx = NULL;

PKIX_ENTER(CERT, "PKIX_PL_Cert_VerifySignature");
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pubKey);

/* if the cert check flag is off, skip the check */
checkSig = pkix_pl_NssContext_GetCertSignatureCheck(
(PKIX_PL_NssContext *)plContext, &checkCertSig);
if ((checkCertSig == PKIX_FALSE) && (checkSig == NULL)) {
goto cleanup;
}

verifySig = PKIX_PL_HashTable_Lookup
(cachedCertSigTable,
(PKIX_PL_Object *) pubKey,
Expand Down Expand Up @@ -2879,6 +2888,7 @@ PKIX_PL_Cert_VerifySignature(
}

PKIX_DECREF(cachedCert);
PKIX_DECREF(checkSig);
PKIX_DECREF(verifySig);
PKIX_DECREF(cachedSig);

Expand Down
3 changes: 2 additions & 1 deletion lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspresponse.c
Expand Up @@ -741,7 +741,8 @@ pkix_pl_OcspResponse_VerifyResponse(
PKIX_CERTVERIFYKEYUSAGEFAILED);
rv = SECSuccess;
} else {
rv = CERT_VerifyCert(response->handle, response->signerCert, PKIX_TRUE,
PRBool checkSig = response->signerCert->isRoot ? PR_FALSE : PR_TRUE;
rv = CERT_VerifyCert(response->handle, response->signerCert, checkSig,
certUsage, response->producedAt, NULL, NULL);
if (rv != SECSuccess) {
PKIX_ERROR(PKIX_CERTVERIFYKEYUSAGEFAILED);
Expand Down
44 changes: 44 additions & 0 deletions tests/ssl/ssl.sh
Expand Up @@ -906,6 +906,49 @@ ssl_policy_listsuites()
html "</TABLE><BR>"
}

ssl_policy_pkix_ocsp()
{
#verbose="-v"
html_head "Check that OCSP doesn't break if we disable sha1 $NORM_EXT - server $SERVER_MODE/client $CLIENT_MODE"

PKIX_SAVE=${NSS_ENABLE_PKIX_VERIFY-"unset"}
NSS_ENABLE_PKIX_VERIFY="1"
export NSS_ENABLE_PKIX_VERIFY

testname=""

if [ ! -f "${P_R_SERVERDIR}/pkcs11.txt" ] ; then
html_failed "${SCRIPTNAME}: ${P_R_SERVERDIR} is not initialized"
return 1;
fi

echo "Saving pkcs11.txt"
cp ${P_R_SERVERDIR}/pkcs11.txt ${P_R_SERVERDIR}/pkcs11.txt.sav

# Disallow all explicitly
setup_policy "disallow=sha1" ${P_R_SERVERDIR}
RET_EXP=0
echo " vfyserv -o wrong.host.badssl.com -d ${P_R_SERVERDIR} 2>&1 | tee ${P_R_SERVERDIR}/vfy.out"
vfyserv -o wrong.host.badssl.com -d ${P_R_SERVERDIR} 2>&1 | tee ${P_R_SERVERDIR}/vfy.out
# make sure we have the domain mismatch, not bad signature error
echo "grep 12276 ${P_R_SERVERDIR}/vfy.out"
grep 12276 ${P_R_SERVERDIR}/vfy.out
RET=$?
html_msg $RET $RET_EXP "${testname}" \
"produced a returncode of $RET, expected is $RET_EXP"

if [ "${PKIX_SAVE}" = "unset" ]; then
unset NSS_ENABLE_PKIX_VERIFY
else
NSS_ENABLE_PKIX_VERIFY=${PKIX_SAVE}
export NSS_ENABLE_PKIX_VERIFY
fi
cp ${P_R_SERVERDIR}/pkcs11.txt.sav ${P_R_SERVERDIR}/pkcs11.txt

html "</TABLE><BR>"

}

############################## ssl_policy_selfserv #####################
# local shell function to perform SSL Policy tests, using selfserv
########################################################################
Expand Down Expand Up @@ -1522,6 +1565,7 @@ ssl_run_tests()
if [ "${TEST_MODE}" = "SHARED_DB" ] ; then
ssl_policy_listsuites
ssl_policy_selfserv
ssl_policy_pkix_ocsp
ssl_policy
fi
;;
Expand Down

0 comments on commit 097a456

Please sign in to comment.