bug 972753 - OCSP testing: delegated responses and including multiple certificates r=cviecco

This commit is contained in:
David Keeler 2014-04-16 09:31:27 -07:00
parent 7fae189111
commit 47abc69838
12 changed files with 114 additions and 5 deletions

View File

@ -127,6 +127,21 @@ function add_tests_in_mode(useMozillaPKIX, certDB, otherTestCA) {
true);
add_ocsp_test("ocsp-stapling-noncritical-extension.example.com", Cr.NS_OK, true);
add_ocsp_test("ocsp-stapling-delegated-included.example.com", Cr.NS_OK, true);
add_ocsp_test("ocsp-stapling-delegated-included-last.example.com", Cr.NS_OK, true);
add_ocsp_test("ocsp-stapling-delegated-missing.example.com",
getXPCOMStatusFromNSS(SEC_ERROR_OCSP_INVALID_SIGNING_CERT), true);
add_ocsp_test("ocsp-stapling-delegated-missing-multiple.example.com",
getXPCOMStatusFromNSS(SEC_ERROR_OCSP_INVALID_SIGNING_CERT), true);
add_ocsp_test("ocsp-stapling-delegated-no-extKeyUsage.example.com",
getXPCOMStatusFromNSS(SEC_ERROR_OCSP_INVALID_SIGNING_CERT), true);
add_ocsp_test("ocsp-stapling-delegated-from-intermediate.example.com",
getXPCOMStatusFromNSS(SEC_ERROR_OCSP_INVALID_SIGNING_CERT), true);
add_ocsp_test("ocsp-stapling-delegated-keyUsage-crlSigning.example.com",
getXPCOMStatusFromNSS(SEC_ERROR_OCSP_INVALID_SIGNING_CERT), true);
add_ocsp_test("ocsp-stapling-delegated-wrong-extKeyUsage.example.com",
getXPCOMStatusFromNSS(SEC_ERROR_OCSP_INVALID_SIGNING_CERT), true);
// ocsp-stapling-expired.example.com and
// ocsp-stapling-expired-fresh-ca.example.com are handled in
// test_ocsp_stapling_expired.js
@ -138,10 +153,10 @@ function check_ocsp_stapling_telemetry() {
.getHistogramById("SSL_OCSP_STAPLING")
.snapshot();
do_check_eq(histogram.counts[0], 2 * 0); // histogram bucket 0 is unused
do_check_eq(histogram.counts[1], 2 + 3); // 2 or 3 connections with a good response (bug 987426)
do_check_eq(histogram.counts[1], 4 + 5); // 4 or 5 connections with a good response (bug 987426)
do_check_eq(histogram.counts[2], 2 * 17); // 17 connections with no stapled resp.
do_check_eq(histogram.counts[3], 2 * 0); // 0 connections with an expired response
do_check_eq(histogram.counts[4], 13 + 11); // 13 or 11 connections with bad responses (bug 979070, bug 987426)
do_check_eq(histogram.counts[4], 19 + 17); // 19 or 17 connections with bad responses (bug 979070, bug 987426)
run_next_test();
}

View File

@ -40,6 +40,14 @@ const OCSPHost sOCSPHosts[] =
{ "ocsp-stapling-skip-responseBytes.example.com", ORTSkipResponseBytes, nullptr },
{ "ocsp-stapling-critical-extension.example.com", ORTCriticalExtension, nullptr },
{ "ocsp-stapling-noncritical-extension.example.com", ORTNoncriticalExtension, nullptr },
{ "ocsp-stapling-delegated-included.example.com", ORTDelegatedIncluded, "delegatedSigner" },
{ "ocsp-stapling-delegated-included-last.example.com", ORTDelegatedIncludedLast, "delegatedSigner" },
{ "ocsp-stapling-delegated-missing.example.com", ORTDelegatedMissing, "delegatedSigner" },
{ "ocsp-stapling-delegated-missing-multiple.example.com", ORTDelegatedMissingMultiple, "delegatedSigner" },
{ "ocsp-stapling-delegated-no-extKeyUsage.example.com", ORTDelegatedIncluded, "invalidDelegatedSignerNoExtKeyUsage" },
{ "ocsp-stapling-delegated-from-intermediate.example.com", ORTDelegatedIncluded, "invalidDelegatedSignerFromIntermediate" },
{ "ocsp-stapling-delegated-keyUsage-crlSigning.example.com", ORTDelegatedIncluded, "invalidDelegatedSignerKeyUsageCrlSigning" },
{ "ocsp-stapling-delegated-wrong-extKeyUsage.example.com", ORTDelegatedIncluded, "invalidDelegatedSignerWrongExtKeyUsage" },
{ nullptr, ORTNull, nullptr }
};

