AppTrustDomain.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  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 "AppTrustDomain.h"
  6. #include "MainThreadUtils.h"
  7. #include "certdb.h"
  8. #include "mozilla/ArrayUtils.h"
  9. #include "mozilla/Casting.h"
  10. #include "mozilla/Preferences.h"
  11. #include "nsComponentManagerUtils.h"
  12. #include "nsIFile.h"
  13. #include "nsIFileStreams.h"
  14. #include "nsIX509CertDB.h"
  15. #include "nsNSSCertificate.h"
  16. #include "nsNetUtil.h"
  17. #include "pkix/pkixnss.h"
  18. #include "prerror.h"
  19. #include "secerr.h"
  20. // Generated in Makefile.in
  21. #include "marketplace-prod-public.inc"
  22. #include "marketplace-prod-reviewers.inc"
  23. #include "marketplace-dev-public.inc"
  24. #include "marketplace-dev-reviewers.inc"
  25. #include "marketplace-stage.inc"
  26. #include "xpcshell.inc"
  27. // Trusted Hosted Apps Certificates
  28. #include "manifest-signing-root.inc"
  29. #include "manifest-signing-test-root.inc"
  30. // Add-on signing Certificates
  31. #include "addons-public.inc"
  32. #include "addons-stage.inc"
  33. // Privileged Package Certificates
  34. #include "privileged-package-root.inc"
  35. using namespace mozilla::pkix;
  36. extern mozilla::LazyLogModule gPIPNSSLog;
  37. static const unsigned int DEFAULT_MIN_RSA_BITS = 2048;
  38. static char kDevImportedDER[] =
  39. "network.http.signed-packages.developer-root";
  40. namespace mozilla { namespace psm {
  41. StaticMutex AppTrustDomain::sMutex;
  42. UniquePtr<unsigned char[]> AppTrustDomain::sDevImportedDERData;
  43. unsigned int AppTrustDomain::sDevImportedDERLen = 0;
  44. AppTrustDomain::AppTrustDomain(UniqueCERTCertList& certChain, void* pinArg)
  45. : mCertChain(certChain)
  46. , mPinArg(pinArg)
  47. , mMinRSABits(DEFAULT_MIN_RSA_BITS)
  48. {
  49. }
  50. SECStatus
  51. AppTrustDomain::SetTrustedRoot(AppTrustedRoot trustedRoot)
  52. {
  53. SECItem trustedDER;
  54. // Load the trusted certificate into the in-memory NSS database so that
  55. // CERT_CreateSubjectCertList can find it.
  56. switch (trustedRoot)
  57. {
  58. case nsIX509CertDB::AppMarketplaceProdPublicRoot:
  59. trustedDER.data = const_cast<uint8_t*>(marketplaceProdPublicRoot);
  60. trustedDER.len = mozilla::ArrayLength(marketplaceProdPublicRoot);
  61. break;
  62. case nsIX509CertDB::AppMarketplaceProdReviewersRoot:
  63. trustedDER.data = const_cast<uint8_t*>(marketplaceProdReviewersRoot);
  64. trustedDER.len = mozilla::ArrayLength(marketplaceProdReviewersRoot);
  65. break;
  66. case nsIX509CertDB::AppMarketplaceDevPublicRoot:
  67. trustedDER.data = const_cast<uint8_t*>(marketplaceDevPublicRoot);
  68. trustedDER.len = mozilla::ArrayLength(marketplaceDevPublicRoot);
  69. break;
  70. case nsIX509CertDB::AppMarketplaceDevReviewersRoot:
  71. trustedDER.data = const_cast<uint8_t*>(marketplaceDevReviewersRoot);
  72. trustedDER.len = mozilla::ArrayLength(marketplaceDevReviewersRoot);
  73. break;
  74. case nsIX509CertDB::AppMarketplaceStageRoot:
  75. trustedDER.data = const_cast<uint8_t*>(marketplaceStageRoot);
  76. trustedDER.len = mozilla::ArrayLength(marketplaceStageRoot);
  77. // The staging root was generated with a 1024-bit key.
  78. mMinRSABits = 1024u;
  79. break;
  80. case nsIX509CertDB::AppXPCShellRoot:
  81. trustedDER.data = const_cast<uint8_t*>(xpcshellRoot);
  82. trustedDER.len = mozilla::ArrayLength(xpcshellRoot);
  83. break;
  84. case nsIX509CertDB::AddonsPublicRoot:
  85. trustedDER.data = const_cast<uint8_t*>(addonsPublicRoot);
  86. trustedDER.len = mozilla::ArrayLength(addonsPublicRoot);
  87. break;
  88. case nsIX509CertDB::AddonsStageRoot:
  89. trustedDER.data = const_cast<uint8_t*>(addonsStageRoot);
  90. trustedDER.len = mozilla::ArrayLength(addonsStageRoot);
  91. break;
  92. case nsIX509CertDB::PrivilegedPackageRoot:
  93. trustedDER.data = const_cast<uint8_t*>(privilegedPackageRoot);
  94. trustedDER.len = mozilla::ArrayLength(privilegedPackageRoot);
  95. break;
  96. case nsIX509CertDB::DeveloperImportedRoot: {
  97. StaticMutexAutoLock lock(sMutex);
  98. if (!sDevImportedDERData) {
  99. MOZ_ASSERT(!NS_IsMainThread());
  100. nsCOMPtr<nsIFile> file(do_CreateInstance("@mozilla.org/file/local;1"));
  101. if (!file) {
  102. PR_SetError(SEC_ERROR_IO, 0);
  103. return SECFailure;
  104. }
  105. nsresult rv = file->InitWithNativePath(
  106. Preferences::GetCString(kDevImportedDER));
  107. if (NS_FAILED(rv)) {
  108. PR_SetError(SEC_ERROR_IO, 0);
  109. return SECFailure;
  110. }
  111. nsCOMPtr<nsIInputStream> inputStream;
  112. NS_NewLocalFileInputStream(getter_AddRefs(inputStream), file, -1, -1,
  113. nsIFileInputStream::CLOSE_ON_EOF);
  114. if (!inputStream) {
  115. PR_SetError(SEC_ERROR_IO, 0);
  116. return SECFailure;
  117. }
  118. uint64_t length;
  119. rv = inputStream->Available(&length);
  120. if (NS_FAILED(rv)) {
  121. PR_SetError(SEC_ERROR_IO, 0);
  122. return SECFailure;
  123. }
  124. auto data = MakeUnique<char[]>(length);
  125. rv = inputStream->Read(data.get(), length, &sDevImportedDERLen);
  126. if (NS_FAILED(rv)) {
  127. PR_SetError(SEC_ERROR_IO, 0);
  128. return SECFailure;
  129. }
  130. MOZ_ASSERT(length == sDevImportedDERLen);
  131. sDevImportedDERData.reset(
  132. BitwiseCast<unsigned char*, char*>(data.release()));
  133. }
  134. trustedDER.data = sDevImportedDERData.get();
  135. trustedDER.len = sDevImportedDERLen;
  136. break;
  137. }
  138. default:
  139. PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
  140. return SECFailure;
  141. }
  142. mTrustedRoot.reset(CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
  143. &trustedDER, nullptr, false, true));
  144. if (!mTrustedRoot) {
  145. return SECFailure;
  146. }
  147. return SECSuccess;
  148. }
  149. Result
  150. AppTrustDomain::FindIssuer(Input encodedIssuerName, IssuerChecker& checker,
  151. Time)
  152. {
  153. MOZ_ASSERT(mTrustedRoot);
  154. if (!mTrustedRoot) {
  155. return Result::FATAL_ERROR_INVALID_STATE;
  156. }
  157. // TODO(bug 1035418): If/when mozilla::pkix relaxes the restriction that
  158. // FindIssuer must only pass certificates with a matching subject name to
  159. // checker.Check, we can stop using CERT_CreateSubjectCertList and instead
  160. // use logic like this:
  161. //
  162. // 1. First, try the trusted trust anchor.
  163. // 2. Secondly, iterate through the certificates that were stored in the CMS
  164. // message, passing each one to checker.Check.
  165. SECItem encodedIssuerNameSECItem =
  166. UnsafeMapInputToSECItem(encodedIssuerName);
  167. UniqueCERTCertList
  168. candidates(CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(),
  169. &encodedIssuerNameSECItem, 0,
  170. false));
  171. if (candidates) {
  172. for (CERTCertListNode* n = CERT_LIST_HEAD(candidates);
  173. !CERT_LIST_END(n, candidates); n = CERT_LIST_NEXT(n)) {
  174. Input certDER;
  175. Result rv = certDER.Init(n->cert->derCert.data, n->cert->derCert.len);
  176. if (rv != Success) {
  177. continue; // probably too big
  178. }
  179. bool keepGoing;
  180. rv = checker.Check(certDER, nullptr/*additionalNameConstraints*/,
  181. keepGoing);
  182. if (rv != Success) {
  183. return rv;
  184. }
  185. if (!keepGoing) {
  186. break;
  187. }
  188. }
  189. }
  190. return Success;
  191. }
  192. Result
  193. AppTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
  194. const CertPolicyId& policy,
  195. Input candidateCertDER,
  196. /*out*/ TrustLevel& trustLevel)
  197. {
  198. MOZ_ASSERT(policy.IsAnyPolicy());
  199. MOZ_ASSERT(mTrustedRoot);
  200. if (!policy.IsAnyPolicy()) {
  201. return Result::FATAL_ERROR_INVALID_ARGS;
  202. }
  203. if (!mTrustedRoot) {
  204. return Result::FATAL_ERROR_INVALID_STATE;
  205. }
  206. // Handle active distrust of the certificate.
  207. // XXX: This would be cleaner and more efficient if we could get the trust
  208. // information without constructing a CERTCertificate here, but NSS doesn't
  209. // expose it in any other easy-to-use fashion.
  210. SECItem candidateCertDERSECItem =
  211. UnsafeMapInputToSECItem(candidateCertDER);
  212. UniqueCERTCertificate candidateCert(
  213. CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &candidateCertDERSECItem,
  214. nullptr, false, true));
  215. if (!candidateCert) {
  216. return MapPRErrorCodeToResult(PR_GetError());
  217. }
  218. CERTCertTrust trust;
  219. if (CERT_GetCertTrust(candidateCert.get(), &trust) == SECSuccess) {
  220. uint32_t flags = SEC_GET_TRUST_FLAGS(&trust, trustObjectSigning);
  221. // For DISTRUST, we use the CERTDB_TRUSTED or CERTDB_TRUSTED_CA bit,
  222. // because we can have active distrust for either type of cert. Note that
  223. // CERTDB_TERMINAL_RECORD means "stop trying to inherit trust" so if the
  224. // relevant trust bit isn't set then that means the cert must be considered
  225. // distrusted.
  226. uint32_t relevantTrustBit = endEntityOrCA == EndEntityOrCA::MustBeCA
  227. ? CERTDB_TRUSTED_CA
  228. : CERTDB_TRUSTED;
  229. if (((flags & (relevantTrustBit | CERTDB_TERMINAL_RECORD)))
  230. == CERTDB_TERMINAL_RECORD) {
  231. trustLevel = TrustLevel::ActivelyDistrusted;
  232. return Success;
  233. }
  234. }
  235. // mTrustedRoot is the only trust anchor for this validation.
  236. if (CERT_CompareCerts(mTrustedRoot.get(), candidateCert.get())) {
  237. trustLevel = TrustLevel::TrustAnchor;
  238. return Success;
  239. }
  240. trustLevel = TrustLevel::InheritsTrust;
  241. return Success;
  242. }
  243. Result
  244. AppTrustDomain::DigestBuf(Input item,
  245. DigestAlgorithm digestAlg,
  246. /*out*/ uint8_t* digestBuf,
  247. size_t digestBufLen)
  248. {
  249. return DigestBufNSS(item, digestAlg, digestBuf, digestBufLen);
  250. }
  251. Result
  252. AppTrustDomain::CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
  253. /*optional*/ const Input*,
  254. /*optional*/ const Input*,
  255. /*optional*/ const Input*)
  256. {
  257. // We don't currently do revocation checking. If we need to distrust an Apps
  258. // certificate, we will use the active distrust mechanism.
  259. return Success;
  260. }
  261. Result
  262. AppTrustDomain::IsChainValid(const DERArray& certChain, Time time,
  263. const CertPolicyId& requiredPolicy)
  264. {
  265. SECStatus srv = ConstructCERTCertListFromReversedDERArray(certChain,
  266. mCertChain);
  267. if (srv != SECSuccess) {
  268. return MapPRErrorCodeToResult(PR_GetError());
  269. }
  270. return Success;
  271. }
  272. Result
  273. AppTrustDomain::CheckSignatureDigestAlgorithm(DigestAlgorithm,
  274. EndEntityOrCA,
  275. Time)
  276. {
  277. // TODO: We should restrict signatures to SHA-256 or better.
  278. return Success;
  279. }
  280. Result
  281. AppTrustDomain::CheckRSAPublicKeyModulusSizeInBits(
  282. EndEntityOrCA /*endEntityOrCA*/, unsigned int modulusSizeInBits)
  283. {
  284. if (modulusSizeInBits < mMinRSABits) {
  285. return Result::ERROR_INADEQUATE_KEY_SIZE;
  286. }
  287. return Success;
  288. }
  289. Result
  290. AppTrustDomain::VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
  291. Input subjectPublicKeyInfo)
  292. {
  293. // TODO: We should restrict signatures to SHA-256 or better.
  294. return VerifyRSAPKCS1SignedDigestNSS(signedDigest, subjectPublicKeyInfo,
  295. mPinArg);
  296. }
  297. Result
  298. AppTrustDomain::CheckECDSACurveIsAcceptable(EndEntityOrCA /*endEntityOrCA*/,
  299. NamedCurve curve)
  300. {
  301. switch (curve) {
  302. case NamedCurve::secp256r1: // fall through
  303. case NamedCurve::secp384r1: // fall through
  304. case NamedCurve::secp521r1:
  305. return Success;
  306. }
  307. return Result::ERROR_UNSUPPORTED_ELLIPTIC_CURVE;
  308. }
  309. Result
  310. AppTrustDomain::VerifyECDSASignedDigest(const SignedDigest& signedDigest,
  311. Input subjectPublicKeyInfo)
  312. {
  313. return VerifyECDSASignedDigestNSS(signedDigest, subjectPublicKeyInfo,
  314. mPinArg);
  315. }
  316. Result
  317. AppTrustDomain::CheckValidityIsAcceptable(Time /*notBefore*/, Time /*notAfter*/,
  318. EndEntityOrCA /*endEntityOrCA*/,
  319. KeyPurposeId /*keyPurpose*/)
  320. {
  321. return Success;
  322. }
  323. Result
  324. AppTrustDomain::NetscapeStepUpMatchesServerAuth(Time /*notBefore*/,
  325. /*out*/ bool& matches)
  326. {
  327. matches = false;
  328. return Success;
  329. }
  330. void
  331. AppTrustDomain::NoteAuxiliaryExtension(AuxiliaryExtension /*extension*/,
  332. Input /*extensionData*/)
  333. {
  334. }
  335. } } // namespace mozilla::psm