Line data Source code
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 Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "CertVerifier.h"
8 :
9 : #include <stdint.h>
10 :
11 : #include "CTDiversityPolicy.h"
12 : #include "CTKnownLogs.h"
13 : #include "CTLogVerifier.h"
14 : #include "ExtendedValidation.h"
15 : #include "MultiLogCTVerifier.h"
16 : #include "NSSCertDBTrustDomain.h"
17 : #include "NSSErrorsService.h"
18 : #include "cert.h"
19 : #include "mozilla/Assertions.h"
20 : #include "mozilla/Casting.h"
21 : #include "mozilla/IntegerPrintfMacros.h"
22 : #include "nsNSSComponent.h"
23 : #include "nsPromiseFlatString.h"
24 : #include "nsServiceManagerUtils.h"
25 : #include "pk11pub.h"
26 : #include "pkix/pkix.h"
27 : #include "pkix/pkixnss.h"
28 : #include "secmod.h"
29 :
30 : using namespace mozilla::ct;
31 : using namespace mozilla::pkix;
32 : using namespace mozilla::psm;
33 :
34 : mozilla::LazyLogModule gCertVerifierLog("certverifier");
35 :
36 : // Returns the certificate validity period in calendar months (rounded down).
37 : // "extern" to allow unit tests in CTPolicyEnforcerTest.cpp.
38 : extern mozilla::pkix::Result
39 0 : GetCertLifetimeInFullMonths(PRTime certNotBefore,
40 : PRTime certNotAfter,
41 : size_t& months)
42 : {
43 0 : if (certNotBefore >= certNotAfter) {
44 0 : MOZ_ASSERT_UNREACHABLE("Expected notBefore < notAfter");
45 : return mozilla::pkix::Result::FATAL_ERROR_INVALID_ARGS;
46 : }
47 :
48 : PRExplodedTime explodedNotBefore;
49 : PRExplodedTime explodedNotAfter;
50 :
51 0 : PR_ExplodeTime(certNotBefore, PR_LocalTimeParameters, &explodedNotBefore);
52 0 : PR_ExplodeTime(certNotAfter, PR_LocalTimeParameters, &explodedNotAfter);
53 :
54 : PRInt32 signedMonths =
55 0 : (explodedNotAfter.tm_year - explodedNotBefore.tm_year) * 12 +
56 0 : (explodedNotAfter.tm_month - explodedNotBefore.tm_month);
57 0 : if (explodedNotAfter.tm_mday < explodedNotBefore.tm_mday) {
58 0 : --signedMonths;
59 : }
60 :
61 : // Can't use `mozilla::AssertedCast<size_t>(signedMonths)` below
62 : // since it currently generates a warning on Win x64 debug.
63 0 : if (signedMonths < 0) {
64 0 : MOZ_ASSERT_UNREACHABLE("Expected explodedNotBefore < explodedNotAfter");
65 : return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE;
66 : }
67 0 : months = static_cast<size_t>(signedMonths);
68 :
69 0 : return Success;
70 : }
71 :
72 : namespace mozilla { namespace psm {
73 :
74 : const CertVerifier::Flags CertVerifier::FLAG_LOCAL_ONLY = 1;
75 : const CertVerifier::Flags CertVerifier::FLAG_MUST_BE_EV = 2;
76 : const CertVerifier::Flags CertVerifier::FLAG_TLS_IGNORE_STATUS_REQUEST = 4;
77 :
78 : void
79 0 : CertificateTransparencyInfo::Reset()
80 : {
81 0 : enabled = false;
82 0 : verifyResult.Reset();
83 0 : policyCompliance = CTPolicyCompliance::Unknown;
84 0 : }
85 :
86 1 : CertVerifier::CertVerifier(OcspDownloadConfig odc,
87 : OcspStrictConfig osc,
88 : OcspGetConfig ogc,
89 : mozilla::TimeDuration ocspTimeoutSoft,
90 : mozilla::TimeDuration ocspTimeoutHard,
91 : uint32_t certShortLifetimeInDays,
92 : PinningMode pinningMode,
93 : SHA1Mode sha1Mode,
94 : BRNameMatchingPolicy::Mode nameMatchingMode,
95 : NetscapeStepUpPolicy netscapeStepUpPolicy,
96 1 : CertificateTransparencyMode ctMode)
97 : : mOCSPDownloadConfig(odc)
98 1 : , mOCSPStrict(osc == ocspStrict)
99 1 : , mOCSPGETEnabled(ogc == ocspGetEnabled)
100 : , mOCSPTimeoutSoft(ocspTimeoutSoft)
101 : , mOCSPTimeoutHard(ocspTimeoutHard)
102 : , mCertShortLifetimeInDays(certShortLifetimeInDays)
103 : , mPinningMode(pinningMode)
104 : , mSHA1Mode(sha1Mode)
105 : , mNameMatchingMode(nameMatchingMode)
106 : , mNetscapeStepUpPolicy(netscapeStepUpPolicy)
107 3 : , mCTMode(ctMode)
108 : {
109 1 : LoadKnownCTLogs();
110 1 : }
111 :
112 0 : CertVerifier::~CertVerifier()
113 : {
114 0 : }
115 :
116 : Result
117 0 : IsCertChainRootBuiltInRoot(const UniqueCERTCertList& chain, bool& result)
118 : {
119 0 : if (!chain || CERT_LIST_EMPTY(chain)) {
120 0 : return Result::FATAL_ERROR_LIBRARY_FAILURE;
121 : }
122 0 : CERTCertListNode* rootNode = CERT_LIST_TAIL(chain);
123 0 : if (!rootNode) {
124 0 : return Result::FATAL_ERROR_LIBRARY_FAILURE;
125 : }
126 0 : CERTCertificate* root = rootNode->cert;
127 0 : if (!root) {
128 0 : return Result::FATAL_ERROR_LIBRARY_FAILURE;
129 : }
130 0 : return IsCertBuiltInRoot(root, result);
131 : }
132 :
133 : // The term "builtin root" traditionally refers to a root CA certificate that
134 : // has been added to the NSS trust store, because it has been approved
135 : // for inclusion according to the Mozilla CA policy, and might be accepted
136 : // by Mozilla applications as an issuer for certificates seen on the public web.
137 : Result
138 0 : IsCertBuiltInRoot(CERTCertificate* cert, bool& result)
139 : {
140 0 : result = false;
141 : #ifdef DEBUG
142 0 : nsCOMPtr<nsINSSComponent> component(do_GetService(PSM_COMPONENT_CONTRACTID));
143 0 : if (!component) {
144 0 : return Result::FATAL_ERROR_LIBRARY_FAILURE;
145 : }
146 0 : nsresult rv = component->IsCertTestBuiltInRoot(cert, result);
147 0 : if (NS_FAILED(rv)) {
148 0 : return Result::FATAL_ERROR_LIBRARY_FAILURE;
149 : }
150 0 : if (result) {
151 0 : return Success;
152 : }
153 : #endif // DEBUG
154 0 : AutoSECMODListReadLock lock;
155 0 : for (SECMODModuleList* list = SECMOD_GetDefaultModuleList(); list;
156 0 : list = list->next) {
157 0 : for (int i = 0; i < list->module->slotCount; i++) {
158 0 : PK11SlotInfo* slot = list->module->slots[i];
159 : // We're searching for the "builtin root module", which is a module that
160 : // contains an object with a CKA_CLASS of CKO_NETSCAPE_BUILTIN_ROOT_LIST.
161 : // We use PK11_HasRootCerts() to identify a module with that property.
162 : // In the past, we exclusively used the PKCS#11 module named nssckbi,
163 : // which is provided by the NSS library.
164 : // Nowadays, some distributions use a replacement module, which contains
165 : // the builtin roots, but which also contains additional CA certificates,
166 : // such as CAs trusted in a local deployment.
167 : // We want to be able to distinguish between these two categories,
168 : // because a CA, which may issue certificates for the public web,
169 : // is expected to comply with additional requirements.
170 : // If the certificate has attribute CKA_NSS_MOZILLA_CA_POLICY set to true,
171 : // then we treat it as a "builtin root".
172 0 : if (PK11_IsPresent(slot) && PK11_HasRootCerts(slot)) {
173 0 : CK_OBJECT_HANDLE handle = PK11_FindCertInSlot(slot, cert, nullptr);
174 0 : if (handle != CK_INVALID_HANDLE &&
175 0 : PK11_HasAttributeSet(slot, handle, CKA_NSS_MOZILLA_CA_POLICY,
176 : false)) {
177 : // Attribute was found, and is set to true
178 0 : result = true;
179 0 : break;
180 : }
181 : }
182 : }
183 : }
184 0 : return Success;
185 : }
186 :
187 : static Result
188 0 : BuildCertChainForOneKeyUsage(NSSCertDBTrustDomain& trustDomain, Input certDER,
189 : Time time, KeyUsage ku1, KeyUsage ku2,
190 : KeyUsage ku3, KeyPurposeId eku,
191 : const CertPolicyId& requiredPolicy,
192 : const Input* stapledOCSPResponse,
193 : /*optional out*/ CertVerifier::OCSPStaplingStatus*
194 : ocspStaplingStatus)
195 : {
196 0 : trustDomain.ResetAccumulatedState();
197 0 : Result rv = BuildCertChain(trustDomain, certDER, time,
198 : EndEntityOrCA::MustBeEndEntity, ku1,
199 0 : eku, requiredPolicy, stapledOCSPResponse);
200 0 : if (rv == Result::ERROR_INADEQUATE_KEY_USAGE) {
201 0 : trustDomain.ResetAccumulatedState();
202 0 : rv = BuildCertChain(trustDomain, certDER, time,
203 : EndEntityOrCA::MustBeEndEntity, ku2,
204 0 : eku, requiredPolicy, stapledOCSPResponse);
205 0 : if (rv == Result::ERROR_INADEQUATE_KEY_USAGE) {
206 0 : trustDomain.ResetAccumulatedState();
207 0 : rv = BuildCertChain(trustDomain, certDER, time,
208 : EndEntityOrCA::MustBeEndEntity, ku3,
209 0 : eku, requiredPolicy, stapledOCSPResponse);
210 0 : if (rv != Success) {
211 0 : rv = Result::ERROR_INADEQUATE_KEY_USAGE;
212 : }
213 : }
214 : }
215 0 : if (ocspStaplingStatus) {
216 0 : *ocspStaplingStatus = trustDomain.GetOCSPStaplingStatus();
217 : }
218 0 : return rv;
219 : }
220 :
221 : void
222 1 : CertVerifier::LoadKnownCTLogs()
223 : {
224 1 : mCTVerifier = MakeUnique<MultiLogCTVerifier>();
225 16 : for (const CTLogInfo& log : kCTLogList) {
226 15 : Input publicKey;
227 15 : Result rv = publicKey.Init(
228 30 : BitwiseCast<const uint8_t*, const char*>(log.key), log.keyLength);
229 15 : if (rv != Success) {
230 0 : MOZ_ASSERT_UNREACHABLE("Failed reading a log key for a known CT Log");
231 0 : continue;
232 : }
233 :
234 30 : CTLogVerifier logVerifier;
235 : const CTLogOperatorInfo& logOperator =
236 15 : kCTLogOperatorList[log.operatorIndex];
237 15 : rv = logVerifier.Init(publicKey, logOperator.id, log.status,
238 30 : log.disqualificationTime);
239 15 : if (rv != Success) {
240 0 : MOZ_ASSERT_UNREACHABLE("Failed initializing a known CT Log");
241 : continue;
242 : }
243 :
244 15 : rv = mCTVerifier->AddLog(Move(logVerifier));
245 15 : if (rv != Success) {
246 0 : MOZ_ASSERT_UNREACHABLE("Failed activating a known CT Log");
247 : continue;
248 : }
249 : }
250 : // TBD: Initialize mCTDiversityPolicy with the CA dependency map
251 : // of the known CT logs operators.
252 1 : mCTDiversityPolicy = MakeUnique<CTDiversityPolicy>();
253 1 : }
254 :
255 : Result
256 0 : CertVerifier::VerifyCertificateTransparencyPolicy(
257 : NSSCertDBTrustDomain& trustDomain, const UniqueCERTCertList& builtChain,
258 : Input sctsFromTLS, Time time,
259 : /*optional out*/ CertificateTransparencyInfo* ctInfo)
260 : {
261 0 : if (ctInfo) {
262 0 : ctInfo->Reset();
263 : }
264 0 : if (mCTMode == CertificateTransparencyMode::Disabled) {
265 0 : return Success;
266 : }
267 0 : if (ctInfo) {
268 0 : ctInfo->enabled = true;
269 : }
270 :
271 0 : if (!builtChain || CERT_LIST_EMPTY(builtChain)) {
272 0 : return Result::FATAL_ERROR_INVALID_ARGS;
273 : }
274 :
275 0 : Input embeddedSCTs = trustDomain.GetSCTListFromCertificate();
276 0 : if (embeddedSCTs.GetLength() > 0) {
277 0 : MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
278 : ("Got embedded SCT data of length %zu\n",
279 : static_cast<size_t>(embeddedSCTs.GetLength())));
280 : }
281 0 : Input sctsFromOCSP = trustDomain.GetSCTListFromOCSPStapling();
282 0 : if (sctsFromOCSP.GetLength() > 0) {
283 0 : MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
284 : ("Got OCSP SCT data of length %zu\n",
285 : static_cast<size_t>(sctsFromOCSP.GetLength())));
286 : }
287 0 : if (sctsFromTLS.GetLength() > 0) {
288 0 : MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
289 : ("Got TLS SCT data of length %zu\n",
290 : static_cast<size_t>(sctsFromTLS.GetLength())));
291 : }
292 :
293 0 : CERTCertListNode* endEntityNode = CERT_LIST_HEAD(builtChain);
294 0 : if (!endEntityNode || CERT_LIST_END(endEntityNode, builtChain)) {
295 0 : return Result::FATAL_ERROR_INVALID_ARGS;
296 : }
297 0 : CERTCertListNode* issuerNode = CERT_LIST_NEXT(endEntityNode);
298 0 : if (!issuerNode || CERT_LIST_END(issuerNode, builtChain)) {
299 : // Issuer certificate is required for SCT verification.
300 0 : return Result::FATAL_ERROR_INVALID_ARGS;
301 : }
302 :
303 0 : CERTCertificate* endEntity = endEntityNode->cert;
304 0 : CERTCertificate* issuer = issuerNode->cert;
305 0 : if (!endEntity || !issuer) {
306 0 : return Result::FATAL_ERROR_INVALID_ARGS;
307 : }
308 :
309 0 : if (endEntity->subjectName) {
310 0 : MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
311 : ("Verifying CT Policy compliance of subject %s\n",
312 : endEntity->subjectName));
313 : }
314 :
315 0 : Input endEntityDER;
316 0 : Result rv = endEntityDER.Init(endEntity->derCert.data,
317 0 : endEntity->derCert.len);
318 0 : if (rv != Success) {
319 0 : return rv;
320 : }
321 :
322 0 : Input issuerPublicKeyDER;
323 0 : rv = issuerPublicKeyDER.Init(issuer->derPublicKey.data,
324 0 : issuer->derPublicKey.len);
325 0 : if (rv != Success) {
326 0 : return rv;
327 : }
328 :
329 0 : CTVerifyResult result;
330 0 : rv = mCTVerifier->Verify(endEntityDER, issuerPublicKeyDER,
331 : embeddedSCTs, sctsFromOCSP, sctsFromTLS, time,
332 0 : result);
333 0 : if (rv != Success) {
334 0 : MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
335 : ("SCT verification failed with fatal error %" PRId32 "\n",
336 : static_cast<uint32_t>(rv)));
337 0 : return rv;
338 : }
339 :
340 0 : if (MOZ_LOG_TEST(gCertVerifierLog, LogLevel::Debug)) {
341 0 : size_t validCount = 0;
342 0 : size_t unknownLogCount = 0;
343 0 : size_t disqualifiedLogCount = 0;
344 0 : size_t invalidSignatureCount = 0;
345 0 : size_t invalidTimestampCount = 0;
346 0 : for (const VerifiedSCT& verifiedSct : result.verifiedScts) {
347 0 : switch (verifiedSct.status) {
348 : case VerifiedSCT::Status::Valid:
349 0 : validCount++;
350 0 : break;
351 : case VerifiedSCT::Status::ValidFromDisqualifiedLog:
352 0 : disqualifiedLogCount++;
353 0 : break;
354 : case VerifiedSCT::Status::UnknownLog:
355 0 : unknownLogCount++;
356 0 : break;
357 : case VerifiedSCT::Status::InvalidSignature:
358 0 : invalidSignatureCount++;
359 0 : break;
360 : case VerifiedSCT::Status::InvalidTimestamp:
361 0 : invalidTimestampCount++;
362 0 : break;
363 : case VerifiedSCT::Status::None:
364 : default:
365 0 : MOZ_ASSERT_UNREACHABLE("Unexpected SCT verification status");
366 : }
367 : }
368 0 : MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
369 : ("SCT verification result: "
370 : "valid=%zu unknownLog=%zu disqualifiedLog=%zu "
371 : "invalidSignature=%zu invalidTimestamp=%zu "
372 : "decodingErrors=%zu\n",
373 : validCount, unknownLogCount, disqualifiedLogCount,
374 : invalidSignatureCount, invalidTimestampCount,
375 : result.decodingErrors));
376 : }
377 :
378 : PRTime notBefore;
379 : PRTime notAfter;
380 0 : if (CERT_GetCertTimes(endEntity, ¬Before, ¬After) != SECSuccess) {
381 0 : return Result::FATAL_ERROR_LIBRARY_FAILURE;
382 : }
383 : size_t lifetimeInMonths;
384 0 : rv = GetCertLifetimeInFullMonths(notBefore, notAfter, lifetimeInMonths);
385 0 : if (rv != Success) {
386 0 : return rv;
387 : }
388 :
389 0 : CTLogOperatorList allOperators;
390 : rv = GetCTLogOperatorsFromVerifiedSCTList(result.verifiedScts,
391 0 : allOperators);
392 0 : if (rv != Success) {
393 0 : return rv;
394 : }
395 :
396 0 : CTLogOperatorList dependentOperators;
397 0 : rv = mCTDiversityPolicy->GetDependentOperators(builtChain, allOperators,
398 0 : dependentOperators);
399 0 : if (rv != Success) {
400 0 : return rv;
401 : }
402 :
403 : CTPolicyEnforcer ctPolicyEnforcer;
404 : CTPolicyCompliance ctPolicyCompliance;
405 0 : rv = ctPolicyEnforcer.CheckCompliance(result.verifiedScts, lifetimeInMonths,
406 0 : dependentOperators, ctPolicyCompliance);
407 0 : if (rv != Success) {
408 0 : MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
409 : ("CT policy check failed with fatal error %" PRIu32 "\n",
410 : static_cast<uint32_t>(rv)));
411 0 : return rv;
412 : }
413 :
414 0 : if (ctInfo) {
415 0 : ctInfo->verifyResult = Move(result);
416 0 : ctInfo->policyCompliance = ctPolicyCompliance;
417 : }
418 0 : return Success;
419 : }
420 :
421 : bool
422 0 : CertVerifier::SHA1ModeMoreRestrictiveThanGivenMode(SHA1Mode mode)
423 : {
424 0 : switch (mSHA1Mode) {
425 : case SHA1Mode::Forbidden:
426 0 : return mode != SHA1Mode::Forbidden;
427 : case SHA1Mode::ImportedRoot:
428 0 : return mode != SHA1Mode::Forbidden && mode != SHA1Mode::ImportedRoot;
429 : case SHA1Mode::ImportedRootOrBefore2016:
430 0 : return mode == SHA1Mode::Allowed;
431 : case SHA1Mode::Allowed:
432 0 : return false;
433 : // MSVC warns unless we explicitly handle this now-unused option.
434 : case SHA1Mode::UsedToBeBefore2016ButNowIsForbidden:
435 : default:
436 0 : MOZ_ASSERT(false, "unexpected SHA1Mode type");
437 : return true;
438 : }
439 : }
440 :
441 : static const unsigned int MIN_RSA_BITS = 2048;
442 : static const unsigned int MIN_RSA_BITS_WEAK = 1024;
443 :
444 : Result
445 0 : CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
446 : Time time, void* pinArg, const char* hostname,
447 : /*out*/ UniqueCERTCertList& builtChain,
448 : /*optional*/ UniqueCERTCertList* peerCertChain,
449 : /*optional*/ const Flags flags,
450 : /*optional*/ const SECItem* stapledOCSPResponseSECItem,
451 : /*optional*/ const SECItem* sctsFromTLSSECItem,
452 : /*optional*/ const OriginAttributes& originAttributes,
453 : /*optional out*/ SECOidTag* evOidPolicy,
454 : /*optional out*/ OCSPStaplingStatus* ocspStaplingStatus,
455 : /*optional out*/ KeySizeStatus* keySizeStatus,
456 : /*optional out*/ SHA1ModeResult* sha1ModeResult,
457 : /*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo,
458 : /*optional out*/ CertificateTransparencyInfo* ctInfo)
459 : {
460 0 : MOZ_LOG(gCertVerifierLog, LogLevel::Debug, ("Top of VerifyCert\n"));
461 :
462 0 : MOZ_ASSERT(cert);
463 0 : MOZ_ASSERT(usage == certificateUsageSSLServer || !(flags & FLAG_MUST_BE_EV));
464 0 : MOZ_ASSERT(usage == certificateUsageSSLServer || !keySizeStatus);
465 0 : MOZ_ASSERT(usage == certificateUsageSSLServer || !sha1ModeResult);
466 :
467 0 : if (evOidPolicy) {
468 0 : *evOidPolicy = SEC_OID_UNKNOWN;
469 : }
470 0 : if (ocspStaplingStatus) {
471 0 : if (usage != certificateUsageSSLServer) {
472 0 : return Result::FATAL_ERROR_INVALID_ARGS;
473 : }
474 0 : *ocspStaplingStatus = OCSP_STAPLING_NEVER_CHECKED;
475 : }
476 :
477 0 : if (keySizeStatus) {
478 0 : if (usage != certificateUsageSSLServer) {
479 0 : return Result::FATAL_ERROR_INVALID_ARGS;
480 : }
481 0 : *keySizeStatus = KeySizeStatus::NeverChecked;
482 : }
483 :
484 0 : if (sha1ModeResult) {
485 0 : if (usage != certificateUsageSSLServer) {
486 0 : return Result::FATAL_ERROR_INVALID_ARGS;
487 : }
488 0 : *sha1ModeResult = SHA1ModeResult::NeverChecked;
489 : }
490 :
491 0 : if (!cert ||
492 0 : (usage != certificateUsageSSLServer && (flags & FLAG_MUST_BE_EV))) {
493 0 : return Result::FATAL_ERROR_INVALID_ARGS;
494 : }
495 :
496 0 : Input certDER;
497 0 : Result rv = certDER.Init(cert->derCert.data, cert->derCert.len);
498 0 : if (rv != Success) {
499 0 : return rv;
500 : }
501 :
502 : // We configure the OCSP fetching modes separately for EV and non-EV
503 : // verifications.
504 : NSSCertDBTrustDomain::OCSPFetching defaultOCSPFetching
505 0 : = (mOCSPDownloadConfig == ocspOff) ||
506 0 : (mOCSPDownloadConfig == ocspEVOnly) ||
507 0 : (flags & FLAG_LOCAL_ONLY) ? NSSCertDBTrustDomain::NeverFetchOCSP
508 0 : : !mOCSPStrict ? NSSCertDBTrustDomain::FetchOCSPForDVSoftFail
509 0 : : NSSCertDBTrustDomain::FetchOCSPForDVHardFail;
510 :
511 0 : OcspGetConfig ocspGETConfig = mOCSPGETEnabled ? ocspGetEnabled
512 0 : : ocspGetDisabled;
513 :
514 0 : Input stapledOCSPResponseInput;
515 0 : const Input* stapledOCSPResponse = nullptr;
516 0 : if (stapledOCSPResponseSECItem) {
517 0 : rv = stapledOCSPResponseInput.Init(stapledOCSPResponseSECItem->data,
518 0 : stapledOCSPResponseSECItem->len);
519 0 : if (rv != Success) {
520 : // The stapled OCSP response was too big.
521 0 : return Result::ERROR_OCSP_MALFORMED_RESPONSE;
522 : }
523 0 : stapledOCSPResponse = &stapledOCSPResponseInput;
524 : }
525 :
526 0 : Input sctsFromTLSInput;
527 0 : if (sctsFromTLSSECItem) {
528 0 : rv = sctsFromTLSInput.Init(sctsFromTLSSECItem->data,
529 0 : sctsFromTLSSECItem->len);
530 : // Silently discard the error of the extension being too big,
531 : // do not fail the verification.
532 0 : MOZ_ASSERT(rv == Success);
533 : }
534 :
535 0 : switch (usage) {
536 : case certificateUsageSSLClient: {
537 : // XXX: We don't really have a trust bit for SSL client authentication so
538 : // just use trustEmail as it is the closest alternative.
539 : NSSCertDBTrustDomain trustDomain(trustEmail, defaultOCSPFetching,
540 : mOCSPCache, pinArg, ocspGETConfig,
541 : mOCSPTimeoutSoft, mOCSPTimeoutHard,
542 0 : mCertShortLifetimeInDays,
543 : pinningDisabled, MIN_RSA_BITS_WEAK,
544 : ValidityCheckingMode::CheckingOff,
545 : SHA1Mode::Allowed,
546 : NetscapeStepUpPolicy::NeverMatch,
547 : originAttributes,
548 : builtChain, peerCertChain, nullptr,
549 0 : nullptr);
550 : rv = BuildCertChain(trustDomain, certDER, time,
551 : EndEntityOrCA::MustBeEndEntity,
552 : KeyUsage::digitalSignature,
553 : KeyPurposeId::id_kp_clientAuth,
554 0 : CertPolicyId::anyPolicy, stapledOCSPResponse);
555 0 : break;
556 : }
557 :
558 : case certificateUsageSSLServer: {
559 : // TODO: When verifying a certificate in an SSL handshake, we should
560 : // restrict the acceptable key usage based on the key exchange method
561 : // chosen by the server.
562 :
563 : // These configurations are in order of most restrictive to least
564 : // restrictive. This enables us to gather telemetry on the expected
565 : // results of setting the default policy to a particular configuration.
566 : SHA1Mode sha1ModeConfigurations[] = {
567 : SHA1Mode::Forbidden,
568 : SHA1Mode::ImportedRoot,
569 : SHA1Mode::ImportedRootOrBefore2016,
570 : SHA1Mode::Allowed,
571 0 : };
572 :
573 : SHA1ModeResult sha1ModeResults[] = {
574 : SHA1ModeResult::SucceededWithoutSHA1,
575 : SHA1ModeResult::SucceededWithImportedRoot,
576 : SHA1ModeResult::SucceededWithImportedRootOrSHA1Before2016,
577 : SHA1ModeResult::SucceededWithSHA1,
578 0 : };
579 :
580 0 : size_t sha1ModeConfigurationsCount = MOZ_ARRAY_LENGTH(sha1ModeConfigurations);
581 :
582 : static_assert(MOZ_ARRAY_LENGTH(sha1ModeConfigurations) ==
583 : MOZ_ARRAY_LENGTH(sha1ModeResults),
584 : "digestAlgorithm array lengths differ");
585 :
586 0 : rv = Result::ERROR_UNKNOWN_ERROR;
587 :
588 : // Try to validate for EV first.
589 : NSSCertDBTrustDomain::OCSPFetching evOCSPFetching
590 0 : = (mOCSPDownloadConfig == ocspOff) ||
591 0 : (flags & FLAG_LOCAL_ONLY) ? NSSCertDBTrustDomain::LocalOnlyOCSPForEV
592 0 : : NSSCertDBTrustDomain::FetchOCSPForEV;
593 :
594 : CertPolicyId evPolicy;
595 : SECOidTag evPolicyOidTag;
596 0 : bool foundEVPolicy = GetFirstEVPolicy(*cert, evPolicy, evPolicyOidTag);
597 0 : for (size_t i = 0;
598 0 : i < sha1ModeConfigurationsCount && rv != Success && foundEVPolicy;
599 : i++) {
600 : // Don't attempt verification if the SHA1 mode set by preferences
601 : // (mSHA1Mode) is more restrictive than the SHA1 mode option we're on.
602 : // (To put it another way, only attempt verification if the SHA1 mode
603 : // option we're on is as restrictive or more restrictive than
604 : // mSHA1Mode.) This allows us to gather telemetry information while
605 : // still enforcing the mode set by preferences.
606 0 : if (SHA1ModeMoreRestrictiveThanGivenMode(sha1ModeConfigurations[i])) {
607 0 : continue;
608 : }
609 :
610 : // Because of the try-strict and fallback approach, we have to clear any
611 : // previously noted telemetry information
612 0 : if (pinningTelemetryInfo) {
613 0 : pinningTelemetryInfo->Reset();
614 : }
615 :
616 : NSSCertDBTrustDomain
617 : trustDomain(trustSSL, evOCSPFetching,
618 : mOCSPCache, pinArg, ocspGETConfig,
619 : mOCSPTimeoutSoft, mOCSPTimeoutHard,
620 0 : mCertShortLifetimeInDays, mPinningMode, MIN_RSA_BITS,
621 : ValidityCheckingMode::CheckForEV,
622 0 : sha1ModeConfigurations[i], mNetscapeStepUpPolicy,
623 : originAttributes, builtChain, peerCertChain,
624 0 : pinningTelemetryInfo, hostname);
625 : rv = BuildCertChainForOneKeyUsage(trustDomain, certDER, time,
626 : KeyUsage::digitalSignature,// (EC)DHE
627 : KeyUsage::keyEncipherment, // RSA
628 : KeyUsage::keyAgreement, // (EC)DH
629 : KeyPurposeId::id_kp_serverAuth,
630 : evPolicy, stapledOCSPResponse,
631 0 : ocspStaplingStatus);
632 0 : if (rv == Success &&
633 0 : sha1ModeConfigurations[i] == SHA1Mode::ImportedRoot) {
634 0 : bool isBuiltInRoot = false;
635 0 : rv = IsCertChainRootBuiltInRoot(builtChain, isBuiltInRoot);
636 0 : if (rv != Success) {
637 0 : break;
638 : }
639 0 : if (isBuiltInRoot) {
640 0 : rv = Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
641 : }
642 : }
643 0 : if (rv == Success) {
644 0 : MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
645 : ("cert is EV with status %i\n", static_cast<int>(sha1ModeResults[i])));
646 0 : if (evOidPolicy) {
647 0 : *evOidPolicy = evPolicyOidTag;
648 : }
649 0 : if (sha1ModeResult) {
650 0 : *sha1ModeResult = sha1ModeResults[i];
651 : }
652 : rv = VerifyCertificateTransparencyPolicy(trustDomain, builtChain,
653 : sctsFromTLSInput, time,
654 0 : ctInfo);
655 0 : if (rv != Success) {
656 0 : break;
657 : }
658 : }
659 : }
660 0 : if (rv == Success) {
661 0 : break;
662 : }
663 :
664 0 : if (flags & FLAG_MUST_BE_EV) {
665 0 : rv = Result::ERROR_POLICY_VALIDATION_FAILED;
666 0 : break;
667 : }
668 :
669 : // Now try non-EV.
670 : unsigned int keySizeOptions[] = {
671 : MIN_RSA_BITS,
672 : MIN_RSA_BITS_WEAK
673 0 : };
674 :
675 : KeySizeStatus keySizeStatuses[] = {
676 : KeySizeStatus::LargeMinimumSucceeded,
677 : KeySizeStatus::CompatibilityRisk
678 0 : };
679 :
680 : static_assert(MOZ_ARRAY_LENGTH(keySizeOptions) ==
681 : MOZ_ARRAY_LENGTH(keySizeStatuses),
682 : "keySize array lengths differ");
683 :
684 0 : size_t keySizeOptionsCount = MOZ_ARRAY_LENGTH(keySizeStatuses);
685 :
686 0 : for (size_t i = 0; i < keySizeOptionsCount && rv != Success; i++) {
687 0 : for (size_t j = 0; j < sha1ModeConfigurationsCount && rv != Success;
688 : j++) {
689 : // Don't attempt verification if the SHA1 mode set by preferences
690 : // (mSHA1Mode) is more restrictive than the SHA1 mode option we're on.
691 : // (To put it another way, only attempt verification if the SHA1 mode
692 : // option we're on is as restrictive or more restrictive than
693 : // mSHA1Mode.) This allows us to gather telemetry information while
694 : // still enforcing the mode set by preferences.
695 0 : if (SHA1ModeMoreRestrictiveThanGivenMode(sha1ModeConfigurations[j])) {
696 0 : continue;
697 : }
698 :
699 : // invalidate any telemetry info relating to failed chains
700 0 : if (pinningTelemetryInfo) {
701 0 : pinningTelemetryInfo->Reset();
702 : }
703 :
704 : NSSCertDBTrustDomain trustDomain(trustSSL, defaultOCSPFetching,
705 : mOCSPCache, pinArg, ocspGETConfig,
706 : mOCSPTimeoutSoft, mOCSPTimeoutHard,
707 0 : mCertShortLifetimeInDays,
708 0 : mPinningMode, keySizeOptions[i],
709 : ValidityCheckingMode::CheckingOff,
710 : sha1ModeConfigurations[j],
711 0 : mNetscapeStepUpPolicy,
712 : originAttributes, builtChain,
713 : peerCertChain, pinningTelemetryInfo,
714 0 : hostname);
715 : rv = BuildCertChainForOneKeyUsage(trustDomain, certDER, time,
716 : KeyUsage::digitalSignature,//(EC)DHE
717 : KeyUsage::keyEncipherment,//RSA
718 : KeyUsage::keyAgreement,//(EC)DH
719 : KeyPurposeId::id_kp_serverAuth,
720 : CertPolicyId::anyPolicy,
721 : stapledOCSPResponse,
722 0 : ocspStaplingStatus);
723 0 : if (rv == Success &&
724 0 : sha1ModeConfigurations[j] == SHA1Mode::ImportedRoot) {
725 0 : bool isBuiltInRoot = false;
726 0 : rv = IsCertChainRootBuiltInRoot(builtChain, isBuiltInRoot);
727 0 : if (rv != Success) {
728 0 : break;
729 : }
730 0 : if (isBuiltInRoot) {
731 0 : rv = Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
732 : }
733 : }
734 0 : if (rv == Success) {
735 0 : if (keySizeStatus) {
736 0 : *keySizeStatus = keySizeStatuses[i];
737 : }
738 0 : if (sha1ModeResult) {
739 0 : *sha1ModeResult = sha1ModeResults[j];
740 : }
741 : rv = VerifyCertificateTransparencyPolicy(trustDomain, builtChain,
742 : sctsFromTLSInput, time,
743 0 : ctInfo);
744 0 : if (rv != Success) {
745 0 : break;
746 : }
747 : }
748 : }
749 : }
750 :
751 0 : if (rv == Success) {
752 0 : break;
753 : }
754 :
755 0 : if (keySizeStatus) {
756 0 : *keySizeStatus = KeySizeStatus::AlreadyBad;
757 : }
758 : // The telemetry probe CERT_CHAIN_SHA1_POLICY_STATUS gives us feedback on
759 : // the result of setting a specific policy. However, we don't want noise
760 : // from users who have manually set the policy to something other than the
761 : // default, so we only collect for ImportedRoot (which is the default).
762 0 : if (sha1ModeResult && mSHA1Mode == SHA1Mode::ImportedRoot) {
763 0 : *sha1ModeResult = SHA1ModeResult::Failed;
764 : }
765 :
766 0 : break;
767 : }
768 :
769 : case certificateUsageSSLCA: {
770 : NSSCertDBTrustDomain trustDomain(trustSSL, defaultOCSPFetching,
771 : mOCSPCache, pinArg, ocspGETConfig,
772 : mOCSPTimeoutSoft, mOCSPTimeoutHard,
773 0 : mCertShortLifetimeInDays,
774 : pinningDisabled, MIN_RSA_BITS_WEAK,
775 : ValidityCheckingMode::CheckingOff,
776 0 : SHA1Mode::Allowed, mNetscapeStepUpPolicy,
777 : originAttributes, builtChain,
778 0 : peerCertChain, nullptr, nullptr);
779 : rv = BuildCertChain(trustDomain, certDER, time,
780 : EndEntityOrCA::MustBeCA, KeyUsage::keyCertSign,
781 : KeyPurposeId::id_kp_serverAuth,
782 0 : CertPolicyId::anyPolicy, stapledOCSPResponse);
783 0 : break;
784 : }
785 :
786 : case certificateUsageEmailSigner: {
787 : NSSCertDBTrustDomain trustDomain(trustEmail, defaultOCSPFetching,
788 : mOCSPCache, pinArg, ocspGETConfig,
789 : mOCSPTimeoutSoft, mOCSPTimeoutHard,
790 0 : mCertShortLifetimeInDays,
791 : pinningDisabled, MIN_RSA_BITS_WEAK,
792 : ValidityCheckingMode::CheckingOff,
793 : SHA1Mode::Allowed,
794 : NetscapeStepUpPolicy::NeverMatch,
795 : originAttributes, builtChain,
796 0 : peerCertChain, nullptr, nullptr);
797 : rv = BuildCertChain(trustDomain, certDER, time,
798 : EndEntityOrCA::MustBeEndEntity,
799 : KeyUsage::digitalSignature,
800 : KeyPurposeId::id_kp_emailProtection,
801 0 : CertPolicyId::anyPolicy, stapledOCSPResponse);
802 0 : if (rv == Result::ERROR_INADEQUATE_KEY_USAGE) {
803 : rv = BuildCertChain(trustDomain, certDER, time,
804 : EndEntityOrCA::MustBeEndEntity,
805 : KeyUsage::nonRepudiation,
806 : KeyPurposeId::id_kp_emailProtection,
807 0 : CertPolicyId::anyPolicy, stapledOCSPResponse);
808 : }
809 0 : break;
810 : }
811 :
812 : case certificateUsageEmailRecipient: {
813 : // TODO: The higher level S/MIME processing should pass in which key
814 : // usage it is trying to verify for, and base its algorithm choices
815 : // based on the result of the verification(s).
816 : NSSCertDBTrustDomain trustDomain(trustEmail, defaultOCSPFetching,
817 : mOCSPCache, pinArg, ocspGETConfig,
818 : mOCSPTimeoutSoft, mOCSPTimeoutHard,
819 0 : mCertShortLifetimeInDays,
820 : pinningDisabled, MIN_RSA_BITS_WEAK,
821 : ValidityCheckingMode::CheckingOff,
822 : SHA1Mode::Allowed,
823 : NetscapeStepUpPolicy::NeverMatch,
824 : originAttributes, builtChain,
825 0 : peerCertChain, nullptr, nullptr);
826 : rv = BuildCertChain(trustDomain, certDER, time,
827 : EndEntityOrCA::MustBeEndEntity,
828 : KeyUsage::keyEncipherment, // RSA
829 : KeyPurposeId::id_kp_emailProtection,
830 0 : CertPolicyId::anyPolicy, stapledOCSPResponse);
831 0 : if (rv == Result::ERROR_INADEQUATE_KEY_USAGE) {
832 : rv = BuildCertChain(trustDomain, certDER, time,
833 : EndEntityOrCA::MustBeEndEntity,
834 : KeyUsage::keyAgreement, // ECDH/DH
835 : KeyPurposeId::id_kp_emailProtection,
836 0 : CertPolicyId::anyPolicy, stapledOCSPResponse);
837 : }
838 0 : break;
839 : }
840 :
841 : case certificateUsageObjectSigner: {
842 : NSSCertDBTrustDomain trustDomain(trustObjectSigning, defaultOCSPFetching,
843 : mOCSPCache, pinArg, ocspGETConfig,
844 : mOCSPTimeoutSoft, mOCSPTimeoutHard,
845 0 : mCertShortLifetimeInDays,
846 : pinningDisabled, MIN_RSA_BITS_WEAK,
847 : ValidityCheckingMode::CheckingOff,
848 : SHA1Mode::Allowed,
849 : NetscapeStepUpPolicy::NeverMatch,
850 : originAttributes, builtChain,
851 0 : peerCertChain, nullptr, nullptr);
852 : rv = BuildCertChain(trustDomain, certDER, time,
853 : EndEntityOrCA::MustBeEndEntity,
854 : KeyUsage::digitalSignature,
855 : KeyPurposeId::id_kp_codeSigning,
856 0 : CertPolicyId::anyPolicy, stapledOCSPResponse);
857 0 : break;
858 : }
859 :
860 : case certificateUsageVerifyCA:
861 : case certificateUsageStatusResponder: {
862 : // XXX This is a pretty useless way to verify a certificate. It is used
863 : // by the certificate viewer UI. Because we don't know what trust bit is
864 : // interesting, we just try them all.
865 : mozilla::pkix::EndEntityOrCA endEntityOrCA;
866 : mozilla::pkix::KeyUsage keyUsage;
867 : KeyPurposeId eku;
868 0 : if (usage == certificateUsageVerifyCA) {
869 0 : endEntityOrCA = EndEntityOrCA::MustBeCA;
870 0 : keyUsage = KeyUsage::keyCertSign;
871 0 : eku = KeyPurposeId::anyExtendedKeyUsage;
872 : } else {
873 0 : endEntityOrCA = EndEntityOrCA::MustBeEndEntity;
874 0 : keyUsage = KeyUsage::digitalSignature;
875 0 : eku = KeyPurposeId::id_kp_OCSPSigning;
876 : }
877 :
878 : NSSCertDBTrustDomain sslTrust(trustSSL, defaultOCSPFetching, mOCSPCache,
879 : pinArg, ocspGETConfig, mOCSPTimeoutSoft,
880 0 : mOCSPTimeoutHard, mCertShortLifetimeInDays,
881 : pinningDisabled, MIN_RSA_BITS_WEAK,
882 : ValidityCheckingMode::CheckingOff,
883 : SHA1Mode::Allowed,
884 : NetscapeStepUpPolicy::NeverMatch,
885 : originAttributes, builtChain, peerCertChain,
886 0 : nullptr, nullptr);
887 : rv = BuildCertChain(sslTrust, certDER, time, endEntityOrCA,
888 : keyUsage, eku, CertPolicyId::anyPolicy,
889 0 : stapledOCSPResponse);
890 0 : if (rv == Result::ERROR_UNKNOWN_ISSUER) {
891 : NSSCertDBTrustDomain emailTrust(trustEmail, defaultOCSPFetching,
892 : mOCSPCache, pinArg, ocspGETConfig,
893 : mOCSPTimeoutSoft, mOCSPTimeoutHard,
894 0 : mCertShortLifetimeInDays,
895 : pinningDisabled, MIN_RSA_BITS_WEAK,
896 : ValidityCheckingMode::CheckingOff,
897 : SHA1Mode::Allowed,
898 : NetscapeStepUpPolicy::NeverMatch,
899 : originAttributes, builtChain,
900 0 : peerCertChain, nullptr, nullptr);
901 : rv = BuildCertChain(emailTrust, certDER, time, endEntityOrCA,
902 : keyUsage, eku, CertPolicyId::anyPolicy,
903 0 : stapledOCSPResponse);
904 0 : if (rv == Result::ERROR_UNKNOWN_ISSUER) {
905 : NSSCertDBTrustDomain objectSigningTrust(trustObjectSigning,
906 : defaultOCSPFetching,
907 : mOCSPCache, pinArg,
908 : ocspGETConfig,
909 : mOCSPTimeoutSoft,
910 : mOCSPTimeoutHard,
911 0 : mCertShortLifetimeInDays,
912 : pinningDisabled,
913 : MIN_RSA_BITS_WEAK,
914 : ValidityCheckingMode::CheckingOff,
915 : SHA1Mode::Allowed,
916 : NetscapeStepUpPolicy::NeverMatch,
917 : originAttributes, builtChain,
918 : peerCertChain, nullptr,
919 0 : nullptr);
920 : rv = BuildCertChain(objectSigningTrust, certDER, time,
921 : endEntityOrCA, keyUsage, eku,
922 0 : CertPolicyId::anyPolicy, stapledOCSPResponse);
923 : }
924 : }
925 :
926 0 : break;
927 : }
928 :
929 : default:
930 0 : rv = Result::FATAL_ERROR_INVALID_ARGS;
931 : }
932 :
933 0 : if (rv != Success) {
934 0 : return rv;
935 : }
936 :
937 0 : return Success;
938 : }
939 :
940 : Result
941 0 : CertVerifier::VerifySSLServerCert(const UniqueCERTCertificate& peerCert,
942 : /*optional*/ const SECItem* stapledOCSPResponse,
943 : /*optional*/ const SECItem* sctsFromTLS,
944 : Time time,
945 : /*optional*/ void* pinarg,
946 : const nsACString& hostname,
947 : /*out*/ UniqueCERTCertList& builtChain,
948 : /*optional*/ UniqueCERTCertList* peerCertChain,
949 : /*optional*/ bool saveIntermediatesInPermanentDatabase,
950 : /*optional*/ Flags flags,
951 : /*optional*/ const OriginAttributes& originAttributes,
952 : /*optional out*/ SECOidTag* evOidPolicy,
953 : /*optional out*/ OCSPStaplingStatus* ocspStaplingStatus,
954 : /*optional out*/ KeySizeStatus* keySizeStatus,
955 : /*optional out*/ SHA1ModeResult* sha1ModeResult,
956 : /*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo,
957 : /*optional out*/ CertificateTransparencyInfo* ctInfo)
958 : {
959 0 : MOZ_ASSERT(peerCert);
960 : // XXX: MOZ_ASSERT(pinarg);
961 0 : MOZ_ASSERT(!hostname.IsEmpty());
962 :
963 0 : if (evOidPolicy) {
964 0 : *evOidPolicy = SEC_OID_UNKNOWN;
965 : }
966 :
967 0 : if (hostname.IsEmpty()) {
968 0 : return Result::ERROR_BAD_CERT_DOMAIN;
969 : }
970 :
971 : // CreateCertErrorRunnable assumes that CheckCertHostname is only called
972 : // if VerifyCert succeeded.
973 0 : Result rv = VerifyCert(peerCert.get(), certificateUsageSSLServer, time,
974 0 : pinarg, PromiseFlatCString(hostname).get(), builtChain,
975 : peerCertChain, flags,
976 : stapledOCSPResponse, sctsFromTLS, originAttributes,
977 : evOidPolicy, ocspStaplingStatus, keySizeStatus,
978 0 : sha1ModeResult, pinningTelemetryInfo, ctInfo);
979 0 : if (rv != Success) {
980 0 : return rv;
981 : }
982 :
983 0 : Input peerCertInput;
984 0 : rv = peerCertInput.Init(peerCert->derCert.data, peerCert->derCert.len);
985 0 : if (rv != Success) {
986 0 : return rv;
987 : }
988 :
989 0 : Input stapledOCSPResponseInput;
990 0 : Input* responseInputPtr = nullptr;
991 0 : if (stapledOCSPResponse) {
992 0 : rv = stapledOCSPResponseInput.Init(stapledOCSPResponse->data,
993 0 : stapledOCSPResponse->len);
994 0 : if (rv != Success) {
995 : // The stapled OCSP response was too big.
996 0 : return Result::ERROR_OCSP_MALFORMED_RESPONSE;
997 : }
998 0 : responseInputPtr = &stapledOCSPResponseInput;
999 : }
1000 :
1001 0 : if (!(flags & FLAG_TLS_IGNORE_STATUS_REQUEST)) {
1002 0 : rv = CheckTLSFeaturesAreSatisfied(peerCertInput, responseInputPtr);
1003 0 : if (rv != Success) {
1004 0 : return rv;
1005 : }
1006 : }
1007 :
1008 0 : Input hostnameInput;
1009 0 : rv = hostnameInput.Init(
1010 : BitwiseCast<const uint8_t*, const char*>(hostname.BeginReading()),
1011 0 : hostname.Length());
1012 0 : if (rv != Success) {
1013 0 : return Result::FATAL_ERROR_INVALID_ARGS;
1014 : }
1015 : bool isBuiltInRoot;
1016 0 : rv = IsCertChainRootBuiltInRoot(builtChain, isBuiltInRoot);
1017 0 : if (rv != Success) {
1018 0 : return rv;
1019 : }
1020 : BRNameMatchingPolicy nameMatchingPolicy(
1021 : isBuiltInRoot ? mNameMatchingMode
1022 0 : : BRNameMatchingPolicy::Mode::DoNotEnforce);
1023 0 : rv = CheckCertHostname(peerCertInput, hostnameInput, nameMatchingPolicy);
1024 0 : if (rv != Success) {
1025 : // Treat malformed name information as a domain mismatch.
1026 0 : if (rv == Result::ERROR_BAD_DER) {
1027 0 : return Result::ERROR_BAD_CERT_DOMAIN;
1028 : }
1029 :
1030 0 : return rv;
1031 : }
1032 :
1033 0 : if (saveIntermediatesInPermanentDatabase) {
1034 0 : SaveIntermediateCerts(builtChain);
1035 : }
1036 :
1037 0 : return Success;
1038 : }
1039 :
1040 : } } // namespace mozilla::psm
|