View File

@ -114,6 +114,24 @@ function make_EE {
SERIALNO=$(($SERIALNO + 1))
}
function make_delegated {
CERT_RESPONSES="n\n\ny\n"
NICKNAME="${1}"
SUBJECT="${2}"
CA="${3}"
EXTRA_ARGS="${4}"
echo -e "$CERT_RESPONSES" | $RUN_MOZILLA $CERTUTIL -d $OUTPUT_DIR -S \
-n $NICKNAME \
-s "$SUBJECT" \
-c $CA \
-t ",," \
-m $SERIALNO \
$COMMON_ARGS \
$EXTRA_ARGS
SERIALNO=$(($SERIALNO + 1))
}
make_CA testCA 'CN=Test CA' test-ca.der
make_CA otherCA 'CN=Other test CA' other-test-ca.der
make_EE localhostAndExampleCom 'CN=Test End-entity' testCA "localhost,*.example.com"
@ -147,6 +165,12 @@ NSS_ALLOW_WEAK_SIGNATURE_ALG=1 make_EE md5signature-expired 'CN=Test MD5Signatur
make_EE inadequatekeyusage 'CN=Inadequate Key Usage Test End-entity' testCA "inadequatekeyusage.example.com" "--keyUsage crlSigning"
make_EE selfsigned-inadequateEKU 'CN=Self-signed Inadequate EKU Test End-entity' unused "selfsigned-inadequateEKU.example.com" "--keyUsage keyEncipherment,dataEncipherment --extKeyUsage serverAuth" "-x"
make_delegated delegatedSigner 'CN=Test Delegated Responder' testCA "--extKeyUsage ocspResponder"
make_delegated invalidDelegatedSignerNoExtKeyUsage 'CN=Test Invalid Delegated Responder No extKeyUsage' testCA
make_delegated invalidDelegatedSignerFromIntermediate 'CN=Test Invalid Delegated Responder From Intermediate' testINT "--extKeyUsage ocspResponder"
make_delegated invalidDelegatedSignerKeyUsageCrlSigning 'CN=Test Invalid Delegated Responder keyUsage crlSigning' testCA "--keyUsage crlSigning"
make_delegated invalidDelegatedSignerWrongExtKeyUsage 'CN=Test Invalid Delegated Responder Wrong extKeyUsage' testCA "--extKeyUsage codeSigning"
make_INT self-signed-EE-with-cA-true 'CN=Test Self-signed End-entity with CA true' unused "-x -8 self-signed-end-entity-with-cA-true.example.com"
cleanup

View File

