1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This code is made available to you under your choice of the following sets
4 * of licensing terms:
5 */
6 /* This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 */
10 /* Copyright 2014 Mozilla Contributors
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 * http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 */
24
25 #include "pkixgtest.h"
26
27 #include "mozpkix/pkixder.h"
28
29 #include "secoid.h"
30
31 using namespace mozilla::pkix;
32 using namespace mozilla::pkix::test;
33
34 const uint16_t END_ENTITY_MAX_LIFETIME_IN_DAYS = 10;
35
36 // Note that CheckRevocation is never called for OCSP signing certificates.
37 class OCSPTestTrustDomain : public DefaultCryptoTrustDomain
38 {
39 public:
OCSPTestTrustDomain()40 OCSPTestTrustDomain() { }
41
GetCertTrust(EndEntityOrCA endEntityOrCA,const CertPolicyId &,Input,TrustLevel & trustLevel)42 Result GetCertTrust(EndEntityOrCA endEntityOrCA, const CertPolicyId&,
43 Input, /*out*/ TrustLevel& trustLevel)
44 /*non-final*/ override
45 {
46 EXPECT_EQ(endEntityOrCA, EndEntityOrCA::MustBeEndEntity);
47 trustLevel = TrustLevel::InheritsTrust;
48 return Success;
49 }
50
NoteAuxiliaryExtension(AuxiliaryExtension extension,Input extensionData)51 virtual void NoteAuxiliaryExtension(AuxiliaryExtension extension,
52 Input extensionData) override
53 {
54 if (extension == AuxiliaryExtension::SCTListFromOCSPResponse) {
55 signedCertificateTimestamps = InputToByteString(extensionData);
56 } else {
57 // We do not currently expect to receive any other extension here.
58 ADD_FAILURE();
59 }
60 }
61
62 ByteString signedCertificateTimestamps;
63 };
64
65 namespace {
66 char const* const rootName = "Test CA 1";
67 } // namespace
68
69 class pkixocsp_VerifyEncodedResponse : public ::testing::Test
70 {
71 public:
SetUpTestSuite()72 static void SetUpTestSuite()
73 {
74 rootKeyPair.reset(GenerateKeyPair());
75 if (!rootKeyPair) {
76 abort();
77 }
78 }
79
SetUp()80 void SetUp()
81 {
82 rootNameDER = CNToDERName(rootName);
83 if (ENCODING_FAILED(rootNameDER)) {
84 abort();
85 }
86 Input rootNameDERInput;
87 if (rootNameDERInput.Init(rootNameDER.data(), rootNameDER.length())
88 != Success) {
89 abort();
90 }
91
92 serialNumberDER =
93 CreateEncodedSerialNumber(static_cast<long>(++rootIssuedCount));
94 if (ENCODING_FAILED(serialNumberDER)) {
95 abort();
96 }
97 Input serialNumberDERInput;
98 if (serialNumberDERInput.Init(serialNumberDER.data(),
99 serialNumberDER.length()) != Success) {
100 abort();
101 }
102
103 Input rootSPKIDER;
104 if (rootSPKIDER.Init(rootKeyPair->subjectPublicKeyInfo.data(),
105 rootKeyPair->subjectPublicKeyInfo.length())
106 != Success) {
107 abort();
108 }
109 endEntityCertID.reset(new (std::nothrow) CertID(rootNameDERInput, rootSPKIDER,
110 serialNumberDERInput));
111 if (!endEntityCertID) {
112 abort();
113 }
114 }
115
116 static ScopedTestKeyPair rootKeyPair;
117 static uint32_t rootIssuedCount;
118 OCSPTestTrustDomain trustDomain;
119
120 // endEntityCertID references rootKeyPair, rootNameDER, and serialNumberDER.
121 ByteString rootNameDER;
122 ByteString serialNumberDER;
123 // endEntityCertID references rootKeyPair, rootNameDER, and serialNumberDER.
124 ScopedCertID endEntityCertID;
125 };
126
127 /*static*/ ScopedTestKeyPair pkixocsp_VerifyEncodedResponse::rootKeyPair;
128 /*static*/ uint32_t pkixocsp_VerifyEncodedResponse::rootIssuedCount = 0;
129
130 ///////////////////////////////////////////////////////////////////////////////
131 // responseStatus
132
133 struct WithoutResponseBytes
134 {
135 uint8_t responseStatus;
136 Result expectedError;
137 };
138
139 static const WithoutResponseBytes WITHOUT_RESPONSEBYTES[] = {
140 { OCSPResponseContext::successful, Result::ERROR_OCSP_MALFORMED_RESPONSE },
141 { OCSPResponseContext::malformedRequest, Result::ERROR_OCSP_MALFORMED_REQUEST },
142 { OCSPResponseContext::internalError, Result::ERROR_OCSP_SERVER_ERROR },
143 { OCSPResponseContext::tryLater, Result::ERROR_OCSP_TRY_SERVER_LATER },
144 { 4/*unused*/, Result::ERROR_OCSP_UNKNOWN_RESPONSE_STATUS },
145 { OCSPResponseContext::sigRequired, Result::ERROR_OCSP_REQUEST_NEEDS_SIG },
146 { OCSPResponseContext::unauthorized, Result::ERROR_OCSP_UNAUTHORIZED_REQUEST },
147 { OCSPResponseContext::unauthorized + 1,
148 Result::ERROR_OCSP_UNKNOWN_RESPONSE_STATUS
149 },
150 };
151
152 class pkixocsp_VerifyEncodedResponse_WithoutResponseBytes
153 : public pkixocsp_VerifyEncodedResponse
154 , public ::testing::WithParamInterface<WithoutResponseBytes>
155 {
156 protected:
CreateEncodedOCSPErrorResponse(uint8_t status)157 ByteString CreateEncodedOCSPErrorResponse(uint8_t status)
158 {
159 static const Input EMPTY;
160 OCSPResponseContext context(CertID(EMPTY, EMPTY, EMPTY),
161 oneDayBeforeNow);
162 context.responseStatus = status;
163 context.skipResponseBytes = true;
164 return CreateEncodedOCSPResponse(context);
165 }
166 };
167
TEST_P(pkixocsp_VerifyEncodedResponse_WithoutResponseBytes,CorrectErrorCode)168 TEST_P(pkixocsp_VerifyEncodedResponse_WithoutResponseBytes, CorrectErrorCode)
169 {
170 ByteString
171 responseString(CreateEncodedOCSPErrorResponse(GetParam().responseStatus));
172 Input response;
173 ASSERT_EQ(Success,
174 response.Init(responseString.data(), responseString.length()));
175 bool expired;
176 ASSERT_EQ(GetParam().expectedError,
177 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
178 END_ENTITY_MAX_LIFETIME_IN_DAYS,
179 response, expired));
180 }
181
182 INSTANTIATE_TEST_SUITE_P(pkixocsp_VerifyEncodedResponse_WithoutResponseBytes,
183 pkixocsp_VerifyEncodedResponse_WithoutResponseBytes,
184 testing::ValuesIn(WITHOUT_RESPONSEBYTES));
185
186 ///////////////////////////////////////////////////////////////////////////////
187 // "successful" responses
188
189 namespace {
190
191 // Alias for nullptr to aid readability in the code below.
192 static const char* byKey = nullptr;
193
194 } // namespace
195
196 class pkixocsp_VerifyEncodedResponse_successful
197 : public pkixocsp_VerifyEncodedResponse
198 {
199 public:
SetUp()200 void SetUp()
201 {
202 pkixocsp_VerifyEncodedResponse::SetUp();
203 }
204
SetUpTestSuite()205 static void SetUpTestSuite()
206 {
207 pkixocsp_VerifyEncodedResponse::SetUpTestSuite();
208 }
209
CreateEncodedOCSPSuccessfulResponse(OCSPResponseContext::CertStatus certStatus,const CertID & certID,const char * signerName,const TestKeyPair & signerKeyPair,time_t producedAt,time_t thisUpdate,const time_t * nextUpdate,const TestSignatureAlgorithm & signatureAlgorithm,const ByteString * certs=nullptr,OCSPResponseExtension * singleExtensions=nullptr,OCSPResponseExtension * responseExtensions=nullptr,DigestAlgorithm certIDHashAlgorithm=DigestAlgorithm::sha1,ByteString certIDHashAlgorithmEncoded=ByteString ())210 ByteString CreateEncodedOCSPSuccessfulResponse(
211 OCSPResponseContext::CertStatus certStatus,
212 const CertID& certID,
213 /*optional*/ const char* signerName,
214 const TestKeyPair& signerKeyPair,
215 time_t producedAt, time_t thisUpdate,
216 /*optional*/ const time_t* nextUpdate,
217 const TestSignatureAlgorithm& signatureAlgorithm,
218 /*optional*/ const ByteString* certs = nullptr,
219 /*optional*/ OCSPResponseExtension* singleExtensions = nullptr,
220 /*optional*/ OCSPResponseExtension* responseExtensions = nullptr,
221 /*optional*/ DigestAlgorithm certIDHashAlgorithm = DigestAlgorithm::sha1,
222 /*optional*/ ByteString certIDHashAlgorithmEncoded = ByteString())
223 {
224 OCSPResponseContext context(certID, producedAt);
225 context.certIDHashAlgorithm = certIDHashAlgorithm;
226 context.certIDHashAlgorithmEncoded = certIDHashAlgorithmEncoded;
227 if (signerName) {
228 context.signerNameDER = CNToDERName(signerName);
229 EXPECT_FALSE(ENCODING_FAILED(context.signerNameDER));
230 }
231 context.signerKeyPair.reset(signerKeyPair.Clone());
232 EXPECT_TRUE(context.signerKeyPair.get());
233 context.responseStatus = OCSPResponseContext::successful;
234 context.producedAt = producedAt;
235 context.signatureAlgorithm = signatureAlgorithm;
236 context.certs = certs;
237 context.singleExtensions = singleExtensions;
238 context.responseExtensions = responseExtensions;
239
240 context.certStatus = static_cast<uint8_t>(certStatus);
241 context.thisUpdate = thisUpdate;
242 context.nextUpdate = nextUpdate ? *nextUpdate : 0;
243 context.includeNextUpdate = nextUpdate != nullptr;
244
245 return CreateEncodedOCSPResponse(context);
246 }
247 };
248
TEST_F(pkixocsp_VerifyEncodedResponse_successful,good_byKey)249 TEST_F(pkixocsp_VerifyEncodedResponse_successful, good_byKey)
250 {
251 ByteString responseString(
252 CreateEncodedOCSPSuccessfulResponse(
253 OCSPResponseContext::good, *endEntityCertID, byKey,
254 *rootKeyPair, oneDayBeforeNow,
255 oneDayBeforeNow, &oneDayAfterNow,
256 sha256WithRSAEncryption()));
257 Input response;
258 ASSERT_EQ(Success,
259 response.Init(responseString.data(), responseString.length()));
260 bool expired;
261 ASSERT_EQ(Success,
262 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID,
263 Now(), END_ENTITY_MAX_LIFETIME_IN_DAYS,
264 response, expired));
265 ASSERT_FALSE(expired);
266 }
267
TEST_F(pkixocsp_VerifyEncodedResponse_successful,good_byName)268 TEST_F(pkixocsp_VerifyEncodedResponse_successful, good_byName)
269 {
270 ByteString responseString(
271 CreateEncodedOCSPSuccessfulResponse(
272 OCSPResponseContext::good, *endEntityCertID, rootName,
273 *rootKeyPair, oneDayBeforeNow,
274 oneDayBeforeNow, &oneDayAfterNow,
275 sha256WithRSAEncryption()));
276 Input response;
277 ASSERT_EQ(Success,
278 response.Init(responseString.data(), responseString.length()));
279 bool expired;
280 ASSERT_EQ(Success,
281 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
282 END_ENTITY_MAX_LIFETIME_IN_DAYS,
283 response, expired));
284 ASSERT_FALSE(expired);
285 }
286
TEST_F(pkixocsp_VerifyEncodedResponse_successful,good_byKey_without_nextUpdate)287 TEST_F(pkixocsp_VerifyEncodedResponse_successful, good_byKey_without_nextUpdate)
288 {
289 ByteString responseString(
290 CreateEncodedOCSPSuccessfulResponse(
291 OCSPResponseContext::good, *endEntityCertID, byKey,
292 *rootKeyPair, oneDayBeforeNow,
293 oneDayBeforeNow, nullptr,
294 sha256WithRSAEncryption()));
295 Input response;
296 ASSERT_EQ(Success,
297 response.Init(responseString.data(), responseString.length()));
298 bool expired;
299 ASSERT_EQ(Success,
300 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
301 END_ENTITY_MAX_LIFETIME_IN_DAYS,
302 response, expired));
303 ASSERT_FALSE(expired);
304 }
305
TEST_F(pkixocsp_VerifyEncodedResponse_successful,revoked)306 TEST_F(pkixocsp_VerifyEncodedResponse_successful, revoked)
307 {
308 ByteString responseString(
309 CreateEncodedOCSPSuccessfulResponse(
310 OCSPResponseContext::revoked, *endEntityCertID, byKey,
311 *rootKeyPair, oneDayBeforeNow,
312 oneDayBeforeNow, &oneDayAfterNow,
313 sha256WithRSAEncryption()));
314 Input response;
315 ASSERT_EQ(Success,
316 response.Init(responseString.data(), responseString.length()));
317 bool expired;
318 ASSERT_EQ(Result::ERROR_REVOKED_CERTIFICATE,
319 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
320 END_ENTITY_MAX_LIFETIME_IN_DAYS,
321 response, expired));
322 ASSERT_FALSE(expired);
323 }
324
TEST_F(pkixocsp_VerifyEncodedResponse_successful,unknown)325 TEST_F(pkixocsp_VerifyEncodedResponse_successful, unknown)
326 {
327 ByteString responseString(
328 CreateEncodedOCSPSuccessfulResponse(
329 OCSPResponseContext::unknown, *endEntityCertID, byKey,
330 *rootKeyPair, oneDayBeforeNow,
331 oneDayBeforeNow, &oneDayAfterNow,
332 sha256WithRSAEncryption()));
333 Input response;
334 ASSERT_EQ(Success,
335 response.Init(responseString.data(), responseString.length()));
336 bool expired;
337 ASSERT_EQ(Result::ERROR_OCSP_UNKNOWN_CERT,
338 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
339 END_ENTITY_MAX_LIFETIME_IN_DAYS,
340 response, expired));
341 ASSERT_FALSE(expired);
342 }
343
TEST_F(pkixocsp_VerifyEncodedResponse_successful,good_unsupportedSignatureAlgorithm)344 TEST_F(pkixocsp_VerifyEncodedResponse_successful,
345 good_unsupportedSignatureAlgorithm)
346 {
347 PRUint32 policyMd5;
348 ASSERT_EQ(SECSuccess,NSS_GetAlgorithmPolicy(SEC_OID_MD5, &policyMd5));
349
350 /* our encode won't work if MD5 isn't allowed by policy */
351 ASSERT_EQ(SECSuccess,
352 NSS_SetAlgorithmPolicy(SEC_OID_MD5, NSS_USE_ALG_IN_SIGNATURE, 0));
353 ByteString responseString(
354 CreateEncodedOCSPSuccessfulResponse(
355 OCSPResponseContext::good, *endEntityCertID, byKey,
356 *rootKeyPair, oneDayBeforeNow,
357 oneDayBeforeNow, &oneDayAfterNow,
358 md5WithRSAEncryption()));
359 Input response;
360 ASSERT_EQ(Success,
361 response.Init(responseString.data(), responseString.length()));
362 /* now restore the existing policy */
363 ASSERT_EQ(SECSuccess,
364 NSS_SetAlgorithmPolicy(SEC_OID_MD5, policyMd5, NSS_USE_ALG_IN_SIGNATURE));
365 bool expired;
366 ASSERT_EQ(Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED,
367 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID,
368 Now(), END_ENTITY_MAX_LIFETIME_IN_DAYS,
369 response, expired));
370 ASSERT_FALSE(expired);
371 }
372
373 // Added for bug 1079436. The output variable validThrough represents the
374 // latest time for which VerifyEncodedOCSPResponse will succeed, which is
375 // different from the nextUpdate time in the OCSP response due to the slop we
376 // add for time comparisons to deal with clock skew.
TEST_F(pkixocsp_VerifyEncodedResponse_successful,check_validThrough)377 TEST_F(pkixocsp_VerifyEncodedResponse_successful, check_validThrough)
378 {
379 ByteString responseString(
380 CreateEncodedOCSPSuccessfulResponse(
381 OCSPResponseContext::good, *endEntityCertID, byKey,
382 *rootKeyPair, oneDayBeforeNow,
383 oneDayBeforeNow, &oneDayAfterNow,
384 sha256WithRSAEncryption()));
385 Time validThrough(Time::uninitialized);
386 {
387 Input response;
388 ASSERT_EQ(Success,
389 response.Init(responseString.data(), responseString.length()));
390 bool expired;
391 ASSERT_EQ(Success,
392 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID,
393 Now(), END_ENTITY_MAX_LIFETIME_IN_DAYS,
394 response, expired, nullptr,
395 &validThrough));
396 ASSERT_FALSE(expired);
397 // The response was created to be valid until one day after now, so the
398 // value we got for validThrough should be after that.
399 Time oneDayAfterNowAsPKIXTime(
400 TimeFromEpochInSeconds(static_cast<uint64_t>(oneDayAfterNow)));
401 ASSERT_TRUE(validThrough > oneDayAfterNowAsPKIXTime);
402 }
403 {
404 Input response;
405 ASSERT_EQ(Success,
406 response.Init(responseString.data(), responseString.length()));
407 bool expired;
408 // Given validThrough from a previous verification, this response should be
409 // valid through that time.
410 ASSERT_EQ(Success,
411 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID,
412 validThrough, END_ENTITY_MAX_LIFETIME_IN_DAYS,
413 response, expired));
414 ASSERT_FALSE(expired);
415 }
416 {
417 Time noLongerValid(validThrough);
418 ASSERT_EQ(Success, noLongerValid.AddSeconds(1));
419 Input response;
420 ASSERT_EQ(Success,
421 response.Init(responseString.data(), responseString.length()));
422 bool expired;
423 // The verification time is now after when the response will be considered
424 // valid.
425 ASSERT_EQ(Result::ERROR_OCSP_OLD_RESPONSE,
426 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID,
427 noLongerValid, END_ENTITY_MAX_LIFETIME_IN_DAYS,
428 response, expired));
429 ASSERT_TRUE(expired);
430 }
431 }
432
TEST_F(pkixocsp_VerifyEncodedResponse_successful,ct_extension)433 TEST_F(pkixocsp_VerifyEncodedResponse_successful, ct_extension)
434 {
435 // python DottedOIDToCode.py --tlv
436 // id_ocsp_singleExtensionSctList 1.3.6.1.4.1.11129.2.4.5
437 static const uint8_t tlv_id_ocsp_singleExtensionSctList[] = {
438 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x04, 0x05
439 };
440 static const uint8_t dummySctList[] = {
441 0x01, 0x02, 0x03, 0x04, 0x05
442 };
443
444 OCSPResponseExtension ctExtension;
445 ctExtension.id = BytesToByteString(tlv_id_ocsp_singleExtensionSctList);
446 // SignedCertificateTimestampList structure is encoded as an OCTET STRING
447 // within the extension value (see RFC 6962 section 3.3).
448 // pkix decodes it internally and returns the actual structure.
449 ctExtension.value = TLV(der::OCTET_STRING, BytesToByteString(dummySctList));
450
451 ByteString responseString(
452 CreateEncodedOCSPSuccessfulResponse(
453 OCSPResponseContext::good, *endEntityCertID, byKey,
454 *rootKeyPair, oneDayBeforeNow,
455 oneDayBeforeNow, &oneDayAfterNow,
456 sha256WithRSAEncryption(),
457 /*certs*/ nullptr,
458 &ctExtension));
459 Input response;
460 ASSERT_EQ(Success,
461 response.Init(responseString.data(), responseString.length()));
462
463 bool expired;
464 ASSERT_EQ(Success,
465 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID,
466 Now(), END_ENTITY_MAX_LIFETIME_IN_DAYS,
467 response, expired));
468 ASSERT_FALSE(expired);
469 ASSERT_EQ(BytesToByteString(dummySctList),
470 trustDomain.signedCertificateTimestamps);
471 }
472
473 struct CertIDHashAlgorithm
474 {
475 DigestAlgorithm hashAlgorithm;
476 ByteString encodedHashAlgorithm;
477 Result expectedResult;
478 };
479
480 // python DottedOIDToCode.py --alg id-sha1 1.3.14.3.2.26
481 static const uint8_t alg_id_sha1[] = {
482 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a
483 };
484 // python DottedOIDToCode.py --alg id-sha256 2.16.840.1.101.3.4.2.1
485 static const uint8_t alg_id_sha256[] = {
486 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
487 };
488 static const uint8_t not_an_encoded_hash_oid[] = {
489 0x01, 0x02, 0x03, 0x04
490 };
491
492 static const CertIDHashAlgorithm CERTID_HASH_ALGORITHMS[] = {
493 { DigestAlgorithm::sha1, ByteString(), Success },
494 { DigestAlgorithm::sha256, ByteString(), Success },
495 { DigestAlgorithm::sha384, ByteString(), Success },
496 { DigestAlgorithm::sha512, ByteString(), Success },
497 { DigestAlgorithm::sha256, BytesToByteString(alg_id_sha1),
498 Result::ERROR_OCSP_MALFORMED_RESPONSE },
499 { DigestAlgorithm::sha1, BytesToByteString(alg_id_sha256),
500 Result::ERROR_OCSP_MALFORMED_RESPONSE },
501 { DigestAlgorithm::sha1, BytesToByteString(not_an_encoded_hash_oid),
502 Result::ERROR_OCSP_MALFORMED_RESPONSE },
503 };
504
505 class pkixocsp_VerifyEncodedResponse_CertIDHashAlgorithm
506 : public pkixocsp_VerifyEncodedResponse_successful
507 , public ::testing::WithParamInterface<CertIDHashAlgorithm>
508 {
509 };
510
TEST_P(pkixocsp_VerifyEncodedResponse_CertIDHashAlgorithm,CertIDHashAlgorithm)511 TEST_P(pkixocsp_VerifyEncodedResponse_CertIDHashAlgorithm, CertIDHashAlgorithm)
512 {
513 ByteString responseString(
514 CreateEncodedOCSPSuccessfulResponse(
515 OCSPResponseContext::good, *endEntityCertID, byKey,
516 *rootKeyPair, oneDayBeforeNow,
517 oneDayBeforeNow, &oneDayAfterNow,
518 sha256WithRSAEncryption(),
519 nullptr,
520 nullptr,
521 nullptr,
522 GetParam().hashAlgorithm,
523 GetParam().encodedHashAlgorithm));
524 Input response;
525 ASSERT_EQ(Success,
526 response.Init(responseString.data(), responseString.length()));
527 bool expired;
528 ASSERT_EQ(GetParam().expectedResult,
529 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID,
530 Now(), END_ENTITY_MAX_LIFETIME_IN_DAYS,
531 response, expired));
532 ASSERT_FALSE(expired);
533 }
534
535 INSTANTIATE_TEST_SUITE_P(pkixocsp_VerifyEncodedResponse_CertIDHashAlgorithm,
536 pkixocsp_VerifyEncodedResponse_CertIDHashAlgorithm,
537 testing::ValuesIn(CERTID_HASH_ALGORITHMS));
538
539 ///////////////////////////////////////////////////////////////////////////////
540 // indirect responses (signed by a delegated OCSP responder cert)
541
542 class pkixocsp_VerifyEncodedResponse_DelegatedResponder
543 : public pkixocsp_VerifyEncodedResponse_successful
544 {
545 protected:
546 // certSubjectName should be unique for each call. This way, we avoid any
547 // issues with NSS caching the certificates internally. For the same reason,
548 // we generate a new keypair on each call. Either one of these should be
549 // sufficient to avoid issues with the NSS cache, but we do both to be
550 // cautious.
551 //
552 // signerName should be byKey to use the byKey ResponderID construction, or
553 // another value (usually equal to certSubjectName) to use the byName
554 // ResponderID construction.
555 //
556 // certSignatureAlgorithm specifies the signature algorithm that the
557 // certificate will be signed with, not the OCSP response.
558 //
559 // If signerEKU is omitted, then the certificate will have the
560 // id-kp-OCSPSigning EKU. If signerEKU is SEC_OID_UNKNOWN then it will not
561 // have any EKU extension. Otherwise, the certificate will have the given
562 // EKU.
CreateEncodedIndirectOCSPSuccessfulResponse(const char * certSubjectName,OCSPResponseContext::CertStatus certStatus,const char * signerName,const TestSignatureAlgorithm & certSignatureAlgorithm,const Input * signerEKUDER=& OCSPSigningEKUDER,ByteString * signerDEROut=nullptr)563 ByteString CreateEncodedIndirectOCSPSuccessfulResponse(
564 const char* certSubjectName,
565 OCSPResponseContext::CertStatus certStatus,
566 const char* signerName,
567 const TestSignatureAlgorithm& certSignatureAlgorithm,
568 /*optional*/ const Input* signerEKUDER = &OCSPSigningEKUDER,
569 /*optional, out*/ ByteString* signerDEROut = nullptr)
570 {
571 assert(certSubjectName);
572
573 const ByteString extensions[] = {
574 signerEKUDER
575 ? CreateEncodedEKUExtension(*signerEKUDER, Critical::No)
576 : ByteString(),
577 ByteString()
578 };
579 ScopedTestKeyPair signerKeyPair(GenerateKeyPair());
580 ByteString signerDER(CreateEncodedCertificate(
581 ++rootIssuedCount, certSignatureAlgorithm,
582 rootName, oneDayBeforeNow, oneDayAfterNow,
583 certSubjectName, *signerKeyPair,
584 signerEKUDER ? extensions : nullptr,
585 *rootKeyPair));
586 EXPECT_FALSE(ENCODING_FAILED(signerDER));
587 if (signerDEROut) {
588 *signerDEROut = signerDER;
589 }
590
591 ByteString signerNameDER;
592 if (signerName) {
593 signerNameDER = CNToDERName(signerName);
594 EXPECT_FALSE(ENCODING_FAILED(signerNameDER));
595 }
596 ByteString certs[] = { signerDER, ByteString() };
597 return CreateEncodedOCSPSuccessfulResponse(certStatus, *endEntityCertID,
598 signerName, *signerKeyPair,
599 oneDayBeforeNow,
600 oneDayBeforeNow,
601 &oneDayAfterNow,
602 sha256WithRSAEncryption(),
603 certs);
604 }
605
CreateEncodedCertificate(uint32_t serialNumber,const TestSignatureAlgorithm & signatureAlg,const char * issuer,time_t notBefore,time_t notAfter,const char * subject,const TestKeyPair & subjectKeyPair,const ByteString * extensions,const TestKeyPair & signerKeyPair)606 static ByteString CreateEncodedCertificate(uint32_t serialNumber,
607 const TestSignatureAlgorithm& signatureAlg,
608 const char* issuer,
609 time_t notBefore,
610 time_t notAfter,
611 const char* subject,
612 const TestKeyPair& subjectKeyPair,
613 /*optional*/ const ByteString* extensions,
614 const TestKeyPair& signerKeyPair)
615 {
616 ByteString serialNumberDER(CreateEncodedSerialNumber(
617 static_cast<long>(serialNumber)));
618 if (ENCODING_FAILED(serialNumberDER)) {
619 return ByteString();
620 }
621 ByteString issuerDER(CNToDERName(issuer));
622 if (ENCODING_FAILED(issuerDER)) {
623 return ByteString();
624 }
625 ByteString subjectDER(CNToDERName(subject));
626 if (ENCODING_FAILED(subjectDER)) {
627 return ByteString();
628 }
629 return ::mozilla::pkix::test::CreateEncodedCertificate(
630 v3, signatureAlg, serialNumberDER,
631 issuerDER, notBefore, notAfter,
632 subjectDER, subjectKeyPair, extensions,
633 signerKeyPair, signatureAlg);
634 }
635
636 static const Input OCSPSigningEKUDER;
637 };
638
639 /*static*/ const Input pkixocsp_VerifyEncodedResponse_DelegatedResponder::
640 OCSPSigningEKUDER(tlv_id_kp_OCSPSigning);
641
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,good_byKey)642 TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_byKey)
643 {
644 ByteString responseString(
645 CreateEncodedIndirectOCSPSuccessfulResponse(
646 "good_indirect_byKey", OCSPResponseContext::good,
647 byKey, sha256WithRSAEncryption()));
648 Input response;
649 ASSERT_EQ(Success,
650 response.Init(responseString.data(), responseString.length()));
651 bool expired;
652 ASSERT_EQ(Success,
653 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
654 END_ENTITY_MAX_LIFETIME_IN_DAYS,
655 response, expired));
656 ASSERT_FALSE(expired);
657 }
658
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,good_byName)659 TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_byName)
660 {
661 ByteString responseString(
662 CreateEncodedIndirectOCSPSuccessfulResponse(
663 "good_indirect_byName", OCSPResponseContext::good,
664 "good_indirect_byName", sha256WithRSAEncryption()));
665 Input response;
666 ASSERT_EQ(Success,
667 response.Init(responseString.data(), responseString.length()));
668 bool expired;
669 ASSERT_EQ(Success,
670 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
671 END_ENTITY_MAX_LIFETIME_IN_DAYS,
672 response, expired));
673 ASSERT_FALSE(expired);
674 }
675
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,good_byKey_missing_signer)676 TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
677 good_byKey_missing_signer)
678 {
679 ScopedTestKeyPair missingSignerKeyPair(GenerateKeyPair());
680 ASSERT_TRUE(missingSignerKeyPair.get());
681
682 ByteString responseString(
683 CreateEncodedOCSPSuccessfulResponse(
684 OCSPResponseContext::good, *endEntityCertID, byKey,
685 *missingSignerKeyPair, oneDayBeforeNow,
686 oneDayBeforeNow, nullptr,
687 sha256WithRSAEncryption()));
688 Input response;
689 ASSERT_EQ(Success,
690 response.Init(responseString.data(), responseString.length()));
691 bool expired;
692 ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
693 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
694 END_ENTITY_MAX_LIFETIME_IN_DAYS,
695 response, expired));
696 ASSERT_FALSE(expired);
697 }
698
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,good_byName_missing_signer)699 TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
700 good_byName_missing_signer)
701 {
702 ScopedTestKeyPair missingSignerKeyPair(GenerateKeyPair());
703 ASSERT_TRUE(missingSignerKeyPair.get());
704 ByteString responseString(
705 CreateEncodedOCSPSuccessfulResponse(
706 OCSPResponseContext::good, *endEntityCertID,
707 "missing", *missingSignerKeyPair,
708 oneDayBeforeNow, oneDayBeforeNow, nullptr,
709 sha256WithRSAEncryption()));
710 Input response;
711 ASSERT_EQ(Success,
712 response.Init(responseString.data(), responseString.length()));
713 bool expired;
714 ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
715 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
716 END_ENTITY_MAX_LIFETIME_IN_DAYS,
717 response, expired));
718 ASSERT_FALSE(expired);
719 }
720
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,good_expired)721 TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_expired)
722 {
723 static const char* signerName = "good_indirect_expired";
724
725 const ByteString extensions[] = {
726 CreateEncodedEKUExtension(OCSPSigningEKUDER, Critical::No),
727 ByteString()
728 };
729
730 ScopedTestKeyPair signerKeyPair(GenerateKeyPair());
731 ByteString signerDER(CreateEncodedCertificate(
732 ++rootIssuedCount, sha256WithRSAEncryption(),
733 rootName,
734 tenDaysBeforeNow,
735 twoDaysBeforeNow,
736 signerName, *signerKeyPair, extensions,
737 *rootKeyPair));
738 ASSERT_FALSE(ENCODING_FAILED(signerDER));
739
740 ByteString certs[] = { signerDER, ByteString() };
741 ByteString responseString(
742 CreateEncodedOCSPSuccessfulResponse(
743 OCSPResponseContext::good, *endEntityCertID,
744 signerName, *signerKeyPair, oneDayBeforeNow,
745 oneDayBeforeNow, &oneDayAfterNow,
746 sha256WithRSAEncryption(), certs));
747 Input response;
748 ASSERT_EQ(Success,
749 response.Init(responseString.data(), responseString.length()));
750 bool expired;
751 ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
752 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
753 END_ENTITY_MAX_LIFETIME_IN_DAYS,
754 response, expired));
755 }
756
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,good_future)757 TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_future)
758 {
759 static const char* signerName = "good_indirect_future";
760
761 const ByteString extensions[] = {
762 CreateEncodedEKUExtension(OCSPSigningEKUDER, Critical::No),
763 ByteString()
764 };
765
766 ScopedTestKeyPair signerKeyPair(GenerateKeyPair());
767 ByteString signerDER(CreateEncodedCertificate(
768 ++rootIssuedCount, sha256WithRSAEncryption(),
769 rootName,
770 twoDaysAfterNow,
771 tenDaysAfterNow,
772 signerName, *signerKeyPair, extensions,
773 *rootKeyPair));
774 ASSERT_FALSE(ENCODING_FAILED(signerDER));
775
776 ByteString certs[] = { signerDER, ByteString() };
777 ByteString responseString(
778 CreateEncodedOCSPSuccessfulResponse(
779 OCSPResponseContext::good, *endEntityCertID,
780 signerName, *signerKeyPair, oneDayBeforeNow,
781 oneDayBeforeNow, &oneDayAfterNow,
782 sha256WithRSAEncryption(), certs));
783 Input response;
784 ASSERT_EQ(Success,
785 response.Init(responseString.data(), responseString.length()));
786 bool expired;
787 ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
788 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
789 END_ENTITY_MAX_LIFETIME_IN_DAYS,
790 response, expired));
791 ASSERT_FALSE(expired);
792 }
793
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,good_no_eku)794 TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_no_eku)
795 {
796 ByteString responseString(
797 CreateEncodedIndirectOCSPSuccessfulResponse(
798 "good_indirect_wrong_eku",
799 OCSPResponseContext::good, byKey,
800 sha256WithRSAEncryption(), nullptr));
801 Input response;
802 ASSERT_EQ(Success,
803 response.Init(responseString.data(), responseString.length()));
804 bool expired;
805 ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
806 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
807 END_ENTITY_MAX_LIFETIME_IN_DAYS,
808 response, expired));
809 ASSERT_FALSE(expired);
810 }
811
812 static const Input serverAuthEKUDER(tlv_id_kp_serverAuth);
813
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,good_indirect_wrong_eku)814 TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
815 good_indirect_wrong_eku)
816 {
817 ByteString responseString(
818 CreateEncodedIndirectOCSPSuccessfulResponse(
819 "good_indirect_wrong_eku",
820 OCSPResponseContext::good, byKey,
821 sha256WithRSAEncryption(), &serverAuthEKUDER));
822 Input response;
823 ASSERT_EQ(Success,
824 response.Init(responseString.data(), responseString.length()));
825 bool expired;
826 ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
827 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
828 END_ENTITY_MAX_LIFETIME_IN_DAYS,
829 response, expired));
830 ASSERT_FALSE(expired);
831 }
832
833 // Test that signature of OCSP response signer cert is verified
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,good_tampered_eku)834 TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_tampered_eku)
835 {
836 ByteString tamperedResponse(
837 CreateEncodedIndirectOCSPSuccessfulResponse(
838 "good_indirect_tampered_eku",
839 OCSPResponseContext::good, byKey,
840 sha256WithRSAEncryption(), &serverAuthEKUDER));
841 ASSERT_EQ(Success,
842 TamperOnce(tamperedResponse,
843 ByteString(tlv_id_kp_serverAuth,
844 sizeof(tlv_id_kp_serverAuth)),
845 ByteString(tlv_id_kp_OCSPSigning,
846 sizeof(tlv_id_kp_OCSPSigning))));
847 Input tamperedResponseInput;
848 ASSERT_EQ(Success, tamperedResponseInput.Init(tamperedResponse.data(),
849 tamperedResponse.length()));
850 bool expired;
851 ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
852 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
853 END_ENTITY_MAX_LIFETIME_IN_DAYS,
854 tamperedResponseInput, expired));
855 ASSERT_FALSE(expired);
856 }
857
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,good_unknown_issuer)858 TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_unknown_issuer)
859 {
860 static const char* subCAName = "good_indirect_unknown_issuer sub-CA";
861 static const char* signerName = "good_indirect_unknown_issuer OCSP signer";
862
863 // unknown issuer
864 ScopedTestKeyPair unknownKeyPair(GenerateKeyPair());
865 ASSERT_TRUE(unknownKeyPair.get());
866
867 // Delegated responder cert signed by unknown issuer
868 const ByteString extensions[] = {
869 CreateEncodedEKUExtension(OCSPSigningEKUDER, Critical::No),
870 ByteString()
871 };
872 ScopedTestKeyPair signerKeyPair(GenerateKeyPair());
873 ByteString signerDER(CreateEncodedCertificate(
874 1, sha256WithRSAEncryption(), subCAName,
875 oneDayBeforeNow, oneDayAfterNow, signerName,
876 *signerKeyPair, extensions, *unknownKeyPair));
877 ASSERT_FALSE(ENCODING_FAILED(signerDER));
878
879 // OCSP response signed by that delegated responder
880 ByteString certs[] = { signerDER, ByteString() };
881 ByteString responseString(
882 CreateEncodedOCSPSuccessfulResponse(
883 OCSPResponseContext::good, *endEntityCertID,
884 signerName, *signerKeyPair, oneDayBeforeNow,
885 oneDayBeforeNow, &oneDayAfterNow,
886 sha256WithRSAEncryption(), certs));
887 Input response;
888 ASSERT_EQ(Success,
889 response.Init(responseString.data(), responseString.length()));
890 bool expired;
891 ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
892 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
893 END_ENTITY_MAX_LIFETIME_IN_DAYS,
894 response, expired));
895 ASSERT_FALSE(expired);
896 }
897
898 // The CA that issued the OCSP responder cert is a sub-CA of the issuer of
899 // the certificate that the OCSP response is for. That sub-CA cert is included
900 // in the OCSP response before the OCSP responder cert.
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,good_indirect_subca_1_first)901 TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
902 good_indirect_subca_1_first)
903 {
904 static const char* subCAName = "good_indirect_subca_1_first sub-CA";
905 static const char* signerName = "good_indirect_subca_1_first OCSP signer";
906 static const long zero = 0;
907
908 // sub-CA of root (root is the direct issuer of endEntity)
909 const ByteString subCAExtensions[] = {
910 CreateEncodedBasicConstraints(true, &zero, Critical::No),
911 ByteString()
912 };
913 ScopedTestKeyPair subCAKeyPair(GenerateKeyPair());
914 ByteString subCADER(CreateEncodedCertificate(
915 ++rootIssuedCount, sha256WithRSAEncryption(), rootName,
916 oneDayBeforeNow, oneDayAfterNow, subCAName,
917 *subCAKeyPair, subCAExtensions, *rootKeyPair));
918 ASSERT_FALSE(ENCODING_FAILED(subCADER));
919
920 // Delegated responder cert signed by that sub-CA
921 const ByteString extensions[] = {
922 CreateEncodedEKUExtension(OCSPSigningEKUDER, Critical::No),
923 ByteString(),
924 };
925 ScopedTestKeyPair signerKeyPair(GenerateKeyPair());
926 ByteString signerDER(CreateEncodedCertificate(
927 1, sha256WithRSAEncryption(), subCAName,
928 oneDayBeforeNow, oneDayAfterNow, signerName,
929 *signerKeyPair, extensions, *subCAKeyPair));
930 ASSERT_FALSE(ENCODING_FAILED(signerDER));
931
932 // OCSP response signed by the delegated responder issued by the sub-CA
933 // that is trying to impersonate the root.
934 ByteString certs[] = { subCADER, signerDER, ByteString() };
935 ByteString responseString(
936 CreateEncodedOCSPSuccessfulResponse(
937 OCSPResponseContext::good, *endEntityCertID,
938 signerName, *signerKeyPair, oneDayBeforeNow,
939 oneDayBeforeNow, &oneDayAfterNow,
940 sha256WithRSAEncryption(), certs));
941 Input response;
942 ASSERT_EQ(Success,
943 response.Init(responseString.data(), responseString.length()));
944 bool expired;
945 ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
946 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
947 END_ENTITY_MAX_LIFETIME_IN_DAYS,
948 response, expired));
949 ASSERT_FALSE(expired);
950 }
951
952 // The CA that issued the OCSP responder cert is a sub-CA of the issuer of
953 // the certificate that the OCSP response is for. That sub-CA cert is included
954 // in the OCSP response after the OCSP responder cert.
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,good_indirect_subca_1_second)955 TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
956 good_indirect_subca_1_second)
957 {
958 static const char* subCAName = "good_indirect_subca_1_second sub-CA";
959 static const char* signerName = "good_indirect_subca_1_second OCSP signer";
960 static const long zero = 0;
961
962 // sub-CA of root (root is the direct issuer of endEntity)
963 const ByteString subCAExtensions[] = {
964 CreateEncodedBasicConstraints(true, &zero, Critical::No),
965 ByteString()
966 };
967 ScopedTestKeyPair subCAKeyPair(GenerateKeyPair());
968 ByteString subCADER(CreateEncodedCertificate(++rootIssuedCount,
969 sha256WithRSAEncryption(),
970 rootName,
971 oneDayBeforeNow, oneDayAfterNow,
972 subCAName, *subCAKeyPair,
973 subCAExtensions, *rootKeyPair));
974 ASSERT_FALSE(ENCODING_FAILED(subCADER));
975
976 // Delegated responder cert signed by that sub-CA
977 const ByteString extensions[] = {
978 CreateEncodedEKUExtension(OCSPSigningEKUDER, Critical::No),
979 ByteString()
980 };
981 ScopedTestKeyPair signerKeyPair(GenerateKeyPair());
982 ByteString signerDER(CreateEncodedCertificate(
983 1, sha256WithRSAEncryption(), subCAName,
984 oneDayBeforeNow, oneDayAfterNow, signerName,
985 *signerKeyPair, extensions, *subCAKeyPair));
986 ASSERT_FALSE(ENCODING_FAILED(signerDER));
987
988 // OCSP response signed by the delegated responder issued by the sub-CA
989 // that is trying to impersonate the root.
990 ByteString certs[] = { signerDER, subCADER, ByteString() };
991 ByteString responseString(
992 CreateEncodedOCSPSuccessfulResponse(
993 OCSPResponseContext::good, *endEntityCertID,
994 signerName, *signerKeyPair, oneDayBeforeNow,
995 oneDayBeforeNow, &oneDayAfterNow,
996 sha256WithRSAEncryption(), certs));
997 Input response;
998 ASSERT_EQ(Success,
999 response.Init(responseString.data(), responseString.length()));
1000 bool expired;
1001 ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
1002 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
1003 END_ENTITY_MAX_LIFETIME_IN_DAYS,
1004 response, expired));
1005 ASSERT_FALSE(expired);
1006 }
1007
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,good_unsupportedSignatureAlgorithmOnResponder)1008 TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
1009 good_unsupportedSignatureAlgorithmOnResponder)
1010 {
1011 // Note that the algorithm ID (md5WithRSAEncryption) identifies the signature
1012 // algorithm that will be used to sign the certificate that issues the OCSP
1013 // responses, not the responses themselves.
1014 PRUint32 policyMd5;
1015 ASSERT_EQ(SECSuccess,NSS_GetAlgorithmPolicy(SEC_OID_MD5, &policyMd5));
1016
1017 /* our encode won't work if MD5 isn't allowed by policy */
1018 ASSERT_EQ(SECSuccess,
1019 NSS_SetAlgorithmPolicy(SEC_OID_MD5, NSS_USE_ALG_IN_SIGNATURE, 0));
1020 ByteString responseString(
1021 CreateEncodedIndirectOCSPSuccessfulResponse(
1022 "good_indirect_unsupportedSignatureAlgorithm",
1023 OCSPResponseContext::good, byKey,
1024 md5WithRSAEncryption()));
1025 Input response;
1026 /* now restore the existing policy */
1027 ASSERT_EQ(Success,
1028 response.Init(responseString.data(), responseString.length()));
1029 ASSERT_EQ(SECSuccess,
1030 NSS_SetAlgorithmPolicy(SEC_OID_MD5, policyMd5, NSS_USE_ALG_IN_SIGNATURE));
1031 bool expired;
1032 ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
1033 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
1034 END_ENTITY_MAX_LIFETIME_IN_DAYS,
1035 response, expired));
1036 }
1037
1038 class pkixocsp_VerifyEncodedResponse_GetCertTrust
1039 : public pkixocsp_VerifyEncodedResponse_DelegatedResponder {
1040 public:
SetUp()1041 void SetUp()
1042 {
1043 pkixocsp_VerifyEncodedResponse_DelegatedResponder::SetUp();
1044
1045 responseString =
1046 CreateEncodedIndirectOCSPSuccessfulResponse(
1047 "OCSPGetCertTrustTest Signer", OCSPResponseContext::good,
1048 byKey, sha256WithRSAEncryption(), &OCSPSigningEKUDER,
1049 &signerCertDER);
1050 if (ENCODING_FAILED(responseString)) {
1051 abort();
1052 }
1053 if (response.Init(responseString.data(), responseString.length())
1054 != Success) {
1055 abort();
1056 }
1057 if (signerCertDER.length() == 0) {
1058 abort();
1059 }
1060 }
1061
1062 class TrustDomain final : public OCSPTestTrustDomain
1063 {
1064 public:
TrustDomain()1065 TrustDomain()
1066 : certTrustLevel(TrustLevel::InheritsTrust)
1067 {
1068 }
1069
SetCertTrust(const ByteString & aCertDER,TrustLevel aCertTrustLevel)1070 bool SetCertTrust(const ByteString& aCertDER, TrustLevel aCertTrustLevel)
1071 {
1072 this->certDER = aCertDER;
1073 this->certTrustLevel = aCertTrustLevel;
1074 return true;
1075 }
1076 private:
GetCertTrust(EndEntityOrCA endEntityOrCA,const CertPolicyId &,Input candidateCert,TrustLevel & trustLevel)1077 Result GetCertTrust(EndEntityOrCA endEntityOrCA, const CertPolicyId&,
1078 Input candidateCert, /*out*/ TrustLevel& trustLevel)
1079 override
1080 {
1081 EXPECT_EQ(endEntityOrCA, EndEntityOrCA::MustBeEndEntity);
1082 EXPECT_FALSE(certDER.empty());
1083 Input certDERInput;
1084 EXPECT_EQ(Success, certDERInput.Init(certDER.data(), certDER.length()));
1085 EXPECT_TRUE(InputsAreEqual(certDERInput, candidateCert));
1086 trustLevel = certTrustLevel;
1087 return Success;
1088 }
1089
1090 ByteString certDER;
1091 TrustLevel certTrustLevel;
1092 };
1093
1094 // trustDomain deliberately shadows the inherited field so that it isn't used
1095 // by accident. See bug 1339921.
1096 // Unfortunately GCC can't parse __has_warning("-Wshadow-field") even if it's
1097 // the latter part of a conjunction that would evaluate to false, so we have to
1098 // wrap it in a separate preprocessor conditional rather than using &&.
1099 #if defined(__clang__)
1100 #if __has_warning("-Wshadow-field")
1101 #pragma clang diagnostic push
1102 #pragma clang diagnostic ignored "-Wshadow-field"
1103 #endif
1104 #endif
1105 TrustDomain trustDomain;
1106 #if defined(__clang__)
1107 #if __has_warning("-Wshadow-field")
1108 #pragma clang diagnostic pop
1109 #endif
1110 #endif
1111 ByteString signerCertDER;
1112 ByteString responseString;
1113 Input response; // references data in responseString
1114 };
1115
TEST_F(pkixocsp_VerifyEncodedResponse_GetCertTrust,InheritTrust)1116 TEST_F(pkixocsp_VerifyEncodedResponse_GetCertTrust, InheritTrust)
1117 {
1118 ASSERT_TRUE(trustDomain.SetCertTrust(signerCertDER,
1119 TrustLevel::InheritsTrust));
1120 bool expired;
1121 ASSERT_EQ(Success,
1122 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
1123 END_ENTITY_MAX_LIFETIME_IN_DAYS,
1124 response, expired));
1125 ASSERT_FALSE(expired);
1126 }
1127
TEST_F(pkixocsp_VerifyEncodedResponse_GetCertTrust,TrustAnchor)1128 TEST_F(pkixocsp_VerifyEncodedResponse_GetCertTrust, TrustAnchor)
1129 {
1130 ASSERT_TRUE(trustDomain.SetCertTrust(signerCertDER,
1131 TrustLevel::TrustAnchor));
1132 bool expired;
1133 ASSERT_EQ(Success,
1134 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
1135 END_ENTITY_MAX_LIFETIME_IN_DAYS,
1136 response, expired));
1137 ASSERT_FALSE(expired);
1138 }
1139
TEST_F(pkixocsp_VerifyEncodedResponse_GetCertTrust,ActivelyDistrusted)1140 TEST_F(pkixocsp_VerifyEncodedResponse_GetCertTrust, ActivelyDistrusted)
1141 {
1142 ASSERT_TRUE(trustDomain.SetCertTrust(signerCertDER,
1143 TrustLevel::ActivelyDistrusted));
1144 Input responseInput;
1145 ASSERT_EQ(Success,
1146 responseInput.Init(responseString.data(),
1147 responseString.length()));
1148 bool expired;
1149 ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
1150 VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
1151 END_ENTITY_MAX_LIFETIME_IN_DAYS,
1152 responseInput, expired));
1153 ASSERT_FALSE(expired);
1154 }
1155