NSSCertDBTrustDomain.cpp 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "NSSCertDBTrustDomain.h"
  6. #include <stdint.h>
  7. #include "ExtendedValidation.h"
  8. #include "NSSErrorsService.h"
  9. #include "OCSPRequestor.h"
  10. #include "OCSPVerificationTrustDomain.h"
  11. #include "cert.h"
  12. #include "certdb.h"
  13. #include "mozilla/Assertions.h"
  14. #include "mozilla/Casting.h"
  15. #include "mozilla/PodOperations.h"
  16. #include "mozilla/UniquePtr.h"
  17. #include "mozilla/Unused.h"
  18. #include "nsNSSCertificate.h"
  19. #include "nsServiceManagerUtils.h"
  20. #include "nsThreadUtils.h"
  21. #include "nss.h"
  22. #include "pk11pub.h"
  23. #include "pkix/Result.h"
  24. #include "pkix/pkix.h"
  25. #include "pkix/pkixnss.h"
  26. #include "prerror.h"
  27. #include "prmem.h"
  28. #include "prprf.h"
  29. #include "secerr.h"
  30. #include "CNNICHashWhitelist.inc"
  31. #include "StartComAndWoSignData.inc"
  32. using namespace mozilla;
  33. using namespace mozilla::pkix;
  34. extern LazyLogModule gCertVerifierLog;
  35. static const uint64_t ServerFailureDelaySeconds = 5 * 60;
  36. namespace mozilla { namespace psm {
  37. const char BUILTIN_ROOTS_MODULE_DEFAULT_NAME[] = "Builtin Roots Module";
  38. NSSCertDBTrustDomain::NSSCertDBTrustDomain(SECTrustType certDBTrustType,
  39. OCSPFetching ocspFetching,
  40. OCSPCache& ocspCache,
  41. /*optional but shouldn't be*/ void* pinArg,
  42. CertVerifier::OcspGetConfig ocspGETConfig,
  43. uint32_t certShortLifetimeInDays,
  44. unsigned int minRSABits,
  45. ValidityCheckingMode validityCheckingMode,
  46. CertVerifier::SHA1Mode sha1Mode,
  47. NetscapeStepUpPolicy netscapeStepUpPolicy,
  48. const NeckoOriginAttributes& originAttributes,
  49. UniqueCERTCertList& builtChain)
  50. : mCertDBTrustType(certDBTrustType)
  51. , mOCSPFetching(ocspFetching)
  52. , mOCSPCache(ocspCache)
  53. , mPinArg(pinArg)
  54. , mOCSPGetConfig(ocspGETConfig)
  55. , mCertShortLifetimeInDays(certShortLifetimeInDays)
  56. , mMinRSABits(minRSABits)
  57. , mValidityCheckingMode(validityCheckingMode)
  58. , mSHA1Mode(sha1Mode)
  59. , mNetscapeStepUpPolicy(netscapeStepUpPolicy)
  60. , mOriginAttributes(originAttributes)
  61. , mBuiltChain(builtChain)
  62. , mCertBlocklist(do_GetService(NS_CERTBLOCKLIST_CONTRACTID))
  63. , mOCSPStaplingStatus(CertVerifier::OCSP_STAPLING_NEVER_CHECKED)
  64. , mSCTListFromCertificate()
  65. , mSCTListFromOCSPStapling()
  66. {
  67. }
  68. // If useRoots is true, we only use root certificates in the candidate list.
  69. // If useRoots is false, we only use non-root certificates in the list.
  70. static Result
  71. FindIssuerInner(const UniqueCERTCertList& candidates, bool useRoots,
  72. Input encodedIssuerName, TrustDomain::IssuerChecker& checker,
  73. /*out*/ bool& keepGoing)
  74. {
  75. keepGoing = true;
  76. for (CERTCertListNode* n = CERT_LIST_HEAD(candidates);
  77. !CERT_LIST_END(n, candidates); n = CERT_LIST_NEXT(n)) {
  78. bool candidateIsRoot = !!n->cert->isRoot;
  79. if (candidateIsRoot != useRoots) {
  80. continue;
  81. }
  82. Input certDER;
  83. Result rv = certDER.Init(n->cert->derCert.data, n->cert->derCert.len);
  84. if (rv != Success) {
  85. continue; // probably too big
  86. }
  87. const SECItem encodedIssuerNameItem = {
  88. siBuffer,
  89. const_cast<unsigned char*>(encodedIssuerName.UnsafeGetData()),
  90. encodedIssuerName.GetLength()
  91. };
  92. ScopedAutoSECItem nameConstraints;
  93. SECStatus srv = CERT_GetImposedNameConstraints(&encodedIssuerNameItem,
  94. &nameConstraints);
  95. if (srv != SECSuccess) {
  96. if (PR_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) {
  97. return Result::FATAL_ERROR_LIBRARY_FAILURE;
  98. }
  99. // If no imposed name constraints were found, continue without them
  100. rv = checker.Check(certDER, nullptr, keepGoing);
  101. } else {
  102. // Otherwise apply the constraints
  103. Input nameConstraintsInput;
  104. if (nameConstraintsInput.Init(nameConstraints.data, nameConstraints.len)
  105. != Success) {
  106. return Result::FATAL_ERROR_LIBRARY_FAILURE;
  107. }
  108. rv = checker.Check(certDER, &nameConstraintsInput, keepGoing);
  109. }
  110. if (rv != Success) {
  111. return rv;
  112. }
  113. if (!keepGoing) {
  114. break;
  115. }
  116. }
  117. return Success;
  118. }
  119. Result
  120. NSSCertDBTrustDomain::FindIssuer(Input encodedIssuerName,
  121. IssuerChecker& checker, Time)
  122. {
  123. // TODO: NSS seems to be ambiguous between "no potential issuers found" and
  124. // "there was an error trying to retrieve the potential issuers."
  125. SECItem encodedIssuerNameItem = UnsafeMapInputToSECItem(encodedIssuerName);
  126. UniqueCERTCertList
  127. candidates(CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(),
  128. &encodedIssuerNameItem, 0,
  129. false));
  130. if (candidates) {
  131. // First, try all the root certs; then try all the non-root certs.
  132. bool keepGoing;
  133. Result rv = FindIssuerInner(candidates, true, encodedIssuerName, checker,
  134. keepGoing);
  135. if (rv != Success) {
  136. return rv;
  137. }
  138. if (keepGoing) {
  139. rv = FindIssuerInner(candidates, false, encodedIssuerName, checker,
  140. keepGoing);
  141. if (rv != Success) {
  142. return rv;
  143. }
  144. }
  145. }
  146. return Success;
  147. }
  148. Result
  149. NSSCertDBTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
  150. const CertPolicyId& policy,
  151. Input candidateCertDER,
  152. /*out*/ TrustLevel& trustLevel)
  153. {
  154. // XXX: This would be cleaner and more efficient if we could get the trust
  155. // information without constructing a CERTCertificate here, but NSS doesn't
  156. // expose it in any other easy-to-use fashion. The use of
  157. // CERT_NewTempCertificate to get a CERTCertificate shouldn't be a
  158. // performance problem because NSS will just find the existing
  159. // CERTCertificate in its in-memory cache and return it.
  160. SECItem candidateCertDERSECItem = UnsafeMapInputToSECItem(candidateCertDER);
  161. UniqueCERTCertificate candidateCert(
  162. CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &candidateCertDERSECItem,
  163. nullptr, false, true));
  164. if (!candidateCert) {
  165. return MapPRErrorCodeToResult(PR_GetError());
  166. }
  167. // Check the certificate against the OneCRL cert blocklist
  168. if (!mCertBlocklist) {
  169. return Result::FATAL_ERROR_LIBRARY_FAILURE;
  170. }
  171. // The certificate blocklist currently only applies to TLS server
  172. // certificates.
  173. if (mCertDBTrustType == trustSSL) {
  174. bool isCertRevoked;
  175. nsresult nsrv = mCertBlocklist->IsCertRevoked(
  176. candidateCert->derIssuer.data,
  177. candidateCert->derIssuer.len,
  178. candidateCert->serialNumber.data,
  179. candidateCert->serialNumber.len,
  180. candidateCert->derSubject.data,
  181. candidateCert->derSubject.len,
  182. candidateCert->derPublicKey.data,
  183. candidateCert->derPublicKey.len,
  184. &isCertRevoked);
  185. if (NS_FAILED(nsrv)) {
  186. return Result::FATAL_ERROR_LIBRARY_FAILURE;
  187. }
  188. if (isCertRevoked) {
  189. MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
  190. ("NSSCertDBTrustDomain: certificate is in blocklist"));
  191. return Result::ERROR_REVOKED_CERTIFICATE;
  192. }
  193. }
  194. // XXX: CERT_GetCertTrust seems to be abusing SECStatus as a boolean, where
  195. // SECSuccess means that there is a trust record and SECFailure means there
  196. // is not a trust record. I looked at NSS's internal uses of
  197. // CERT_GetCertTrust, and all that code uses the result as a boolean meaning
  198. // "We have a trust record."
  199. CERTCertTrust trust;
  200. if (CERT_GetCertTrust(candidateCert.get(), &trust) == SECSuccess) {
  201. uint32_t flags = SEC_GET_TRUST_FLAGS(&trust, mCertDBTrustType);
  202. // For DISTRUST, we use the CERTDB_TRUSTED or CERTDB_TRUSTED_CA bit,
  203. // because we can have active distrust for either type of cert. Note that
  204. // CERTDB_TERMINAL_RECORD means "stop trying to inherit trust" so if the
  205. // relevant trust bit isn't set then that means the cert must be considered
  206. // distrusted.
  207. uint32_t relevantTrustBit =
  208. endEntityOrCA == EndEntityOrCA::MustBeCA ? CERTDB_TRUSTED_CA
  209. : CERTDB_TRUSTED;
  210. if (((flags & (relevantTrustBit|CERTDB_TERMINAL_RECORD)))
  211. == CERTDB_TERMINAL_RECORD) {
  212. trustLevel = TrustLevel::ActivelyDistrusted;
  213. return Success;
  214. }
  215. // For TRUST, we only use the CERTDB_TRUSTED_CA bit, because Goanna hasn't
  216. // needed to consider end-entity certs to be their own trust anchors since
  217. // Goanna implemented nsICertOverrideService.
  218. // Of course, for this to work as expected, we need to make sure we're
  219. // inquiring about the trust of a CA and not an end-entity. If an end-entity
  220. // has the CERTDB_TRUSTED_CA bit set, Gecko does not consider it to be a
  221. // trust anchor; it must inherit its trust.
  222. if (flags & CERTDB_TRUSTED_CA && endEntityOrCA == EndEntityOrCA::MustBeCA) {
  223. if (policy.IsAnyPolicy()) {
  224. trustLevel = TrustLevel::TrustAnchor;
  225. return Success;
  226. }
  227. if (CertIsAuthoritativeForEVPolicy(candidateCert, policy)) {
  228. trustLevel = TrustLevel::TrustAnchor;
  229. return Success;
  230. }
  231. }
  232. }
  233. trustLevel = TrustLevel::InheritsTrust;
  234. return Success;
  235. }
  236. Result
  237. NSSCertDBTrustDomain::DigestBuf(Input item, DigestAlgorithm digestAlg,
  238. /*out*/ uint8_t* digestBuf, size_t digestBufLen)
  239. {
  240. return DigestBufNSS(item, digestAlg, digestBuf, digestBufLen);
  241. }
  242. static PRIntervalTime
  243. OCSPFetchingTypeToTimeoutTime(NSSCertDBTrustDomain::OCSPFetching ocspFetching)
  244. {
  245. switch (ocspFetching) {
  246. case NSSCertDBTrustDomain::FetchOCSPForDVSoftFail:
  247. return PR_SecondsToInterval(2);
  248. case NSSCertDBTrustDomain::FetchOCSPForEV:
  249. case NSSCertDBTrustDomain::FetchOCSPForDVHardFail:
  250. return PR_SecondsToInterval(10);
  251. // The rest of these are error cases. Assert in debug builds, but return
  252. // the default value corresponding to 2 seconds in release builds.
  253. case NSSCertDBTrustDomain::NeverFetchOCSP:
  254. case NSSCertDBTrustDomain::LocalOnlyOCSPForEV:
  255. PR_NOT_REACHED("we should never see this OCSPFetching type here");
  256. break;
  257. }
  258. PR_NOT_REACHED("we're not handling every OCSPFetching type");
  259. return PR_SecondsToInterval(2);
  260. }
  261. // Copied and modified from CERT_GetOCSPAuthorityInfoAccessLocation and
  262. // CERT_GetGeneralNameByType. Returns a non-Result::Success result on error,
  263. // Success with url == nullptr when an OCSP URI was not found, and Success with
  264. // url != nullptr when an OCSP URI was found. The output url will be owned
  265. // by the arena.
  266. static Result
  267. GetOCSPAuthorityInfoAccessLocation(const UniquePLArenaPool& arena,
  268. Input aiaExtension,
  269. /*out*/ char const*& url)
  270. {
  271. MOZ_ASSERT(arena.get());
  272. if (!arena.get()) {
  273. return Result::FATAL_ERROR_INVALID_ARGS;
  274. }
  275. url = nullptr;
  276. SECItem aiaExtensionSECItem = UnsafeMapInputToSECItem(aiaExtension);
  277. CERTAuthInfoAccess** aia =
  278. CERT_DecodeAuthInfoAccessExtension(arena.get(), &aiaExtensionSECItem);
  279. if (!aia) {
  280. return Result::ERROR_CERT_BAD_ACCESS_LOCATION;
  281. }
  282. for (size_t i = 0; aia[i]; ++i) {
  283. if (SECOID_FindOIDTag(&aia[i]->method) == SEC_OID_PKIX_OCSP) {
  284. // NSS chooses the **last** OCSP URL; we choose the **first**
  285. CERTGeneralName* current = aia[i]->location;
  286. if (!current) {
  287. continue;
  288. }
  289. do {
  290. if (current->type == certURI) {
  291. const SECItem& location = current->name.other;
  292. // (location.len + 1) must be small enough to fit into a uint32_t,
  293. // but we limit it to a smaller bound to reduce OOM risk.
  294. if (location.len > 1024 || memchr(location.data, 0, location.len)) {
  295. // Reject embedded nulls. (NSS doesn't do this)
  296. return Result::ERROR_CERT_BAD_ACCESS_LOCATION;
  297. }
  298. // Copy the non-null-terminated SECItem into a null-terminated string.
  299. char* nullTerminatedURL(
  300. static_cast<char*>(PORT_ArenaAlloc(arena.get(), location.len + 1)));
  301. if (!nullTerminatedURL) {
  302. return Result::FATAL_ERROR_NO_MEMORY;
  303. }
  304. memcpy(nullTerminatedURL, location.data, location.len);
  305. nullTerminatedURL[location.len] = 0;
  306. url = nullTerminatedURL;
  307. return Success;
  308. }
  309. current = CERT_GetNextGeneralName(current);
  310. } while (current != aia[i]->location);
  311. }
  312. }
  313. return Success;
  314. }
  315. Result
  316. NSSCertDBTrustDomain::CheckRevocation(EndEntityOrCA endEntityOrCA,
  317. const CertID& certID, Time time,
  318. Duration validityDuration,
  319. /*optional*/ const Input* stapledOCSPResponse,
  320. /*optional*/ const Input* aiaExtension,
  321. /*optional*/ const Input* sctExtension)
  322. {
  323. // Actively distrusted certificates will have already been blocked by
  324. // GetCertTrust.
  325. // TODO: need to verify that IsRevoked isn't called for trust anchors AND
  326. // that that fact is documented in mozillapkix.
  327. MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
  328. ("NSSCertDBTrustDomain: Top of CheckRevocation\n"));
  329. // Bug 991815: The BR allow OCSP for intermediates to be up to one year old.
  330. // Since this affects EV there is no reason why DV should be more strict
  331. // so all intermediatates are allowed to have OCSP responses up to one year
  332. // old.
  333. uint16_t maxOCSPLifetimeInDays = 10;
  334. if (endEntityOrCA == EndEntityOrCA::MustBeCA) {
  335. maxOCSPLifetimeInDays = 365;
  336. }
  337. // If we have a stapled OCSP response then the verification of that response
  338. // determines the result unless the OCSP response is expired. We make an
  339. // exception for expired responses because some servers, nginx in particular,
  340. // are known to serve expired responses due to bugs.
  341. // We keep track of the result of verifying the stapled response but don't
  342. // immediately return failure if the response has expired.
  343. //
  344. // We only set the OCSP stapling status if we're validating the end-entity
  345. // certificate. Non-end-entity certificates would always be
  346. // OCSP_STAPLING_NONE unless/until we implement multi-stapling.
  347. Result stapledOCSPResponseResult = Success;
  348. if (stapledOCSPResponse) {
  349. PR_ASSERT(endEntityOrCA == EndEntityOrCA::MustBeEndEntity);
  350. bool expired;
  351. stapledOCSPResponseResult =
  352. VerifyAndMaybeCacheEncodedOCSPResponse(certID, time,
  353. maxOCSPLifetimeInDays,
  354. *stapledOCSPResponse,
  355. ResponseWasStapled, expired);
  356. if (stapledOCSPResponseResult == Success) {
  357. // stapled OCSP response present and good
  358. mOCSPStaplingStatus = CertVerifier::OCSP_STAPLING_GOOD;
  359. MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
  360. ("NSSCertDBTrustDomain: stapled OCSP response: good"));
  361. return Success;
  362. }
  363. if (stapledOCSPResponseResult == Result::ERROR_OCSP_OLD_RESPONSE ||
  364. expired) {
  365. // stapled OCSP response present but expired
  366. mOCSPStaplingStatus = CertVerifier::OCSP_STAPLING_EXPIRED;
  367. MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
  368. ("NSSCertDBTrustDomain: expired stapled OCSP response"));
  369. } else {
  370. // stapled OCSP response present but invalid for some reason
  371. mOCSPStaplingStatus = CertVerifier::OCSP_STAPLING_INVALID;
  372. MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
  373. ("NSSCertDBTrustDomain: stapled OCSP response: failure"));
  374. return stapledOCSPResponseResult;
  375. }
  376. } else if (endEntityOrCA == EndEntityOrCA::MustBeEndEntity) {
  377. // no stapled OCSP response
  378. mOCSPStaplingStatus = CertVerifier::OCSP_STAPLING_NONE;
  379. MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
  380. ("NSSCertDBTrustDomain: no stapled OCSP response"));
  381. }
  382. Result cachedResponseResult = Success;
  383. Time cachedResponseValidThrough(Time::uninitialized);
  384. bool cachedResponsePresent = mOCSPCache.Get(certID, mOriginAttributes,
  385. cachedResponseResult,
  386. cachedResponseValidThrough);
  387. if (cachedResponsePresent) {
  388. if (cachedResponseResult == Success && cachedResponseValidThrough >= time) {
  389. MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
  390. ("NSSCertDBTrustDomain: cached OCSP response: good"));
  391. return Success;
  392. }
  393. // If we have a cached revoked response, use it.
  394. if (cachedResponseResult == Result::ERROR_REVOKED_CERTIFICATE) {
  395. MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
  396. ("NSSCertDBTrustDomain: cached OCSP response: revoked"));
  397. return Result::ERROR_REVOKED_CERTIFICATE;
  398. }
  399. // The cached response may indicate an unknown certificate or it may be
  400. // expired. Don't return with either of these statuses yet - we may be
  401. // able to fetch a more recent one.
  402. MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
  403. ("NSSCertDBTrustDomain: cached OCSP response: error %d",
  404. cachedResponseResult));
  405. // When a good cached response has expired, it is more convenient
  406. // to convert that to an error code and just deal with
  407. // cachedResponseResult from here on out.
  408. if (cachedResponseResult == Success && cachedResponseValidThrough < time) {
  409. cachedResponseResult = Result::ERROR_OCSP_OLD_RESPONSE;
  410. }
  411. // We may have a cached indication of server failure. Ignore it if
  412. // it has expired.
  413. if (cachedResponseResult != Success &&
  414. cachedResponseResult != Result::ERROR_OCSP_UNKNOWN_CERT &&
  415. cachedResponseResult != Result::ERROR_OCSP_OLD_RESPONSE &&
  416. cachedResponseValidThrough < time) {
  417. cachedResponseResult = Success;
  418. cachedResponsePresent = false;
  419. }
  420. } else {
  421. MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
  422. ("NSSCertDBTrustDomain: no cached OCSP response"));
  423. }
  424. // At this point, if and only if cachedErrorResult is Success, there was no
  425. // cached response.
  426. PR_ASSERT((!cachedResponsePresent && cachedResponseResult == Success) ||
  427. (cachedResponsePresent && cachedResponseResult != Success));
  428. // If we have a fresh OneCRL Blocklist we can skip OCSP for CA certs
  429. bool blocklistIsFresh;
  430. nsresult nsrv = mCertBlocklist->IsBlocklistFresh(&blocklistIsFresh);
  431. if (NS_FAILED(nsrv)) {
  432. return Result::FATAL_ERROR_LIBRARY_FAILURE;
  433. }
  434. // TODO: We still need to handle the fallback for expired responses. But,
  435. // if/when we disable OCSP fetching by default, it would be ambiguous whether
  436. // security.OCSP.enable==0 means "I want the default" or "I really never want
  437. // you to ever fetch OCSP."
  438. Duration shortLifetime(mCertShortLifetimeInDays * Time::ONE_DAY_IN_SECONDS);
  439. if ((mOCSPFetching == NeverFetchOCSP) ||
  440. (validityDuration < shortLifetime) ||
  441. (endEntityOrCA == EndEntityOrCA::MustBeCA &&
  442. (mOCSPFetching == FetchOCSPForDVHardFail ||
  443. mOCSPFetching == FetchOCSPForDVSoftFail ||
  444. blocklistIsFresh))) {
  445. // We're not going to be doing any fetching, so if there was a cached
  446. // "unknown" response, say so.
  447. if (cachedResponseResult == Result::ERROR_OCSP_UNKNOWN_CERT) {
  448. return Result::ERROR_OCSP_UNKNOWN_CERT;
  449. }
  450. // If we're doing hard-fail, we want to know if we have a cached response
  451. // that has expired.
  452. if (mOCSPFetching == FetchOCSPForDVHardFail &&
  453. cachedResponseResult == Result::ERROR_OCSP_OLD_RESPONSE) {
  454. return Result::ERROR_OCSP_OLD_RESPONSE;
  455. }
  456. return Success;
  457. }
  458. if (mOCSPFetching == LocalOnlyOCSPForEV) {
  459. if (cachedResponseResult != Success) {
  460. return cachedResponseResult;
  461. }
  462. return Result::ERROR_OCSP_UNKNOWN_CERT;
  463. }
  464. UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
  465. if (!arena) {
  466. return Result::FATAL_ERROR_NO_MEMORY;
  467. }
  468. Result rv;
  469. const char* url = nullptr; // owned by the arena
  470. if (aiaExtension) {
  471. rv = GetOCSPAuthorityInfoAccessLocation(arena, *aiaExtension, url);
  472. if (rv != Success) {
  473. return rv;
  474. }
  475. }
  476. if (!url) {
  477. if (mOCSPFetching == FetchOCSPForEV ||
  478. cachedResponseResult == Result::ERROR_OCSP_UNKNOWN_CERT) {
  479. return Result::ERROR_OCSP_UNKNOWN_CERT;
  480. }
  481. if (cachedResponseResult == Result::ERROR_OCSP_OLD_RESPONSE) {
  482. return Result::ERROR_OCSP_OLD_RESPONSE;
  483. }
  484. if (stapledOCSPResponseResult != Success) {
  485. return stapledOCSPResponseResult;
  486. }
  487. // Nothing to do if we don't have an OCSP responder URI for the cert; just
  488. // assume it is good. Note that this is the confusing, but intended,
  489. // interpretation of "strict" revocation checking in the face of a
  490. // certificate that lacks an OCSP responder URI.
  491. return Success;
  492. }
  493. // Only request a response if we didn't have a cached indication of failure
  494. // (don't keep requesting responses from a failing server).
  495. Input response;
  496. bool attemptedRequest;
  497. if (cachedResponseResult == Success ||
  498. cachedResponseResult == Result::ERROR_OCSP_UNKNOWN_CERT ||
  499. cachedResponseResult == Result::ERROR_OCSP_OLD_RESPONSE) {
  500. uint8_t ocspRequest[OCSP_REQUEST_MAX_LENGTH];
  501. size_t ocspRequestLength;
  502. rv = CreateEncodedOCSPRequest(*this, certID, ocspRequest,
  503. ocspRequestLength);
  504. if (rv != Success) {
  505. return rv;
  506. }
  507. SECItem ocspRequestItem = {
  508. siBuffer,
  509. ocspRequest,
  510. static_cast<unsigned int>(ocspRequestLength)
  511. };
  512. // Owned by arena
  513. SECItem* responseSECItem = nullptr;
  514. Result tempRV =
  515. DoOCSPRequest(arena, url, mOriginAttributes, &ocspRequestItem,
  516. OCSPFetchingTypeToTimeoutTime(mOCSPFetching),
  517. mOCSPGetConfig == CertVerifier::ocspGetEnabled,
  518. responseSECItem);
  519. MOZ_ASSERT((tempRV != Success) || responseSECItem);
  520. if (tempRV != Success) {
  521. rv = tempRV;
  522. } else if (response.Init(responseSECItem->data, responseSECItem->len)
  523. != Success) {
  524. rv = Result::ERROR_OCSP_MALFORMED_RESPONSE; // too big
  525. }
  526. attemptedRequest = true;
  527. } else {
  528. rv = cachedResponseResult;
  529. attemptedRequest = false;
  530. }
  531. if (response.GetLength() == 0) {
  532. Result error = rv;
  533. if (attemptedRequest) {
  534. Time timeout(time);
  535. if (timeout.AddSeconds(ServerFailureDelaySeconds) != Success) {
  536. return Result::FATAL_ERROR_LIBRARY_FAILURE; // integer overflow
  537. }
  538. rv = mOCSPCache.Put(certID, mOriginAttributes, error, time, timeout);
  539. if (rv != Success) {
  540. return rv;
  541. }
  542. }
  543. if (mOCSPFetching != FetchOCSPForDVSoftFail) {
  544. MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
  545. ("NSSCertDBTrustDomain: returning SECFailure after "
  546. "OCSP request failure"));
  547. return error;
  548. }
  549. if (cachedResponseResult == Result::ERROR_OCSP_UNKNOWN_CERT) {
  550. MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
  551. ("NSSCertDBTrustDomain: returning SECFailure from cached "
  552. "response after OCSP request failure"));
  553. return cachedResponseResult;
  554. }
  555. if (stapledOCSPResponseResult != Success) {
  556. MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
  557. ("NSSCertDBTrustDomain: returning SECFailure from expired "
  558. "stapled response after OCSP request failure"));
  559. return stapledOCSPResponseResult;
  560. }
  561. MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
  562. ("NSSCertDBTrustDomain: returning SECSuccess after "
  563. "OCSP request failure"));
  564. return Success; // Soft fail -> success :(
  565. }
  566. // If the response from the network has expired but indicates a revoked
  567. // or unknown certificate, PR_GetError() will return the appropriate error.
  568. // We actually ignore expired here.
  569. bool expired;
  570. rv = VerifyAndMaybeCacheEncodedOCSPResponse(certID, time,
  571. maxOCSPLifetimeInDays,
  572. response, ResponseIsFromNetwork,
  573. expired);
  574. if (rv == Success || mOCSPFetching != FetchOCSPForDVSoftFail) {
  575. MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
  576. ("NSSCertDBTrustDomain: returning after VerifyEncodedOCSPResponse"));
  577. return rv;
  578. }
  579. if (rv == Result::ERROR_OCSP_UNKNOWN_CERT ||
  580. rv == Result::ERROR_REVOKED_CERTIFICATE) {
  581. return rv;
  582. }
  583. if (stapledOCSPResponseResult != Success) {
  584. MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
  585. ("NSSCertDBTrustDomain: returning SECFailure from expired stapled "
  586. "response after OCSP request verification failure"));
  587. return stapledOCSPResponseResult;
  588. }
  589. MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
  590. ("NSSCertDBTrustDomain: end of CheckRevocation"));
  591. return Success; // Soft fail -> success :(
  592. }
  593. Result
  594. NSSCertDBTrustDomain::VerifyAndMaybeCacheEncodedOCSPResponse(
  595. const CertID& certID, Time time, uint16_t maxLifetimeInDays,
  596. Input encodedResponse, EncodedResponseSource responseSource,
  597. /*out*/ bool& expired)
  598. {
  599. Time thisUpdate(Time::uninitialized);
  600. Time validThrough(Time::uninitialized);
  601. // We use a try and fallback approach which first mandates good signature
  602. // digest algorithms, then falls back to SHA-1 if this fails. If a delegated
  603. // OCSP response signing certificate was issued with a SHA-1 signature,
  604. // verification initially fails. We cache the failure and then re-use that
  605. // result even when doing fallback (i.e. when weak signature digest algorithms
  606. // should succeed). To address this we use an OCSPVerificationTrustDomain
  607. // here, rather than using *this, to ensure verification succeeds for all
  608. // allowed signature digest algorithms.
  609. OCSPVerificationTrustDomain trustDomain(*this);
  610. Result rv = VerifyEncodedOCSPResponse(trustDomain, certID, time,
  611. maxLifetimeInDays, encodedResponse,
  612. expired, &thisUpdate, &validThrough);
  613. // If a response was stapled and expired, we don't want to cache it. Return
  614. // early to simplify the logic here.
  615. if (responseSource == ResponseWasStapled && expired) {
  616. PR_ASSERT(rv != Success);
  617. return rv;
  618. }
  619. // validThrough is only trustworthy if the response successfully verifies
  620. // or it indicates a revoked or unknown certificate.
  621. // If this isn't the case, store an indication of failure (to prevent
  622. // repeatedly requesting a response from a failing server).
  623. if (rv != Success && rv != Result::ERROR_REVOKED_CERTIFICATE &&
  624. rv != Result::ERROR_OCSP_UNKNOWN_CERT) {
  625. validThrough = time;
  626. if (validThrough.AddSeconds(ServerFailureDelaySeconds) != Success) {
  627. return Result::FATAL_ERROR_LIBRARY_FAILURE; // integer overflow
  628. }
  629. }
  630. if (responseSource == ResponseIsFromNetwork ||
  631. rv == Success ||
  632. rv == Result::ERROR_REVOKED_CERTIFICATE ||
  633. rv == Result::ERROR_OCSP_UNKNOWN_CERT) {
  634. MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
  635. ("NSSCertDBTrustDomain: caching OCSP response"));
  636. Result putRV = mOCSPCache.Put(certID, mOriginAttributes, rv, thisUpdate,
  637. validThrough);
  638. if (putRV != Success) {
  639. return putRV;
  640. }
  641. }
  642. return rv;
  643. }
  644. static const uint8_t CNNIC_ROOT_CA_SUBJECT_DATA[] =
  645. "\x30\x32\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x43\x4E\x31\x0E\x30"
  646. "\x0C\x06\x03\x55\x04\x0A\x13\x05\x43\x4E\x4E\x49\x43\x31\x13\x30\x11\x06"
  647. "\x03\x55\x04\x03\x13\x0A\x43\x4E\x4E\x49\x43\x20\x52\x4F\x4F\x54";
  648. static const uint8_t CNNIC_EV_ROOT_CA_SUBJECT_DATA[] =
  649. "\x30\x81\x8A\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x43\x4E\x31\x32"
  650. "\x30\x30\x06\x03\x55\x04\x0A\x0C\x29\x43\x68\x69\x6E\x61\x20\x49\x6E\x74"
  651. "\x65\x72\x6E\x65\x74\x20\x4E\x65\x74\x77\x6F\x72\x6B\x20\x49\x6E\x66\x6F"
  652. "\x72\x6D\x61\x74\x69\x6F\x6E\x20\x43\x65\x6E\x74\x65\x72\x31\x47\x30\x45"
  653. "\x06\x03\x55\x04\x03\x0C\x3E\x43\x68\x69\x6E\x61\x20\x49\x6E\x74\x65\x72"
  654. "\x6E\x65\x74\x20\x4E\x65\x74\x77\x6F\x72\x6B\x20\x49\x6E\x66\x6F\x72\x6D"
  655. "\x61\x74\x69\x6F\x6E\x20\x43\x65\x6E\x74\x65\x72\x20\x45\x56\x20\x43\x65"
  656. "\x72\x74\x69\x66\x69\x63\x61\x74\x65\x73\x20\x52\x6F\x6F\x74";
  657. class WhitelistedCNNICHashBinarySearchComparator
  658. {
  659. public:
  660. explicit WhitelistedCNNICHashBinarySearchComparator(const uint8_t* aTarget,
  661. size_t aTargetLength)
  662. : mTarget(aTarget)
  663. {
  664. MOZ_ASSERT(aTargetLength == CNNIC_WHITELIST_HASH_LEN,
  665. "Hashes should be of the same length.");
  666. }
  667. int operator()(const WhitelistedCNNICHash val) const {
  668. return memcmp(mTarget, val.hash, CNNIC_WHITELIST_HASH_LEN);
  669. }
  670. private:
  671. const uint8_t* mTarget;
  672. };
  673. static bool
  674. CertIsStartComOrWoSign(const CERTCertificate* cert)
  675. {
  676. for (const DataAndLength& dn : StartComAndWoSignDNs) {
  677. if (cert->derSubject.len == dn.len &&
  678. PodEqual(cert->derSubject.data, dn.data, dn.len)) {
  679. return true;
  680. }
  681. }
  682. return false;
  683. }
  684. // If a certificate in the given chain appears to have been issued by one of
  685. // seven roots operated by StartCom and WoSign that are not trusted to issue new
  686. // certificates, verify that the end-entity has a notBefore date before 21
  687. // October 2016. If the value of notBefore is after this time, the chain is not
  688. // valid.
  689. // (NB: While there are seven distinct roots being checked for, two of them
  690. // share distinguished names, resulting in six distinct distinguished names to
  691. // actually look for.)
  692. static Result
  693. CheckForStartComOrWoSign(const UniqueCERTCertList& certChain)
  694. {
  695. if (CERT_LIST_EMPTY(certChain)) {
  696. return Result::FATAL_ERROR_LIBRARY_FAILURE;
  697. }
  698. const CERTCertListNode* endEntityNode = CERT_LIST_HEAD(certChain);
  699. if (!endEntityNode || !endEntityNode->cert) {
  700. return Result::FATAL_ERROR_LIBRARY_FAILURE;
  701. }
  702. PRTime notBefore;
  703. PRTime notAfter;
  704. if (CERT_GetCertTimes(endEntityNode->cert, &notBefore, &notAfter)
  705. != SECSuccess) {
  706. return Result::FATAL_ERROR_LIBRARY_FAILURE;
  707. }
  708. // PRTime is microseconds since the epoch, whereas JS time is milliseconds.
  709. // (new Date("2016-10-21T00:00:00Z")).getTime() * 1000
  710. static const PRTime OCTOBER_21_2016 = 1477008000000000;
  711. if (notBefore <= OCTOBER_21_2016) {
  712. return Success;
  713. }
  714. for (const CERTCertListNode* node = CERT_LIST_HEAD(certChain);
  715. !CERT_LIST_END(node, certChain); node = CERT_LIST_NEXT(node)) {
  716. if (!node || !node->cert) {
  717. return Result::FATAL_ERROR_LIBRARY_FAILURE;
  718. }
  719. if (CertIsStartComOrWoSign(node->cert)) {
  720. return Result::ERROR_REVOKED_CERTIFICATE;
  721. }
  722. }
  723. return Success;
  724. }
  725. Result
  726. NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray,
  727. Time time,
  728. const CertPolicyId& requiredPolicy)
  729. {
  730. MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
  731. ("NSSCertDBTrustDomain: IsChainValid"));
  732. UniqueCERTCertList certList;
  733. SECStatus srv = ConstructCERTCertListFromReversedDERArray(certArray,
  734. certList);
  735. if (srv != SECSuccess) {
  736. return MapPRErrorCodeToResult(PR_GetError());
  737. }
  738. if (CERT_LIST_EMPTY(certList)) {
  739. return Result::FATAL_ERROR_LIBRARY_FAILURE;
  740. }
  741. Result rv = CheckForStartComOrWoSign(certList);
  742. if (rv != Success) {
  743. return rv;
  744. }
  745. // If the certificate appears to have been issued by a CNNIC root, only allow
  746. // it if it is on the whitelist.
  747. CERTCertListNode* rootNode = CERT_LIST_TAIL(certList);
  748. if (!rootNode) {
  749. return Result::FATAL_ERROR_LIBRARY_FAILURE;
  750. }
  751. CERTCertificate* root = rootNode->cert;
  752. if (!root) {
  753. return Result::FATAL_ERROR_LIBRARY_FAILURE;
  754. }
  755. if ((root->derSubject.len == sizeof(CNNIC_ROOT_CA_SUBJECT_DATA) - 1 &&
  756. memcmp(root->derSubject.data, CNNIC_ROOT_CA_SUBJECT_DATA,
  757. root->derSubject.len) == 0) ||
  758. (root->derSubject.len == sizeof(CNNIC_EV_ROOT_CA_SUBJECT_DATA) - 1 &&
  759. memcmp(root->derSubject.data, CNNIC_EV_ROOT_CA_SUBJECT_DATA,
  760. root->derSubject.len) == 0)) {
  761. CERTCertListNode* certNode = CERT_LIST_HEAD(certList);
  762. if (!certNode) {
  763. return Result::FATAL_ERROR_LIBRARY_FAILURE;
  764. }
  765. CERTCertificate* cert = certNode->cert;
  766. if (!cert) {
  767. return Result::FATAL_ERROR_LIBRARY_FAILURE;
  768. }
  769. Digest digest;
  770. nsresult nsrv = digest.DigestBuf(SEC_OID_SHA256, cert->derCert.data,
  771. cert->derCert.len);
  772. if (NS_FAILED(nsrv)) {
  773. return Result::FATAL_ERROR_LIBRARY_FAILURE;
  774. }
  775. const uint8_t* certHash(
  776. BitwiseCast<uint8_t*, unsigned char*>(digest.get().data));
  777. size_t certHashLen = digest.get().len;
  778. size_t unused;
  779. if (!mozilla::BinarySearchIf(WhitelistedCNNICHashes, 0,
  780. ArrayLength(WhitelistedCNNICHashes),
  781. WhitelistedCNNICHashBinarySearchComparator(
  782. certHash, certHashLen),
  783. &unused)) {
  784. return Result::ERROR_REVOKED_CERTIFICATE;
  785. }
  786. }
  787. bool isBuiltInRoot = false;
  788. rv = IsCertBuiltInRoot(root, isBuiltInRoot);
  789. if (rv != Success) {
  790. return rv;
  791. }
  792. mBuiltChain = Move(certList);
  793. return Success;
  794. }
  795. Result
  796. NSSCertDBTrustDomain::CheckSignatureDigestAlgorithm(DigestAlgorithm aAlg,
  797. EndEntityOrCA endEntityOrCA,
  798. Time notBefore)
  799. {
  800. // (new Date("2016-01-01T00:00:00Z")).getTime() / 1000
  801. static const Time JANUARY_FIRST_2016 = TimeFromEpochInSeconds(1451606400);
  802. MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
  803. ("NSSCertDBTrustDomain: CheckSignatureDigestAlgorithm"));
  804. if (aAlg == DigestAlgorithm::sha1) {
  805. switch (mSHA1Mode) {
  806. case CertVerifier::SHA1Mode::Forbidden:
  807. MOZ_LOG(gCertVerifierLog, LogLevel::Debug, ("SHA-1 certificate rejected"));
  808. return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
  809. case CertVerifier::SHA1Mode::ImportedRootOrBefore2016:
  810. if (JANUARY_FIRST_2016 <= notBefore) {
  811. MOZ_LOG(gCertVerifierLog, LogLevel::Debug, ("Post-2015 SHA-1 certificate rejected"));
  812. return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
  813. }
  814. break;
  815. case CertVerifier::SHA1Mode::Allowed:
  816. // Enforcing that the resulting chain uses an imported root is only
  817. // possible at a higher level. This is done in CertVerifier::VerifyCert.
  818. case CertVerifier::SHA1Mode::ImportedRoot:
  819. default:
  820. break;
  821. // MSVC warns unless we explicitly handle this now-unused option.
  822. case CertVerifier::SHA1Mode::UsedToBeBefore2016ButNowIsForbidden:
  823. MOZ_ASSERT_UNREACHABLE("unexpected SHA1Mode type");
  824. return Result::FATAL_ERROR_LIBRARY_FAILURE;
  825. }
  826. }
  827. return Success;
  828. }
  829. Result
  830. NSSCertDBTrustDomain::CheckRSAPublicKeyModulusSizeInBits(
  831. EndEntityOrCA /*endEntityOrCA*/, unsigned int modulusSizeInBits)
  832. {
  833. if (modulusSizeInBits < mMinRSABits) {
  834. return Result::ERROR_INADEQUATE_KEY_SIZE;
  835. }
  836. return Success;
  837. }
  838. Result
  839. NSSCertDBTrustDomain::VerifyRSAPKCS1SignedDigest(
  840. const SignedDigest& signedDigest,
  841. Input subjectPublicKeyInfo)
  842. {
  843. return VerifyRSAPKCS1SignedDigestNSS(signedDigest, subjectPublicKeyInfo,
  844. mPinArg);
  845. }
  846. Result
  847. NSSCertDBTrustDomain::CheckECDSACurveIsAcceptable(
  848. EndEntityOrCA /*endEntityOrCA*/, NamedCurve curve)
  849. {
  850. switch (curve) {
  851. case NamedCurve::secp256r1: // fall through
  852. case NamedCurve::secp384r1: // fall through
  853. case NamedCurve::secp521r1:
  854. return Success;
  855. }
  856. return Result::ERROR_UNSUPPORTED_ELLIPTIC_CURVE;
  857. }
  858. Result
  859. NSSCertDBTrustDomain::VerifyECDSASignedDigest(const SignedDigest& signedDigest,
  860. Input subjectPublicKeyInfo)
  861. {
  862. return VerifyECDSASignedDigestNSS(signedDigest, subjectPublicKeyInfo,
  863. mPinArg);
  864. }
  865. Result
  866. NSSCertDBTrustDomain::CheckValidityIsAcceptable(Time notBefore, Time notAfter,
  867. EndEntityOrCA endEntityOrCA,
  868. KeyPurposeId keyPurpose)
  869. {
  870. if (endEntityOrCA != EndEntityOrCA::MustBeEndEntity) {
  871. return Success;
  872. }
  873. if (keyPurpose == KeyPurposeId::id_kp_OCSPSigning) {
  874. return Success;
  875. }
  876. Duration DURATION_27_MONTHS_PLUS_SLOP((2 * 365 + 3 * 31 + 7) *
  877. Time::ONE_DAY_IN_SECONDS);
  878. Duration maxValidityDuration(UINT64_MAX);
  879. Duration validityDuration(notBefore, notAfter);
  880. switch (mValidityCheckingMode) {
  881. case ValidityCheckingMode::CheckingOff:
  882. return Success;
  883. case ValidityCheckingMode::CheckForEV:
  884. // The EV Guidelines say the maximum is 27 months, but we use a slightly
  885. // higher limit here to (hopefully) minimize compatibility breakage.
  886. maxValidityDuration = DURATION_27_MONTHS_PLUS_SLOP;
  887. break;
  888. default:
  889. PR_NOT_REACHED("We're not handling every ValidityCheckingMode type");
  890. }
  891. if (validityDuration > maxValidityDuration) {
  892. return Result::ERROR_VALIDITY_TOO_LONG;
  893. }
  894. return Success;
  895. }
  896. Result
  897. NSSCertDBTrustDomain::NetscapeStepUpMatchesServerAuth(Time notBefore,
  898. /*out*/ bool& matches)
  899. {
  900. // (new Date("2015-08-23T00:00:00Z")).getTime() / 1000
  901. static const Time AUGUST_23_2015 = TimeFromEpochInSeconds(1440288000);
  902. // (new Date("2016-08-23T00:00:00Z")).getTime() / 1000
  903. static const Time AUGUST_23_2016 = TimeFromEpochInSeconds(1471910400);
  904. switch (mNetscapeStepUpPolicy) {
  905. case NetscapeStepUpPolicy::AlwaysMatch:
  906. matches = true;
  907. return Success;
  908. case NetscapeStepUpPolicy::MatchBefore23August2016:
  909. matches = notBefore < AUGUST_23_2016;
  910. return Success;
  911. case NetscapeStepUpPolicy::MatchBefore23August2015:
  912. matches = notBefore < AUGUST_23_2015;
  913. return Success;
  914. case NetscapeStepUpPolicy::NeverMatch:
  915. matches = false;
  916. return Success;
  917. default:
  918. MOZ_ASSERT_UNREACHABLE("unhandled NetscapeStepUpPolicy type");
  919. }
  920. return Result::FATAL_ERROR_LIBRARY_FAILURE;
  921. }
  922. void
  923. NSSCertDBTrustDomain::ResetAccumulatedState()
  924. {
  925. mOCSPStaplingStatus = CertVerifier::OCSP_STAPLING_NEVER_CHECKED;
  926. mSCTListFromOCSPStapling = nullptr;
  927. mSCTListFromCertificate = nullptr;
  928. }
  929. static Input
  930. SECItemToInput(const UniqueSECItem& item)
  931. {
  932. Input result;
  933. if (item) {
  934. MOZ_ASSERT(item->type == siBuffer);
  935. Result rv = result.Init(item->data, item->len);
  936. // As used here, |item| originally comes from an Input,
  937. // so there should be no issues converting it back.
  938. MOZ_ASSERT(rv == Success);
  939. Unused << rv; // suppresses warnings in release builds
  940. }
  941. return result;
  942. }
  943. Input
  944. NSSCertDBTrustDomain::GetSCTListFromCertificate() const
  945. {
  946. return SECItemToInput(mSCTListFromCertificate);
  947. }
  948. Input
  949. NSSCertDBTrustDomain::GetSCTListFromOCSPStapling() const
  950. {
  951. return SECItemToInput(mSCTListFromOCSPStapling);
  952. }
  953. void
  954. NSSCertDBTrustDomain::NoteAuxiliaryExtension(AuxiliaryExtension extension,
  955. Input extensionData)
  956. {
  957. UniqueSECItem* out = nullptr;
  958. switch (extension) {
  959. case AuxiliaryExtension::EmbeddedSCTList:
  960. out = &mSCTListFromCertificate;
  961. break;
  962. case AuxiliaryExtension::SCTListFromOCSPResponse:
  963. out = &mSCTListFromOCSPStapling;
  964. break;
  965. default:
  966. MOZ_ASSERT_UNREACHABLE("unhandled AuxiliaryExtension");
  967. }
  968. if (out) {
  969. SECItem extensionDataItem = UnsafeMapInputToSECItem(extensionData);
  970. out->reset(SECITEM_DupItem(&extensionDataItem));
  971. }
  972. }
  973. SECStatus
  974. InitializeNSS(const nsACString& dir, bool readOnly, bool loadPKCS11Modules)
  975. {
  976. MOZ_ASSERT(NS_IsMainThread());
  977. // The NSS_INIT_NOROOTINIT flag turns off the loading of the root certs
  978. // module by NSS_Initialize because we will load it in InstallLoadableRoots
  979. // later. It also allows us to work around a bug in the system NSS in
  980. // Ubuntu 8.04, which loads any nonexistent "<configdir>/libnssckbi.so" as
  981. // "/usr/lib/nss/libnssckbi.so".
  982. uint32_t flags = NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE;
  983. if (readOnly) {
  984. flags |= NSS_INIT_READONLY;
  985. }
  986. if (!loadPKCS11Modules) {
  987. flags |= NSS_INIT_NOMODDB;
  988. }
  989. nsAutoCString dbTypeAndDirectory;
  990. #ifdef MOZ_SECURITY_SQLSTORE
  991. // Not strictly necessary with current NSS versions, but can't hurt to be explicit.
  992. dbTypeAndDirectory.Append("sql:");
  993. #else
  994. dbTypeAndDirectory.Append("dbm:");
  995. #endif
  996. dbTypeAndDirectory.Append(dir);
  997. return ::NSS_Initialize(dbTypeAndDirectory.get(), "", "", SECMOD_DB, flags);
  998. }
  999. void
  1000. DisableMD5()
  1001. {
  1002. NSS_SetAlgorithmPolicy(SEC_OID_MD5,
  1003. 0, NSS_USE_ALG_IN_CERT_SIGNATURE | NSS_USE_ALG_IN_CMS_SIGNATURE);
  1004. NSS_SetAlgorithmPolicy(SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION,
  1005. 0, NSS_USE_ALG_IN_CERT_SIGNATURE | NSS_USE_ALG_IN_CMS_SIGNATURE);
  1006. NSS_SetAlgorithmPolicy(SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC,
  1007. 0, NSS_USE_ALG_IN_CERT_SIGNATURE | NSS_USE_ALG_IN_CMS_SIGNATURE);
  1008. }
  1009. SECStatus
  1010. LoadLoadableRoots(/*optional*/ const char* dir, const char* modNameUTF8)
  1011. {
  1012. PR_ASSERT(modNameUTF8);
  1013. if (!modNameUTF8) {
  1014. PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
  1015. return SECFailure;
  1016. }
  1017. UniquePtr<char, void(&)(char*)>
  1018. fullLibraryPath(PR_GetLibraryName(dir, "nssckbi"), PR_FreeLibraryName);
  1019. if (!fullLibraryPath) {
  1020. return SECFailure;
  1021. }
  1022. // Escape the \ and " characters.
  1023. nsAutoCString escapedFullLibraryPath(fullLibraryPath.get());
  1024. escapedFullLibraryPath.ReplaceSubstring("\\", "\\\\");
  1025. escapedFullLibraryPath.ReplaceSubstring("\"", "\\\"");
  1026. if (escapedFullLibraryPath.IsEmpty()) {
  1027. return SECFailure;
  1028. }
  1029. // If a module exists with the same name, delete it.
  1030. int modType;
  1031. SECMOD_DeleteModule(modNameUTF8, &modType);
  1032. nsAutoCString pkcs11ModuleSpec;
  1033. pkcs11ModuleSpec.AppendPrintf("name=\"%s\" library=\"%s\"", modNameUTF8,
  1034. escapedFullLibraryPath.get());
  1035. if (pkcs11ModuleSpec.IsEmpty()) {
  1036. return SECFailure;
  1037. }
  1038. UniqueSECMODModule rootsModule(
  1039. SECMOD_LoadUserModule(const_cast<char*>(pkcs11ModuleSpec.get()), nullptr,
  1040. false));
  1041. if (!rootsModule) {
  1042. return SECFailure;
  1043. }
  1044. if (!rootsModule->loaded) {
  1045. PR_SetError(PR_INVALID_STATE_ERROR, 0);
  1046. return SECFailure;
  1047. }
  1048. return SECSuccess;
  1049. }
  1050. void
  1051. UnloadLoadableRoots(const char* modNameUTF8)
  1052. {
  1053. PR_ASSERT(modNameUTF8);
  1054. UniqueSECMODModule rootsModule(SECMOD_FindModule(modNameUTF8));
  1055. if (rootsModule) {
  1056. SECMOD_UnloadUserModule(rootsModule.get());
  1057. }
  1058. }
  1059. nsresult
  1060. DefaultServerNicknameForCert(const CERTCertificate* cert,
  1061. /*out*/ nsCString& nickname)
  1062. {
  1063. MOZ_ASSERT(cert);
  1064. NS_ENSURE_ARG_POINTER(cert);
  1065. UniquePORTString baseName(CERT_GetCommonName(&cert->subject));
  1066. if (!baseName) {
  1067. baseName = UniquePORTString(CERT_GetOrgUnitName(&cert->subject));
  1068. }
  1069. if (!baseName) {
  1070. baseName = UniquePORTString(CERT_GetOrgName(&cert->subject));
  1071. }
  1072. if (!baseName) {
  1073. baseName = UniquePORTString(CERT_GetLocalityName(&cert->subject));
  1074. }
  1075. if (!baseName) {
  1076. baseName = UniquePORTString(CERT_GetStateName(&cert->subject));
  1077. }
  1078. if (!baseName) {
  1079. baseName = UniquePORTString(CERT_GetCountryName(&cert->subject));
  1080. }
  1081. if (!baseName) {
  1082. return NS_ERROR_FAILURE;
  1083. }
  1084. // This function is only used in contexts where a failure to find a suitable
  1085. // nickname does not block the overall task from succeeding.
  1086. // As such, we use an arbitrary limit to prevent this nickname searching
  1087. // process from taking forever.
  1088. static const uint32_t ARBITRARY_LIMIT = 500;
  1089. for (uint32_t count = 1; count < ARBITRARY_LIMIT; count++) {
  1090. nickname = baseName.get();
  1091. if (count != 1) {
  1092. nickname.AppendPrintf(" #%u", count);
  1093. }
  1094. if (nickname.IsEmpty()) {
  1095. return NS_ERROR_FAILURE;
  1096. }
  1097. bool conflict = SEC_CertNicknameConflict(nickname.get(), &cert->derSubject,
  1098. cert->dbhandle);
  1099. if (!conflict) {
  1100. return NS_OK;
  1101. }
  1102. }
  1103. return NS_ERROR_FAILURE;
  1104. }
  1105. /**
  1106. * Given a list of certificates representing a verified certificate path from an
  1107. * end-entity certificate to a trust anchor, imports the intermediate
  1108. * certificates into the permanent certificate database. This is an attempt to
  1109. * cope with misconfigured servers that don't include the appropriate
  1110. * intermediate certificates in the TLS handshake.
  1111. *
  1112. * @param certList the verified certificate list
  1113. */
  1114. void
  1115. SaveIntermediateCerts(const UniqueCERTCertList& certList)
  1116. {
  1117. if (!certList) {
  1118. return;
  1119. }
  1120. UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
  1121. if (!slot) {
  1122. return;
  1123. }
  1124. bool isEndEntity = true;
  1125. for (CERTCertListNode* node = CERT_LIST_HEAD(certList);
  1126. !CERT_LIST_END(node, certList);
  1127. node = CERT_LIST_NEXT(node)) {
  1128. if (isEndEntity) {
  1129. // Skip the end-entity; we only want to store intermediates
  1130. isEndEntity = false;
  1131. continue;
  1132. }
  1133. if (node->cert->slot) {
  1134. // This cert was found on a token; no need to remember it in the permanent
  1135. // database.
  1136. continue;
  1137. }
  1138. if (node->cert->isperm) {
  1139. // We don't need to remember certs already stored in perm db.
  1140. continue;
  1141. }
  1142. // No need to save the trust anchor - it's either already a permanent
  1143. // certificate or it's the Microsoft Family Safety root or an enterprise
  1144. // root temporarily imported via the child mode or enterprise root features.
  1145. // We don't want to import these because they're intended to be temporary
  1146. // (and because importing them happens to reset their trust settings, which
  1147. // breaks these features).
  1148. if (node == CERT_LIST_TAIL(certList)) {
  1149. continue;
  1150. }
  1151. nsAutoCString nickname;
  1152. nsresult rv = DefaultServerNicknameForCert(node->cert, nickname);
  1153. if (NS_FAILED(rv)) {
  1154. continue;
  1155. }
  1156. // As mentioned in the documentation of this function, we're importing only
  1157. // to cope with misconfigured servers. As such, we ignore the return value
  1158. // below, since it doesn't really matter if the import fails.
  1159. Unused << PK11_ImportCert(slot.get(), node->cert, CK_INVALID_HANDLE,
  1160. nickname.get(), false);
  1161. }
  1162. }
  1163. } } // namespace mozilla::psm