@ -55,7 +55,9 @@ GetOCSPResponseForType(OCSPResponseType aORT, CERTCertificate *aCert,
PrintPRError("CERT_FindCertIssuer failed");
return nullptr;
}
if (aORT == ORTGoodOtherCA) {
if (aORT == ORTGoodOtherCA || aORT == ORTDelegatedIncluded ||
aORT == ORTDelegatedIncludedLast || aORT == ORTDelegatedMissing ||
aORT == ORTDelegatedMissingMultiple) {
context.signerCert = PK11_FindCertFromNickname(aAdditionalCertName,
nullptr);
if (!context.signerCert) {
@ -63,6 +65,21 @@ GetOCSPResponseForType(OCSPResponseType aORT, CERTCertificate *aCert,
return nullptr;
}
}
if (aORT == ORTDelegatedIncluded) {
context.includedCertificates[0] =
CERT_DupCertificate(context.signerCert.get());
}
if (aORT == ORTDelegatedIncludedLast || aORT == ORTDelegatedMissingMultiple) {
context.includedCertificates[0] =
CERT_DupCertificate(context.issuerCert.get());
context.includedCertificates[1] = CERT_DupCertificate(context.cert.get());
context.includedCertificates[2] =
CERT_DupCertificate(context.issuerCert.get());
if (aORT != ORTDelegatedMissingMultiple) {
context.includedCertificates[3] =
CERT_DupCertificate(context.signerCert.get());
}
}
switch (aORT) {
case ORTMalformed:
context.responseStatus = 1;

View File

@ -31,7 +31,11 @@ enum OCSPResponseType
ORTBadSignature, // the response has a signature that does not verify
ORTSkipResponseBytes, // the response does not include responseBytes
ORTCriticalExtension, // the response includes a critical extension
ORTNoncriticalExtension // the response includes an extension that is not critical
ORTNoncriticalExtension, // the response includes an extension that is not critical
ORTDelegatedIncluded, // the response is signed by an included delegated responder
ORTDelegatedIncludedLast, // same, but multiple other certificates are included
ORTDelegatedMissing, // the response is signed by a not included delegated responder
ORTDelegatedMissingMultiple, // same, but multiple other certificates are included
};
struct OCSPHost

View File

@ -131,6 +131,9 @@ OCSPResponseContext::OCSPResponseContext(PLArenaPool* arena,
, responderIDType(ByKeyHash)
, extensions(nullptr)
{
for (size_t i = 0; i < MaxIncludedCertificates; i++) {
includedCertificates[i] = nullptr;
}
}
static SECItem* ResponseBytes(OCSPResponseContext& context);
@ -141,6 +144,7 @@ static SECItem* KeyHash(OCSPResponseContext& context);
static SECItem* SingleResponse(OCSPResponseContext& context);
static SECItem* CertID(OCSPResponseContext& context);
static SECItem* CertStatus(OCSPResponseContext& context);
static SECItem* Certificates(OCSPResponseContext& context);
static SECItem*
EncodeNested(PLArenaPool* arena, uint8_t tag, SECItem* inner)
@ -385,8 +389,22 @@ BasicOCSPResponse(OCSPResponseContext& context)
if (!signatureNested) {
return nullptr;
}
SECItem* certificatesNested = nullptr;
if (context.includedCertificates[0]) {
SECItem* certificates = Certificates(context);
if (!certificates) {
return nullptr;
}
certificatesNested = EncodeNested(context.arena,
der::CONSTRUCTED |
der::CONTEXT_SPECIFIC |
0,
certificates);
if (!certificatesNested) {
return nullptr;
}
}
// TODO(bug 980538): certificates
Output output;
if (output.Add(tbsResponseData) != der::Success) {
return nullptr;
@ -397,6 +415,11 @@ BasicOCSPResponse(OCSPResponseContext& context)
if (output.Add(signatureNested) != der::Success) {
return nullptr;
}
if (certificatesNested) {
if (output.Add(certificatesNested) != der::Success) {
return nullptr;
}
}
return output.Squash(context.arena, der::SEQUENCE);
}
@ -704,4 +727,19 @@ CertStatus(OCSPResponseContext& context)
return nullptr;
}
// SEQUENCE OF Certificate
SECItem*
Certificates(OCSPResponseContext& context)
{
Output output;
for (size_t i = 0; i < context.MaxIncludedCertificates; i++) {
CERTCertificate* cert = context.includedCertificates[i].get();
if (!cert) {
break;
}
output.Add(&cert->derCert);
}
return output.Squash(context.arena, der::SEQUENCE);
}
} } } // namespace mozilla::pkix::test

View File

@ -46,6 +46,9 @@ public:
uint8_t responseStatus; // See the OCSPResponseStatus enum in rfc 6960
bool skipResponseBytes; // If true, don't include responseBytes
static const uint32_t MaxIncludedCertificates = 4;
pkix::ScopedCERTCertificate includedCertificates[MaxIncludedCertificates];
// The following fields are on a per-SingleResponse basis. In the future we
// may support including multiple SingleResponses per response.
PRTime producedAt;