summaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
authorMoonchild <moonchild@palemoon.org>2022-07-22 00:16:06 +0000
committerMoonchild <moonchild@palemoon.org>2022-07-22 02:30:42 +0000
commitc6c045a7f7d19110986c60965da56f6864ea600b (patch)
tree425f1291d3d428d9edc3c1ff6d981ba6289d4e64 /security
parenta5421542e5fbeb2167cbdd4b2e19e7482a227ca7 (diff)
downloaduxp-c6c045a7f7d19110986c60965da56f6864ea600b.tar.gz
Issue #1966 - Remove support for Firefox Marketplace "apps"
Because UXP may be a platform, but it's not a mobile OS.
Diffstat (limited to 'security')
-rw-r--r--security/apps/AppSignatureVerification.cpp1559
-rw-r--r--security/apps/AppTrustDomain.cpp388
-rw-r--r--security/apps/AppTrustDomain.h89
-rw-r--r--security/apps/addons-public.crtbin1637 -> 0 bytes
-rw-r--r--security/apps/addons-stage.crtbin1895 -> 0 bytes
-rw-r--r--security/apps/gen_cert_header.py45
-rw-r--r--security/apps/marketplace-dev-public.crtbin964 -> 0 bytes
-rw-r--r--security/apps/marketplace-dev-reviewers.crtbin1012 -> 0 bytes
-rw-r--r--security/apps/marketplace-prod-public.crtbin1177 -> 0 bytes
-rw-r--r--security/apps/marketplace-prod-reviewers.crtbin1171 -> 0 bytes
-rw-r--r--security/apps/marketplace-stage.crtbin1157 -> 0 bytes
-rw-r--r--security/apps/moz.build43
-rw-r--r--security/apps/privileged-package-root.derbin930 -> 0 bytes
-rw-r--r--security/apps/trusted-app-public.der0
-rw-r--r--security/manager/ssl/nsIX509CertDB.idl73
15 files changed, 5 insertions, 2192 deletions
diff --git a/security/apps/AppSignatureVerification.cpp b/security/apps/AppSignatureVerification.cpp
deleted file mode 100644
index aed0b70c1c..0000000000
--- a/security/apps/AppSignatureVerification.cpp
+++ /dev/null
@@ -1,1559 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsNSSCertificateDB.h"
-
-#include "AppTrustDomain.h"
-#include "CryptoTask.h"
-#include "NSSCertDBTrustDomain.h"
-#include "ScopedNSSTypes.h"
-#include "base64.h"
-#include "certdb.h"
-#include "mozilla/Casting.h"
-#include "mozilla/Logging.h"
-#include "mozilla/RefPtr.h"
-#include "mozilla/UniquePtr.h"
-#include "nsCOMPtr.h"
-#include "nsComponentManagerUtils.h"
-#include "nsDataSignatureVerifier.h"
-#include "nsHashKeys.h"
-#include "nsIDirectoryEnumerator.h"
-#include "nsIFile.h"
-#include "nsIFileStreams.h"
-#include "nsIInputStream.h"
-#include "nsIStringEnumerator.h"
-#include "nsIZipReader.h"
-#include "nsNSSCertificate.h"
-#include "nsNetUtil.h"
-#include "nsProxyRelease.h"
-#include "nsString.h"
-#include "nsTHashtable.h"
-#include "nssb64.h"
-#include "pkix/pkix.h"
-#include "pkix/pkixnss.h"
-#include "plstr.h"
-#include "secmime.h"
-
-
-using namespace mozilla::pkix;
-using namespace mozilla;
-using namespace mozilla::psm;
-
-extern mozilla::LazyLogModule gPIPNSSLog;
-
-namespace {
-
-// Reads a maximum of 1MB from a stream into the supplied buffer.
-// The reason for the 1MB limit is because this function is used to read
-// signature-related files and we want to avoid OOM. The uncompressed length of
-// an entry can be hundreds of times larger than the compressed version,
-// especially if someone has specifically crafted the entry to cause OOM or to
-// consume massive amounts of disk space.
-//
-// @param stream The input stream to read from.
-// @param buf The buffer that we read the stream into, which must have
-// already been allocated.
-nsresult
-ReadStream(const nsCOMPtr<nsIInputStream>& stream, /*out*/ SECItem& buf)
-{
- // The size returned by Available() might be inaccurate so we need
- // to check that Available() matches up with the actual length of
- // the file.
- uint64_t length;
- nsresult rv = stream->Available(&length);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- // Cap the maximum accepted size of signature-related files at 1MB (which is
- // still crazily huge) to avoid OOM. The uncompressed length of an entry can be
- // hundreds of times larger than the compressed version, especially if
- // someone has speifically crafted the entry to cause OOM or to consume
- // massive amounts of disk space.
- static const uint32_t MAX_LENGTH = 1024 * 1024;
- if (length > MAX_LENGTH) {
- return NS_ERROR_FILE_TOO_BIG;
- }
-
- // With bug 164695 in mind we +1 to leave room for null-terminating
- // the buffer.
- SECITEM_AllocItem(buf, static_cast<uint32_t>(length + 1));
-
- // buf.len == length + 1. We attempt to read length + 1 bytes
- // instead of length, so that we can check whether the metadata for
- // the entry is incorrect.
- uint32_t bytesRead;
- rv = stream->Read(BitwiseCast<char*, unsigned char*>(buf.data), buf.len,
- &bytesRead);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- if (bytesRead != length) {
- return NS_ERROR_FILE_CORRUPTED;
- }
-
- buf.data[buf.len - 1] = 0; // null-terminate
-
- return NS_OK;
-}
-
-// Finds exactly one (signature metadata) JAR entry that matches the given
-// search pattern, and then load it. Fails if there are no matches or if
-// there is more than one match. If bugDigest is not null then on success
-// bufDigest will contain the SHA-1 digeset of the entry.
-nsresult
-FindAndLoadOneEntry(nsIZipReader * zip,
- const nsACString & searchPattern,
- /*out*/ nsACString & filename,
- /*out*/ SECItem & buf,
- /*optional, out*/ Digest * bufDigest)
-{
- nsCOMPtr<nsIUTF8StringEnumerator> files;
- nsresult rv = zip->FindEntries(searchPattern, getter_AddRefs(files));
- if (NS_FAILED(rv) || !files) {
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- bool more;
- rv = files->HasMore(&more);
- NS_ENSURE_SUCCESS(rv, rv);
- if (!more) {
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- rv = files->GetNext(filename);
- NS_ENSURE_SUCCESS(rv, rv);
-
- // Check if there is more than one match, if so then error!
- rv = files->HasMore(&more);
- NS_ENSURE_SUCCESS(rv, rv);
- if (more) {
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- nsCOMPtr<nsIInputStream> stream;
- rv = zip->GetInputStream(filename, getter_AddRefs(stream));
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = ReadStream(stream, buf);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return NS_ERROR_SIGNED_JAR_ENTRY_INVALID;
- }
-
- if (bufDigest) {
- rv = bufDigest->DigestBuf(SEC_OID_SHA1, buf.data, buf.len - 1);
- NS_ENSURE_SUCCESS(rv, rv);
- }
-
- return NS_OK;
-}
-
-// Verify the digest of an entry. We avoid loading the entire entry into memory
-// at once, which would require memory in proportion to the size of the largest
-// entry. Instead, we require only a small, fixed amount of memory.
-//
-// @param stream an input stream from a JAR entry or file depending on whether
-// it is from a signed archive or unpacked into a directory
-// @param digestFromManifest The digest that we're supposed to check the file's
-// contents against, from the manifest
-// @param buf A scratch buffer that we use for doing the I/O, which must have
-// already been allocated. The size of this buffer is the unit
-// size of our I/O.
-nsresult
-VerifyStreamContentDigest(nsIInputStream* stream,
- const SECItem& digestFromManifest, SECItem& buf)
-{
- MOZ_ASSERT(buf.len > 0);
- if (digestFromManifest.len != SHA1_LENGTH)
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
-
- nsresult rv;
- uint64_t len64;
- rv = stream->Available(&len64);
- NS_ENSURE_SUCCESS(rv, rv);
- if (len64 > UINT32_MAX) {
- return NS_ERROR_SIGNED_JAR_ENTRY_TOO_LARGE;
- }
-
- UniquePK11Context digestContext(PK11_CreateDigestContext(SEC_OID_SHA1));
- if (!digestContext) {
- return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
- }
-
- rv = MapSECStatus(PK11_DigestBegin(digestContext.get()));
- NS_ENSURE_SUCCESS(rv, rv);
-
- uint64_t totalBytesRead = 0;
- for (;;) {
- uint32_t bytesRead;
- rv = stream->Read(BitwiseCast<char*, unsigned char*>(buf.data), buf.len,
- &bytesRead);
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (bytesRead == 0) {
- break; // EOF
- }
-
- totalBytesRead += bytesRead;
- if (totalBytesRead >= UINT32_MAX) {
- return NS_ERROR_SIGNED_JAR_ENTRY_TOO_LARGE;
- }
-
- rv = MapSECStatus(PK11_DigestOp(digestContext.get(), buf.data, bytesRead));
- NS_ENSURE_SUCCESS(rv, rv);
- }
-
- if (totalBytesRead != len64) {
- // The metadata we used for Available() doesn't match the actual size of
- // the entry.
- return NS_ERROR_SIGNED_JAR_ENTRY_INVALID;
- }
-
- // Verify that the digests match.
- Digest digest;
- rv = digest.End(SEC_OID_SHA1, digestContext);
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (SECITEM_CompareItem(&digestFromManifest, &digest.get()) != SECEqual) {
- return NS_ERROR_SIGNED_JAR_MODIFIED_ENTRY;
- }
-
- return NS_OK;
-}
-
-nsresult
-VerifyEntryContentDigest(nsIZipReader* zip, const nsACString& aFilename,
- const SECItem& digestFromManifest, SECItem& buf)
-{
- nsCOMPtr<nsIInputStream> stream;
- nsresult rv = zip->GetInputStream(aFilename, getter_AddRefs(stream));
- if (NS_FAILED(rv)) {
- return NS_ERROR_SIGNED_JAR_ENTRY_MISSING;
- }
-
- return VerifyStreamContentDigest(stream, digestFromManifest, buf);
-}
-
-// @oaram aDir directory containing the unpacked signed archive
-// @param aFilename path of the target file relative to aDir
-// @param digestFromManifest The digest that we're supposed to check the file's
-// contents against, from the manifest
-// @param buf A scratch buffer that we use for doing the I/O
-nsresult
-VerifyFileContentDigest(nsIFile* aDir, const nsAString& aFilename,
- const SECItem& digestFromManifest, SECItem& buf)
-{
- // Find the file corresponding to the manifest path
- nsCOMPtr<nsIFile> file;
- nsresult rv = aDir->Clone(getter_AddRefs(file));
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- // We don't know how to handle JARs with signed directory entries.
- // It's technically possible in the manifest but makes no sense on disk.
- // Inside an archive we just ignore them, but here we have to treat it
- // as an error because the signed bytes never got unpacked.
- int32_t pos = 0;
- int32_t slash;
- int32_t namelen = aFilename.Length();
- if (namelen == 0 || aFilename[namelen - 1] == '/') {
- return NS_ERROR_SIGNED_JAR_ENTRY_INVALID;
- }
-
- // Append path segments one by one
- do {
- slash = aFilename.FindChar('/', pos);
- int32_t segend = (slash == kNotFound) ? namelen : slash;
- rv = file->Append(Substring(aFilename, pos, (segend - pos)));
- if (NS_FAILED(rv)) {
- return NS_ERROR_SIGNED_JAR_ENTRY_INVALID;
- }
- pos = slash + 1;
- } while (pos < namelen && slash != kNotFound);
-
- bool exists;
- rv = file->Exists(&exists);
- if (NS_FAILED(rv) || !exists) {
- return NS_ERROR_SIGNED_JAR_ENTRY_MISSING;
- }
-
- bool isDir;
- rv = file->IsDirectory(&isDir);
- if (NS_FAILED(rv) || isDir) {
- // We only support signed files, not directory entries
- return NS_ERROR_SIGNED_JAR_ENTRY_INVALID;
- }
-
- // Open an input stream for that file and verify it.
- nsCOMPtr<nsIInputStream> stream;
- rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), file, -1, -1,
- nsIFileInputStream::CLOSE_ON_EOF);
- if (NS_FAILED(rv) || !stream) {
- return NS_ERROR_SIGNED_JAR_ENTRY_MISSING;
- }
-
- return VerifyStreamContentDigest(stream, digestFromManifest, buf);
-}
-
-// On input, nextLineStart is the start of the current line. On output,
-// nextLineStart is the start of the next line.
-nsresult
-ReadLine(/*in/out*/ const char* & nextLineStart, /*out*/ nsCString & line,
- bool allowContinuations = true)
-{
- line.Truncate();
- size_t previousLength = 0;
- size_t currentLength = 0;
- for (;;) {
- const char* eol = PL_strpbrk(nextLineStart, "\r\n");
-
- if (!eol) { // Reached end of file before newline
- eol = nextLineStart + strlen(nextLineStart);
- }
-
- previousLength = currentLength;
- line.Append(nextLineStart, eol - nextLineStart);
- currentLength = line.Length();
-
- // The spec says "No line may be longer than 72 bytes (not characters)"
- // in its UTF8-encoded form.
- static const size_t lineLimit = 72;
- if (currentLength - previousLength > lineLimit) {
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- // The spec says: "Implementations should support 65535-byte
- // (not character) header values..."
- if (currentLength > 65535) {
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- if (*eol == '\r') {
- ++eol;
- }
- if (*eol == '\n') {
- ++eol;
- }
-
- nextLineStart = eol;
-
- if (*eol != ' ') {
- // not a continuation
- return NS_OK;
- }
-
- // continuation
- if (!allowContinuations) {
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- ++nextLineStart; // skip space and keep appending
- }
-}
-
-// The header strings are defined in the JAR specification.
-#define JAR_MF_SEARCH_STRING "(M|/M)ETA-INF/(M|m)(ANIFEST|anifest).(MF|mf)$"
-#define JAR_SF_SEARCH_STRING "(M|/M)ETA-INF/*.(SF|sf)$"
-#define JAR_RSA_SEARCH_STRING "(M|/M)ETA-INF/*.(RSA|rsa)$"
-#define JAR_META_DIR "META-INF"
-#define JAR_MF_HEADER "Manifest-Version: 1.0"
-#define JAR_SF_HEADER "Signature-Version: 1.0"
-
-nsresult
-ParseAttribute(const nsAutoCString & curLine,
- /*out*/ nsAutoCString & attrName,
- /*out*/ nsAutoCString & attrValue)
-{
- // Find the colon that separates the name from the value.
- int32_t colonPos = curLine.FindChar(':');
- if (colonPos == kNotFound) {
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- // set attrName to the name, skipping spaces between the name and colon
- int32_t nameEnd = colonPos;
- for (;;) {
- if (nameEnd == 0) {
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID; // colon with no name
- }
- if (curLine[nameEnd - 1] != ' ')
- break;
- --nameEnd;
- }
- curLine.Left(attrName, nameEnd);
-
- // Set attrValue to the value, skipping spaces between the colon and the
- // value. The value may be empty.
- int32_t valueStart = colonPos + 1;
- int32_t curLineLength = curLine.Length();
- while (valueStart != curLineLength && curLine[valueStart] == ' ') {
- ++valueStart;
- }
- curLine.Right(attrValue, curLineLength - valueStart);
-
- return NS_OK;
-}
-
-// Parses the version line of the MF or SF header.
-nsresult
-CheckManifestVersion(const char* & nextLineStart,
- const nsACString & expectedHeader)
-{
- // The JAR spec says: "Manifest-Version and Signature-Version must be first,
- // and in exactly that case (so that they can be recognized easily as magic
- // strings)."
- nsAutoCString curLine;
- nsresult rv = ReadLine(nextLineStart, curLine, false);
- if (NS_FAILED(rv)) {
- return rv;
- }
- if (!curLine.Equals(expectedHeader)) {
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
- return NS_OK;
-}
-
-// Parses a signature file (SF) as defined in the JDK 8 JAR Specification.
-//
-// The SF file *must* contain exactly one SHA1-Digest-Manifest attribute in
-// the main section. All other sections are ignored. This means that this will
-// NOT parse old-style signature files that have separate digests per entry.
-// The JDK8 x-Digest-Manifest variant is better because:
-//
-// (1) It allows us to follow the principle that we should minimize the
-// processing of data that we do before we verify its signature. In
-// particular, with the x-Digest-Manifest style, we can verify the digest
-// of MANIFEST.MF before we parse it, which prevents malicious JARs
-// exploiting our MANIFEST.MF parser.
-// (2) It is more time-efficient and space-efficient to have one
-// x-Digest-Manifest instead of multiple x-Digest values.
-//
-// In order to get benefit (1), we do NOT implement the fallback to the older
-// mechanism as the spec requires/suggests. Also, for simplity's sake, we only
-// support exactly one SHA1-Digest-Manifest attribute, and no other
-// algorithms.
-//
-// filebuf must be null-terminated. On output, mfDigest will contain the
-// decoded value of SHA1-Digest-Manifest.
-nsresult
-ParseSF(const char* filebuf, /*out*/ SECItem & mfDigest)
-{
- nsresult rv;
-
- const char* nextLineStart = filebuf;
- rv = CheckManifestVersion(nextLineStart, NS_LITERAL_CSTRING(JAR_SF_HEADER));
- if (NS_FAILED(rv))
- return rv;
-
- // Find SHA1-Digest-Manifest
- for (;;) {
- nsAutoCString curLine;
- rv = ReadLine(nextLineStart, curLine);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- if (curLine.Length() == 0) {
- // End of main section (blank line or end-of-file), and no
- // SHA1-Digest-Manifest found.
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- nsAutoCString attrName;
- nsAutoCString attrValue;
- rv = ParseAttribute(curLine, attrName, attrValue);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- if (attrName.LowerCaseEqualsLiteral("sha1-digest-manifest")) {
- rv = MapSECStatus(ATOB_ConvertAsciiToItem(&mfDigest, attrValue.get()));
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- // There could be multiple SHA1-Digest-Manifest attributes, which
- // would be an error, but it's better to just skip any erroneous
- // duplicate entries rather than trying to detect them, because:
- //
- // (1) It's simpler, and simpler generally means more secure
- // (2) An attacker can't make us accept a JAR we would otherwise
- // reject just by adding additional SHA1-Digest-Manifest
- // attributes.
- break;
- }
-
- // ignore unrecognized attributes
- }
-
- return NS_OK;
-}
-
-// Parses MANIFEST.MF. The filenames of all entries will be returned in
-// mfItems. buf must be a pre-allocated scratch buffer that is used for doing
-// I/O.
-nsresult
-ParseMF(const char* filebuf, nsIZipReader * zip,
- /*out*/ nsTHashtable<nsCStringHashKey> & mfItems,
- ScopedAutoSECItem & buf)
-{
- nsresult rv;
-
- const char* nextLineStart = filebuf;
-
- rv = CheckManifestVersion(nextLineStart, NS_LITERAL_CSTRING(JAR_MF_HEADER));
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- // Skip the rest of the header section, which ends with a blank line.
- {
- nsAutoCString line;
- do {
- rv = ReadLine(nextLineStart, line);
- if (NS_FAILED(rv)) {
- return rv;
- }
- } while (line.Length() > 0);
-
- // Manifest containing no file entries is OK, though useless.
- if (*nextLineStart == '\0') {
- return NS_OK;
- }
- }
-
- nsAutoCString curItemName;
- ScopedAutoSECItem digest;
-
- for (;;) {
- nsAutoCString curLine;
- rv = ReadLine(nextLineStart, curLine);
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (curLine.Length() == 0) {
- // end of section (blank line or end-of-file)
-
- if (curItemName.Length() == 0) {
- // '...Each section must start with an attribute with the name as
- // "Name",...', so every section must have a Name attribute.
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- if (digest.len == 0) {
- // We require every entry to have a digest, since we require every
- // entry to be signed and we don't allow duplicate entries.
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- if (mfItems.Contains(curItemName)) {
- // Duplicate entry
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- // Verify that the entry's content digest matches the digest from this
- // MF section.
- rv = VerifyEntryContentDigest(zip, curItemName, digest, buf);
- if (NS_FAILED(rv))
- return rv;
-
- mfItems.PutEntry(curItemName);
-
- if (*nextLineStart == '\0') // end-of-file
- break;
-
- // reset so we know we haven't encountered either of these for the next
- // item yet.
- curItemName.Truncate();
- digest.reset();
-
- continue; // skip the rest of the loop below
- }
-
- nsAutoCString attrName;
- nsAutoCString attrValue;
- rv = ParseAttribute(curLine, attrName, attrValue);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- // Lines to look for:
-
- // (1) Digest:
- if (attrName.LowerCaseEqualsLiteral("sha1-digest"))
- {
- if (digest.len > 0) // multiple SHA1 digests in section
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
-
- rv = MapSECStatus(ATOB_ConvertAsciiToItem(&digest, attrValue.get()));
- if (NS_FAILED(rv))
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
-
- continue;
- }
-
- // (2) Name: associates this manifest section with a file in the jar.
- if (attrName.LowerCaseEqualsLiteral("name"))
- {
- if (MOZ_UNLIKELY(curItemName.Length() > 0)) // multiple names in section
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
-
- if (MOZ_UNLIKELY(attrValue.Length() == 0))
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
-
- curItemName = attrValue;
-
- continue;
- }
-
- // (3) Magic: the only other must-understand attribute
- if (attrName.LowerCaseEqualsLiteral("magic")) {
- // We don't understand any magic, so we can't verify an entry that
- // requires magic. Since we require every entry to have a valid
- // signature, we have no choice but to reject the entry.
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- // unrecognized attributes must be ignored
- }
-
- return NS_OK;
-}
-
-struct VerifyCertificateContext {
- AppTrustedRoot trustedRoot;
- UniqueCERTCertList& builtChain;
-};
-
-nsresult
-VerifyCertificate(CERTCertificate* signerCert, void* voidContext, void* pinArg)
-{
- // TODO: null pinArg is tolerated.
- if (NS_WARN_IF(!signerCert) || NS_WARN_IF(!voidContext)) {
- return NS_ERROR_INVALID_ARG;
- }
- const VerifyCertificateContext& context =
- *static_cast<const VerifyCertificateContext*>(voidContext);
-
- AppTrustDomain trustDomain(context.builtChain, pinArg);
- if (trustDomain.SetTrustedRoot(context.trustedRoot) != SECSuccess) {
- return MapSECStatus(SECFailure);
- }
- Input certDER;
- mozilla::pkix::Result rv = certDER.Init(signerCert->derCert.data,
- signerCert->derCert.len);
- if (rv != Success) {
- return mozilla::psm::GetXPCOMFromNSSError(MapResultToPRErrorCode(rv));
- }
-
- rv = BuildCertChain(trustDomain, certDER, Now(),
- EndEntityOrCA::MustBeEndEntity,
- KeyUsage::digitalSignature,
- KeyPurposeId::id_kp_codeSigning,
- CertPolicyId::anyPolicy,
- nullptr/*stapledOCSPResponse*/);
- if (rv == mozilla::pkix::Result::ERROR_EXPIRED_CERTIFICATE) {
- // For code-signing you normally need trusted 3rd-party timestamps to
- // handle expiration properly. The signer could always mess with their
- // system clock so you can't trust the certificate was un-expired when
- // the signing took place. The choice is either to ignore expiration
- // or to enforce expiration at time of use. The latter leads to the
- // user-hostile result that perfectly good code stops working.
- //
- // Our package format doesn't support timestamps (nor do we have a
- // trusted 3rd party timestamper), but since we sign all of our apps and
- // add-ons ourselves we can trust ourselves not to mess with the clock
- // on the signing systems. We also have a revocation mechanism if we
- // need it. It's OK to ignore cert expiration under these conditions.
- //
- // This is an invalid approach if
- // * we issue certs to let others sign their own packages
- // * mozilla::pkix returns "expired" when there are "worse" problems
- // with the certificate or chain.
- // (see bug 1267318)
- rv = Success;
- }
- if (rv != Success) {
- return mozilla::psm::GetXPCOMFromNSSError(MapResultToPRErrorCode(rv));
- }
-
- return NS_OK;
-}
-
-nsresult
-VerifySignature(AppTrustedRoot trustedRoot, const SECItem& buffer,
- const SECItem& detachedDigest,
- /*out*/ UniqueCERTCertList& builtChain)
-{
- // Currently, this function is only called within the CalculateResult() method
- // of CryptoTasks. As such, NSS should not be shut down at this point and the
- // CryptoTask implementation should already hold a nsNSSShutDownPreventionLock.
- // We acquire a nsNSSShutDownPreventionLock here solely to prove we did to
- // VerifyCMSDetachedSignatureIncludingCertificate().
- nsNSSShutDownPreventionLock locker;
- VerifyCertificateContext context = { trustedRoot, builtChain };
- // XXX: missing pinArg
- return VerifyCMSDetachedSignatureIncludingCertificate(buffer, detachedDigest,
- VerifyCertificate,
- &context, nullptr,
- locker);
-}
-
-NS_IMETHODIMP
-OpenSignedAppFile(AppTrustedRoot aTrustedRoot, nsIFile* aJarFile,
- /*out, optional */ nsIZipReader** aZipReader,
- /*out, optional */ nsIX509Cert** aSignerCert)
-{
- NS_ENSURE_ARG_POINTER(aJarFile);
-
- if (aZipReader) {
- *aZipReader = nullptr;
- }
-
- if (aSignerCert) {
- *aSignerCert = nullptr;
- }
-
- nsresult rv;
-
- static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
- nsCOMPtr<nsIZipReader> zip = do_CreateInstance(kZipReaderCID, &rv);
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = zip->Open(aJarFile);
- NS_ENSURE_SUCCESS(rv, rv);
-
- // Signature (RSA) file
- nsAutoCString sigFilename;
- ScopedAutoSECItem sigBuffer;
- rv = FindAndLoadOneEntry(zip, nsLiteralCString(JAR_RSA_SEARCH_STRING),
- sigFilename, sigBuffer, nullptr);
- if (NS_FAILED(rv)) {
- return NS_ERROR_SIGNED_JAR_NOT_SIGNED;
- }
-
- // Signature (SF) file
- nsAutoCString sfFilename;
- ScopedAutoSECItem sfBuffer;
- Digest sfCalculatedDigest;
- rv = FindAndLoadOneEntry(zip, NS_LITERAL_CSTRING(JAR_SF_SEARCH_STRING),
- sfFilename, sfBuffer, &sfCalculatedDigest);
- if (NS_FAILED(rv)) {
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- sigBuffer.type = siBuffer;
- UniqueCERTCertList builtChain;
- rv = VerifySignature(aTrustedRoot, sigBuffer, sfCalculatedDigest.get(),
- builtChain);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- ScopedAutoSECItem mfDigest;
- rv = ParseSF(BitwiseCast<char*, unsigned char*>(sfBuffer.data), mfDigest);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- // Manifest (MF) file
- nsAutoCString mfFilename;
- ScopedAutoSECItem manifestBuffer;
- Digest mfCalculatedDigest;
- rv = FindAndLoadOneEntry(zip, NS_LITERAL_CSTRING(JAR_MF_SEARCH_STRING),
- mfFilename, manifestBuffer, &mfCalculatedDigest);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- if (SECITEM_CompareItem(&mfDigest, &mfCalculatedDigest.get()) != SECEqual) {
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- // Allocate the I/O buffer only once per JAR, instead of once per entry, in
- // order to minimize malloc/free calls and in order to avoid fragmenting
- // memory.
- ScopedAutoSECItem buf(128 * 1024);
-
- nsTHashtable<nsCStringHashKey> items;
-
- rv = ParseMF(BitwiseCast<char*, unsigned char*>(manifestBuffer.data), zip,
- items, buf);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- // Verify every entry in the file.
- nsCOMPtr<nsIUTF8StringEnumerator> entries;
- rv = zip->FindEntries(EmptyCString(), getter_AddRefs(entries));
- if (NS_SUCCEEDED(rv) && !entries) {
- rv = NS_ERROR_UNEXPECTED;
- }
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- for (;;) {
- bool hasMore;
- rv = entries->HasMore(&hasMore);
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (!hasMore) {
- break;
- }
-
- nsAutoCString entryFilename;
- rv = entries->GetNext(entryFilename);
- NS_ENSURE_SUCCESS(rv, rv);
-
- MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Verifying digests for %s",
- entryFilename.get()));
-
- // The files that comprise the signature mechanism are not covered by the
- // signature.
- //
- // XXX: This is OK for a single signature, but doesn't work for
- // multiple signatures, because the metadata for the other signatures
- // is not signed either.
- if (entryFilename == mfFilename ||
- entryFilename == sfFilename ||
- entryFilename == sigFilename) {
- continue;
- }
-
- if (entryFilename.Length() == 0) {
- return NS_ERROR_SIGNED_JAR_ENTRY_INVALID;
- }
-
- // Entries with names that end in "/" are directory entries, which are not
- // signed.
- //
- // XXX: As long as we don't unpack the JAR into the filesystem, the "/"
- // entries are harmless. But, it is not clear what the security
- // implications of directory entries are if/when we were to unpackage the
- // JAR into the filesystem.
- if (entryFilename[entryFilename.Length() - 1] == '/') {
- continue;
- }
-
- nsCStringHashKey * item = items.GetEntry(entryFilename);
- if (!item) {
- return NS_ERROR_SIGNED_JAR_UNSIGNED_ENTRY;
- }
-
- // Remove the item so we can check for leftover items later
- items.RemoveEntry(item);
- }
-
- // We verified that every entry that we require to be signed is signed. But,
- // were there any missing entries--that is, entries that are mentioned in the
- // manifest but missing from the archive?
- if (items.Count() != 0) {
- return NS_ERROR_SIGNED_JAR_ENTRY_MISSING;
- }
-
- // Return the reader to the caller if they want it
- if (aZipReader) {
- zip.forget(aZipReader);
- }
-
- // Return the signer's certificate to the reader if they want it.
- // XXX: We should return an nsIX509CertList with the whole validated chain.
- if (aSignerCert) {
- CERTCertListNode* signerCertNode = CERT_LIST_HEAD(builtChain);
- if (!signerCertNode || CERT_LIST_END(signerCertNode, builtChain) ||
- !signerCertNode->cert) {
- return NS_ERROR_FAILURE;
- }
- nsCOMPtr<nsIX509Cert> signerCert =
- nsNSSCertificate::Create(signerCertNode->cert);
- NS_ENSURE_TRUE(signerCert, NS_ERROR_OUT_OF_MEMORY);
- signerCert.forget(aSignerCert);
- }
-
- return NS_OK;
-}
-
-nsresult
-VerifySignedManifest(AppTrustedRoot aTrustedRoot,
- nsIInputStream* aManifestStream,
- nsIInputStream* aSignatureStream,
- /*out, optional */ nsIX509Cert** aSignerCert)
-{
- NS_ENSURE_ARG(aManifestStream);
- NS_ENSURE_ARG(aSignatureStream);
-
- if (aSignerCert) {
- *aSignerCert = nullptr;
- }
-
- // Load signature file in buffer
- ScopedAutoSECItem signatureBuffer;
- nsresult rv = ReadStream(aSignatureStream, signatureBuffer);
- if (NS_FAILED(rv)) {
- return rv;
- }
- signatureBuffer.type = siBuffer;
-
- // Load manifest file in buffer
- ScopedAutoSECItem manifestBuffer;
- rv = ReadStream(aManifestStream, manifestBuffer);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- // Calculate SHA1 digest of the manifest buffer
- Digest manifestCalculatedDigest;
- rv = manifestCalculatedDigest.DigestBuf(SEC_OID_SHA1,
- manifestBuffer.data,
- manifestBuffer.len - 1); // buffer is null terminated
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- // Get base64 encoded string from manifest buffer digest
- UniquePORTString
- base64EncDigest(NSSBase64_EncodeItem(nullptr, nullptr, 0,
- const_cast<SECItem*>(&manifestCalculatedDigest.get())));
- if (NS_WARN_IF(!base64EncDigest)) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
-
- // Calculate SHA1 digest of the base64 encoded string
- Digest doubleDigest;
- rv = doubleDigest.DigestBuf(SEC_OID_SHA1,
- BitwiseCast<uint8_t*, char*>(base64EncDigest.get()),
- strlen(base64EncDigest.get()));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- // Verify the manifest signature (signed digest of the base64 encoded string)
- UniqueCERTCertList builtChain;
- rv = VerifySignature(aTrustedRoot, signatureBuffer,
- doubleDigest.get(), builtChain);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- // Return the signer's certificate to the reader if they want it.
- if (aSignerCert) {
- CERTCertListNode* signerCertNode = CERT_LIST_HEAD(builtChain);
- if (!signerCertNode || CERT_LIST_END(signerCertNode, builtChain) ||
- !signerCertNode->cert) {
- return NS_ERROR_FAILURE;
- }
- nsCOMPtr<nsIX509Cert> signerCert =
- nsNSSCertificate::Create(signerCertNode->cert);
- if (NS_WARN_IF(!signerCert)) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
-
- signerCert.forget(aSignerCert);
- }
-
- return NS_OK;
-}
-
-class OpenSignedAppFileTask final : public CryptoTask
-{
-public:
- OpenSignedAppFileTask(AppTrustedRoot aTrustedRoot, nsIFile* aJarFile,
- nsIOpenSignedAppFileCallback* aCallback)
- : mTrustedRoot(aTrustedRoot)
- , mJarFile(aJarFile)
- , mCallback(new nsMainThreadPtrHolder<nsIOpenSignedAppFileCallback>(aCallback))
- {
- }
-
-private:
- virtual nsresult CalculateResult() override
- {
- return OpenSignedAppFile(mTrustedRoot, mJarFile,
- getter_AddRefs(mZipReader),
- getter_AddRefs(mSignerCert));
- }
-
- // nsNSSCertificate implements nsNSSShutdownObject, so there's nothing that
- // needs to be released
- virtual void ReleaseNSSResources() override { }
-
- virtual void CallCallback(nsresult rv) override
- {
- (void) mCallback->OpenSignedAppFileFinished(rv, mZipReader, mSignerCert);
- }
-
- const AppTrustedRoot mTrustedRoot;
- const nsCOMPtr<nsIFile> mJarFile;
- nsMainThreadPtrHandle<nsIOpenSignedAppFileCallback> mCallback;
- nsCOMPtr<nsIZipReader> mZipReader; // out
- nsCOMPtr<nsIX509Cert> mSignerCert; // out
-};
-
-class VerifySignedmanifestTask final : public CryptoTask
-{
-public:
- VerifySignedmanifestTask(AppTrustedRoot aTrustedRoot,
- nsIInputStream* aManifestStream,
- nsIInputStream* aSignatureStream,
- nsIVerifySignedManifestCallback* aCallback)
- : mTrustedRoot(aTrustedRoot)
- , mManifestStream(aManifestStream)
- , mSignatureStream(aSignatureStream)
- , mCallback(
- new nsMainThreadPtrHolder<nsIVerifySignedManifestCallback>(aCallback))
- {
- }
-
-private:
- virtual nsresult CalculateResult() override
- {
- return VerifySignedManifest(mTrustedRoot, mManifestStream,
- mSignatureStream, getter_AddRefs(mSignerCert));
- }
-
- // nsNSSCertificate implements nsNSSShutdownObject, so there's nothing that
- // needs to be released
- virtual void ReleaseNSSResources() override { }
-
- virtual void CallCallback(nsresult rv) override
- {
- (void) mCallback->VerifySignedManifestFinished(rv, mSignerCert);
- }
-
- const AppTrustedRoot mTrustedRoot;
- const nsCOMPtr<nsIInputStream> mManifestStream;
- const nsCOMPtr<nsIInputStream> mSignatureStream;
- nsMainThreadPtrHandle<nsIVerifySignedManifestCallback> mCallback;
- nsCOMPtr<nsIX509Cert> mSignerCert; // out
-};
-
-} // unnamed namespace
-
-NS_IMETHODIMP
-nsNSSCertificateDB::OpenSignedAppFileAsync(
- AppTrustedRoot aTrustedRoot, nsIFile* aJarFile,
- nsIOpenSignedAppFileCallback* aCallback)
-{
- NS_ENSURE_ARG_POINTER(aJarFile);
- NS_ENSURE_ARG_POINTER(aCallback);
- RefPtr<OpenSignedAppFileTask> task(new OpenSignedAppFileTask(aTrustedRoot,
- aJarFile,
- aCallback));
- return task->Dispatch("SignedJAR");
-}
-
-NS_IMETHODIMP
-nsNSSCertificateDB::VerifySignedManifestAsync(
- AppTrustedRoot aTrustedRoot, nsIInputStream* aManifestStream,
- nsIInputStream* aSignatureStream, nsIVerifySignedManifestCallback* aCallback)
-{
- NS_ENSURE_ARG_POINTER(aManifestStream);
- NS_ENSURE_ARG_POINTER(aSignatureStream);
- NS_ENSURE_ARG_POINTER(aCallback);
-
- RefPtr<VerifySignedmanifestTask> task(
- new VerifySignedmanifestTask(aTrustedRoot, aManifestStream,
- aSignatureStream, aCallback));
- return task->Dispatch("SignedManifest");
-}
-
-
-//
-// Signature verification for archives unpacked into a file structure
-//
-
-// Finds the "*.rsa" signature file in the META-INF directory and returns
-// the name. It is an error if there are none or more than one .rsa file
-nsresult
-FindSignatureFilename(nsIFile* aMetaDir,
- /*out*/ nsAString& aFilename)
-{
- nsCOMPtr<nsISimpleEnumerator> entries;
- nsresult rv = aMetaDir->GetDirectoryEntries(getter_AddRefs(entries));
- nsCOMPtr<nsIDirectoryEnumerator> files = do_QueryInterface(entries);
- if (NS_FAILED(rv) || !files) {
- return NS_ERROR_SIGNED_JAR_NOT_SIGNED;
- }
-
- bool found = false;
- nsCOMPtr<nsIFile> file;
- rv = files->GetNextFile(getter_AddRefs(file));
-
- while (NS_SUCCEEDED(rv) && file) {
- nsAutoString leafname;
- rv = file->GetLeafName(leafname);
- if (NS_SUCCEEDED(rv)) {
- if (StringEndsWith(leafname, NS_LITERAL_STRING(".rsa"))) {
- if (!found) {
- found = true;
- aFilename = leafname;
- } else {
- // second signature file is an error
- rv = NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- break;
- }
- }
- rv = files->GetNextFile(getter_AddRefs(file));
- }
- }
-
- if (!found) {
- rv = NS_ERROR_SIGNED_JAR_NOT_SIGNED;
- }
-
- files->Close();
- return rv;
-}
-
-// Loads the signature metadata file that matches the given filename in
-// the passed-in Meta-inf directory. If bufDigest is not null then on
-// success bufDigest will contain the SHA-1 digest of the entry.
-nsresult
-LoadOneMetafile(nsIFile* aMetaDir,
- const nsAString& aFilename,
- /*out*/ SECItem& aBuf,
- /*optional, out*/ Digest* aBufDigest)
-{
- nsCOMPtr<nsIFile> metafile;
- nsresult rv = aMetaDir->Clone(getter_AddRefs(metafile));
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = metafile->Append(aFilename);
- NS_ENSURE_SUCCESS(rv, rv);
-
- bool exists;
- rv = metafile->Exists(&exists);
- if (NS_FAILED(rv) || !exists) {
- // we can call a missing .rsa file "unsigned" but FindSignatureFilename()
- // already found one: missing other metadata files means a broken signature.
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- nsCOMPtr<nsIInputStream> stream;
- rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), metafile);
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = ReadStream(stream, aBuf);
- stream->Close();
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (aBufDigest) {
- rv = aBufDigest->DigestBuf(SEC_OID_SHA1, aBuf.data, aBuf.len - 1);
- NS_ENSURE_SUCCESS(rv, rv);
- }
-
- return NS_OK;
-}
-
-// Parses MANIFEST.MF and verifies the contents of the unpacked files
-// listed in the manifest.
-// The filenames of all entries will be returned in aMfItems. aBuf must
-// be a pre-allocated scratch buffer that is used for doing I/O.
-nsresult
-ParseMFUnpacked(const char* aFilebuf, nsIFile* aDir,
- /*out*/ nsTHashtable<nsStringHashKey>& aMfItems,
- ScopedAutoSECItem& aBuf)
-{
- nsresult rv;
-
- const char* nextLineStart = aFilebuf;
-
- rv = CheckManifestVersion(nextLineStart, NS_LITERAL_CSTRING(JAR_MF_HEADER));
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- // Skip the rest of the header section, which ends with a blank line.
- {
- nsAutoCString line;
- do {
- rv = ReadLine(nextLineStart, line);
- if (NS_FAILED(rv)) {
- return rv;
- }
- } while (line.Length() > 0);
-
- // Manifest containing no file entries is OK, though useless.
- if (*nextLineStart == '\0') {
- return NS_OK;
- }
- }
-
- nsAutoString curItemName;
- ScopedAutoSECItem digest;
-
- for (;;) {
- nsAutoCString curLine;
- rv = ReadLine(nextLineStart, curLine);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- if (curLine.Length() == 0) {
- // end of section (blank line or end-of-file)
-
- if (curItemName.Length() == 0) {
- // '...Each section must start with an attribute with the name as
- // "Name",...', so every section must have a Name attribute.
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- if (digest.len == 0) {
- // We require every entry to have a digest, since we require every
- // entry to be signed and we don't allow duplicate entries.
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- if (aMfItems.Contains(curItemName)) {
- // Duplicate entry
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- // Verify that the file's content digest matches the digest from this
- // MF section.
- rv = VerifyFileContentDigest(aDir, curItemName, digest, aBuf);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- aMfItems.PutEntry(curItemName);
-
- if (*nextLineStart == '\0') {
- // end-of-file
- break;
- }
-
- // reset so we know we haven't encountered either of these for the next
- // item yet.
- curItemName.Truncate();
- digest.reset();
-
- continue; // skip the rest of the loop below
- }
-
- nsAutoCString attrName;
- nsAutoCString attrValue;
- rv = ParseAttribute(curLine, attrName, attrValue);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- // Lines to look for:
-
- // (1) Digest:
- if (attrName.LowerCaseEqualsLiteral("sha1-digest")) {
- if (digest.len > 0) {
- // multiple SHA1 digests in section
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- rv = MapSECStatus(ATOB_ConvertAsciiToItem(&digest, attrValue.get()));
- if (NS_FAILED(rv)) {
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- continue;
- }
-
- // (2) Name: associates this manifest section with a file in the jar.
- if (attrName.LowerCaseEqualsLiteral("name")) {
- if (MOZ_UNLIKELY(curItemName.Length() > 0)) {
- // multiple names in section
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- if (MOZ_UNLIKELY(attrValue.Length() == 0)) {
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- curItemName = NS_ConvertUTF8toUTF16(attrValue);
-
- continue;
- }
-
- // (3) Magic: the only other must-understand attribute
- if (attrName.LowerCaseEqualsLiteral("magic")) {
- // We don't understand any magic, so we can't verify an entry that
- // requires magic. Since we require every entry to have a valid
- // signature, we have no choice but to reject the entry.
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- // unrecognized attributes must be ignored
- }
-
- return NS_OK;
-}
-
-// recursively check a directory tree for files not in the list of
-// verified files we found in the manifest. For each file we find
-// Check it against the files found in the manifest. If the file wasn't
-// in the manifest then it's unsigned and we can stop looking. Otherwise
-// remove it from the collection so we can check leftovers later.
-//
-// @param aDir Directory to check
-// @param aPath Relative path to that directory (to check against aItems)
-// @param aItems All the files found
-// @param *Filename signature files that won't be in the manifest
-nsresult
-CheckDirForUnsignedFiles(nsIFile* aDir,
- const nsString& aPath,
- /* in/out */ nsTHashtable<nsStringHashKey>& aItems,
- const nsAString& sigFilename,
- const nsAString& sfFilename,
- const nsAString& mfFilename)
-{
- nsCOMPtr<nsISimpleEnumerator> entries;
- nsresult rv = aDir->GetDirectoryEntries(getter_AddRefs(entries));
- nsCOMPtr<nsIDirectoryEnumerator> files = do_QueryInterface(entries);
- if (NS_FAILED(rv) || !files) {
- return NS_ERROR_SIGNED_JAR_ENTRY_MISSING;
- }
-
- bool inMeta = StringBeginsWith(aPath, NS_LITERAL_STRING(JAR_META_DIR));
-
- while (NS_SUCCEEDED(rv)) {
- nsCOMPtr<nsIFile> file;
- rv = files->GetNextFile(getter_AddRefs(file));
- if (NS_FAILED(rv) || !file) {
- break;
- }
-
- nsAutoString leafname;
- rv = file->GetLeafName(leafname);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- nsAutoString curName(aPath + leafname);
-
- bool isDir;
- rv = file->IsDirectory(&isDir);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- // if it's a directory we need to recurse
- if (isDir) {
- curName.Append(NS_LITERAL_STRING("/"));
- rv = CheckDirForUnsignedFiles(file, curName, aItems,
- sigFilename, sfFilename, mfFilename);
- } else {
- // The files that comprise the signature mechanism are not covered by the
- // signature.
- //
- // XXX: This is OK for a single signature, but doesn't work for
- // multiple signatures because the metadata for the other signatures
- // is not signed either.
- if (inMeta && ( leafname == sigFilename ||
- leafname == sfFilename ||
- leafname == mfFilename )) {
- continue;
- }
-
- // make sure the current file was found in the manifest
- nsStringHashKey* item = aItems.GetEntry(curName);
- if (!item) {
- return NS_ERROR_SIGNED_JAR_UNSIGNED_ENTRY;
- }
-
- // Remove the item so we can check for leftover items later
- aItems.RemoveEntry(item);
- }
- }
- files->Close();
- return rv;
-}
-
-/*
- * Verify the signature of a directory structure as if it were a
- * signed JAR file (used for unpacked JARs)
- */
-nsresult
-VerifySignedDirectory(AppTrustedRoot aTrustedRoot,
- nsIFile* aDirectory,
- /*out, optional */ nsIX509Cert** aSignerCert)
-{
- NS_ENSURE_ARG_POINTER(aDirectory);
-
- if (aSignerCert) {
- *aSignerCert = nullptr;
- }
-
- // Make sure there's a META-INF directory
-
- nsCOMPtr<nsIFile> metaDir;
- nsresult rv = aDirectory->Clone(getter_AddRefs(metaDir));
- if (NS_FAILED(rv)) {
- return rv;
- }
- rv = metaDir->Append(NS_LITERAL_STRING(JAR_META_DIR));
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- bool exists;
- rv = metaDir->Exists(&exists);
- if (NS_FAILED(rv) || !exists) {
- return NS_ERROR_SIGNED_JAR_NOT_SIGNED;
- }
- bool isDirectory;
- rv = metaDir->IsDirectory(&isDirectory);
- if (NS_FAILED(rv) || !isDirectory) {
- return NS_ERROR_SIGNED_JAR_NOT_SIGNED;
- }
-
- // Find and load the Signature (RSA) file
-
- nsAutoString sigFilename;
- rv = FindSignatureFilename(metaDir, sigFilename);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- ScopedAutoSECItem sigBuffer;
- rv = LoadOneMetafile(metaDir, sigFilename, sigBuffer, nullptr);
- if (NS_FAILED(rv)) {
- return NS_ERROR_SIGNED_JAR_NOT_SIGNED;
- }
-
- // Load the signature (SF) file and verify the signature.
- // The .sf and .rsa files must have the same name apart from the extension.
-
- nsAutoString sfFilename(Substring(sigFilename, 0, sigFilename.Length() - 3)
- + NS_LITERAL_STRING("sf"));
-
- ScopedAutoSECItem sfBuffer;
- Digest sfCalculatedDigest;
- rv = LoadOneMetafile(metaDir, sfFilename, sfBuffer, &sfCalculatedDigest);
- if (NS_FAILED(rv)) {
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- sigBuffer.type = siBuffer;
- UniqueCERTCertList builtChain;
- rv = VerifySignature(aTrustedRoot, sigBuffer, sfCalculatedDigest.get(),
- builtChain);
- if (NS_FAILED(rv)) {
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- // Get the expected manifest hash from the signed .sf file
-
- ScopedAutoSECItem mfDigest;
- rv = ParseSF(BitwiseCast<char*, unsigned char*>(sfBuffer.data), mfDigest);
- if (NS_FAILED(rv)) {
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- // Load manifest (MF) file and verify signature
-
- nsAutoString mfFilename(NS_LITERAL_STRING("manifest.mf"));
- ScopedAutoSECItem manifestBuffer;
- Digest mfCalculatedDigest;
- rv = LoadOneMetafile(metaDir, mfFilename, manifestBuffer, &mfCalculatedDigest);
- if (NS_FAILED(rv)) {
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- if (SECITEM_CompareItem(&mfDigest, &mfCalculatedDigest.get()) != SECEqual) {
- return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
- }
-
- // Parse manifest and verify signed hash of all listed files
-
- // Allocate the I/O buffer only once per JAR, instead of once per entry, in
- // order to minimize malloc/free calls and in order to avoid fragmenting
- // memory.
- ScopedAutoSECItem buf(128 * 1024);
-
- nsTHashtable<nsStringHashKey> items;
- rv = ParseMFUnpacked(BitwiseCast<char*, unsigned char*>(manifestBuffer.data),
- aDirectory, items, buf);
- if (NS_FAILED(rv)){
- return rv;
- }
-
- // We've checked that everything listed in the manifest exists and is signed
- // correctly. Now check on disk for extra (unsigned) files.
- // Deletes found entries from items as it goes.
- rv = CheckDirForUnsignedFiles(aDirectory, EmptyString(), items,
- sigFilename, sfFilename, mfFilename);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- // We verified that every entry that we require to be signed is signed. But,
- // were there any missing entries--that is, entries that are mentioned in the
- // manifest but missing from the directory tree? (There shouldn't be given
- // ParseMFUnpacked() checking them all, but it's a cheap sanity check.)
- if (items.Count() != 0) {
- return NS_ERROR_SIGNED_JAR_ENTRY_MISSING;
- }
-
- // Return the signer's certificate to the reader if they want it.
- // XXX: We should return an nsIX509CertList with the whole validated chain.
- if (aSignerCert) {
- CERTCertListNode* signerCertNode = CERT_LIST_HEAD(builtChain);
- if (!signerCertNode || CERT_LIST_END(signerCertNode, builtChain) ||
- !signerCertNode->cert) {
- return NS_ERROR_FAILURE;
- }
- nsCOMPtr<nsIX509Cert> signerCert =
- nsNSSCertificate::Create(signerCertNode->cert);
- NS_ENSURE_TRUE(signerCert, NS_ERROR_OUT_OF_MEMORY);
- signerCert.forget(aSignerCert);
- }
-
- return NS_OK;
-}
-
-class VerifySignedDirectoryTask final : public CryptoTask
-{
-public:
- VerifySignedDirectoryTask(AppTrustedRoot aTrustedRoot, nsIFile* aUnpackedJar,
- nsIVerifySignedDirectoryCallback* aCallback)
- : mTrustedRoot(aTrustedRoot)
- , mDirectory(aUnpackedJar)
- , mCallback(new nsMainThreadPtrHolder<nsIVerifySignedDirectoryCallback>(aCallback))
- {
- }
-
-private:
- virtual nsresult CalculateResult() override
- {
- return VerifySignedDirectory(mTrustedRoot,
- mDirectory,
- getter_AddRefs(mSignerCert));
- }
-
- // This class doesn't directly hold NSS resources so there's nothing that
- // needs to be released
- virtual void ReleaseNSSResources() override { }
-
- virtual void CallCallback(nsresult rv) override
- {
- (void) mCallback->VerifySignedDirectoryFinished(rv, mSignerCert);
- }
-
- const AppTrustedRoot mTrustedRoot;
- const nsCOMPtr<nsIFile> mDirectory;
- nsMainThreadPtrHandle<nsIVerifySignedDirectoryCallback> mCallback;
- nsCOMPtr<nsIX509Cert> mSignerCert; // out
-};
-
-NS_IMETHODIMP
-nsNSSCertificateDB::VerifySignedDirectoryAsync(
- AppTrustedRoot aTrustedRoot, nsIFile* aUnpackedJar,
- nsIVerifySignedDirectoryCallback* aCallback)
-{
- NS_ENSURE_ARG_POINTER(aUnpackedJar);
- NS_ENSURE_ARG_POINTER(aCallback);
- RefPtr<VerifySignedDirectoryTask> task(new VerifySignedDirectoryTask(aTrustedRoot,
- aUnpackedJar,
- aCallback));
- return task->Dispatch("UnpackedJar");
-}
diff --git a/security/apps/AppTrustDomain.cpp b/security/apps/AppTrustDomain.cpp
deleted file mode 100644
index 35be4ebd97..0000000000
--- a/security/apps/AppTrustDomain.cpp
+++ /dev/null
@@ -1,388 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "AppTrustDomain.h"
-#include "MainThreadUtils.h"
-#include "certdb.h"
-#include "mozilla/ArrayUtils.h"
-#include "mozilla/Casting.h"
-#include "mozilla/Preferences.h"
-#include "nsComponentManagerUtils.h"
-#include "nsIFile.h"
-#include "nsIFileStreams.h"
-#include "nsIX509CertDB.h"
-#include "nsNSSCertificate.h"
-#include "nsNetUtil.h"
-#include "pkix/pkixnss.h"
-#include "prerror.h"
-#include "secerr.h"
-
-// Generated in Makefile.in
-#include "marketplace-prod-public.inc"
-#include "marketplace-prod-reviewers.inc"
-#include "marketplace-dev-public.inc"
-#include "marketplace-dev-reviewers.inc"
-#include "marketplace-stage.inc"
-#include "xpcshell.inc"
-// Trusted Hosted Apps Certificates
-#include "manifest-signing-root.inc"
-#include "manifest-signing-test-root.inc"
-// Add-on signing Certificates
-#include "addons-public.inc"
-#include "addons-stage.inc"
-// Privileged Package Certificates
-#include "privileged-package-root.inc"
-
-using namespace mozilla::pkix;
-
-extern mozilla::LazyLogModule gPIPNSSLog;
-
-static const unsigned int DEFAULT_MIN_RSA_BITS = 2048;
-static char kDevImportedDER[] =
- "network.http.signed-packages.developer-root";
-
-namespace mozilla { namespace psm {
-
-StaticMutex AppTrustDomain::sMutex;
-UniquePtr<unsigned char[]> AppTrustDomain::sDevImportedDERData;
-unsigned int AppTrustDomain::sDevImportedDERLen = 0;
-
-AppTrustDomain::AppTrustDomain(UniqueCERTCertList& certChain, void* pinArg)
- : mCertChain(certChain)
- , mPinArg(pinArg)
- , mMinRSABits(DEFAULT_MIN_RSA_BITS)
-{
-}
-
-SECStatus
-AppTrustDomain::SetTrustedRoot(AppTrustedRoot trustedRoot)
-{
- SECItem trustedDER;
-
- // Load the trusted certificate into the in-memory NSS database so that
- // CERT_CreateSubjectCertList can find it.
-
- switch (trustedRoot)
- {
- case nsIX509CertDB::AppMarketplaceProdPublicRoot:
- trustedDER.data = const_cast<uint8_t*>(marketplaceProdPublicRoot);
- trustedDER.len = mozilla::ArrayLength(marketplaceProdPublicRoot);
- break;
-
- case nsIX509CertDB::AppMarketplaceProdReviewersRoot:
- trustedDER.data = const_cast<uint8_t*>(marketplaceProdReviewersRoot);
- trustedDER.len = mozilla::ArrayLength(marketplaceProdReviewersRoot);
- break;
-
- case nsIX509CertDB::AppMarketplaceDevPublicRoot:
- trustedDER.data = const_cast<uint8_t*>(marketplaceDevPublicRoot);
- trustedDER.len = mozilla::ArrayLength(marketplaceDevPublicRoot);
- break;
-
- case nsIX509CertDB::AppMarketplaceDevReviewersRoot:
- trustedDER.data = const_cast<uint8_t*>(marketplaceDevReviewersRoot);
- trustedDER.len = mozilla::ArrayLength(marketplaceDevReviewersRoot);
- break;
-
- case nsIX509CertDB::AppMarketplaceStageRoot:
- trustedDER.data = const_cast<uint8_t*>(marketplaceStageRoot);
- trustedDER.len = mozilla::ArrayLength(marketplaceStageRoot);
- // The staging root was generated with a 1024-bit key.
- mMinRSABits = 1024u;
- break;
-
- case nsIX509CertDB::AppXPCShellRoot:
- trustedDER.data = const_cast<uint8_t*>(xpcshellRoot);
- trustedDER.len = mozilla::ArrayLength(xpcshellRoot);
- break;
-
- case nsIX509CertDB::AddonsPublicRoot:
- trustedDER.data = const_cast<uint8_t*>(addonsPublicRoot);
- trustedDER.len = mozilla::ArrayLength(addonsPublicRoot);
- break;
-
- case nsIX509CertDB::AddonsStageRoot:
- trustedDER.data = const_cast<uint8_t*>(addonsStageRoot);
- trustedDER.len = mozilla::ArrayLength(addonsStageRoot);
- break;
-
- case nsIX509CertDB::PrivilegedPackageRoot:
- trustedDER.data = const_cast<uint8_t*>(privilegedPackageRoot);
- trustedDER.len = mozilla::ArrayLength(privilegedPackageRoot);
- break;
-
- case nsIX509CertDB::DeveloperImportedRoot: {
- StaticMutexAutoLock lock(sMutex);
- if (!sDevImportedDERData) {
- MOZ_ASSERT(!NS_IsMainThread());
- nsCOMPtr<nsIFile> file(do_CreateInstance("@mozilla.org/file/local;1"));
- if (!file) {
- PR_SetError(SEC_ERROR_IO, 0);
- return SECFailure;
- }
- nsresult rv = file->InitWithNativePath(
- Preferences::GetCString(kDevImportedDER));
- if (NS_FAILED(rv)) {
- PR_SetError(SEC_ERROR_IO, 0);
- return SECFailure;
- }
-
- nsCOMPtr<nsIInputStream> inputStream;
- NS_NewLocalFileInputStream(getter_AddRefs(inputStream), file, -1, -1,
- nsIFileInputStream::CLOSE_ON_EOF);
- if (!inputStream) {
- PR_SetError(SEC_ERROR_IO, 0);
- return SECFailure;
- }
-
- uint64_t length;
- rv = inputStream->Available(&length);
- if (NS_FAILED(rv)) {
- PR_SetError(SEC_ERROR_IO, 0);
- return SECFailure;
- }
-
- auto data = MakeUnique<char[]>(length);
- rv = inputStream->Read(data.get(), length, &sDevImportedDERLen);
- if (NS_FAILED(rv)) {
- PR_SetError(SEC_ERROR_IO, 0);
- return SECFailure;
- }
-
- MOZ_ASSERT(length == sDevImportedDERLen);
- sDevImportedDERData.reset(
- BitwiseCast<unsigned char*, char*>(data.release()));
- }
-
- trustedDER.data = sDevImportedDERData.get();
- trustedDER.len = sDevImportedDERLen;
- break;
- }
-
- default:
- PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
- return SECFailure;
- }
-
- mTrustedRoot.reset(CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
- &trustedDER, nullptr, false, true));
- if (!mTrustedRoot) {
- return SECFailure;
- }
-
- return SECSuccess;
-}
-
-Result
-AppTrustDomain::FindIssuer(Input encodedIssuerName, IssuerChecker& checker,
- Time)
-
-{
- MOZ_ASSERT(mTrustedRoot);
- if (!mTrustedRoot) {
- return Result::FATAL_ERROR_INVALID_STATE;
- }
-
- // TODO(bug 1035418): If/when mozilla::pkix relaxes the restriction that
- // FindIssuer must only pass certificates with a matching subject name to
- // checker.Check, we can stop using CERT_CreateSubjectCertList and instead
- // use logic like this:
- //
- // 1. First, try the trusted trust anchor.
- // 2. Secondly, iterate through the certificates that were stored in the CMS
- // message, passing each one to checker.Check.
- SECItem encodedIssuerNameSECItem =
- UnsafeMapInputToSECItem(encodedIssuerName);
- UniqueCERTCertList
- candidates(CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(),
- &encodedIssuerNameSECItem, 0,
- false));
- if (candidates) {
- for (CERTCertListNode* n = CERT_LIST_HEAD(candidates);
- !CERT_LIST_END(n, candidates); n = CERT_LIST_NEXT(n)) {
- Input certDER;
- Result rv = certDER.Init(n->cert->derCert.data, n->cert->derCert.len);
- if (rv != Success) {
- continue; // probably too big
- }
-
- bool keepGoing;
- rv = checker.Check(certDER, nullptr/*additionalNameConstraints*/,
- keepGoing);
- if (rv != Success) {
- return rv;
- }
- if (!keepGoing) {
- break;
- }
- }
- }
-
- return Success;
-}
-
-Result
-AppTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
- const CertPolicyId& policy,
- Input candidateCertDER,
- /*out*/ TrustLevel& trustLevel)
-{
- MOZ_ASSERT(policy.IsAnyPolicy());
- MOZ_ASSERT(mTrustedRoot);
- if (!policy.IsAnyPolicy()) {
- return Result::FATAL_ERROR_INVALID_ARGS;
- }
- if (!mTrustedRoot) {
- return Result::FATAL_ERROR_INVALID_STATE;
- }
-
- // Handle active distrust of the certificate.
-
- // XXX: This would be cleaner and more efficient if we could get the trust
- // information without constructing a CERTCertificate here, but NSS doesn't
- // expose it in any other easy-to-use fashion.
- SECItem candidateCertDERSECItem =
- UnsafeMapInputToSECItem(candidateCertDER);
- UniqueCERTCertificate candidateCert(
- CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &candidateCertDERSECItem,
- nullptr, false, true));
- if (!candidateCert) {
- return MapPRErrorCodeToResult(PR_GetError());
- }
-
- CERTCertTrust trust;
- if (CERT_GetCertTrust(candidateCert.get(), &trust) == SECSuccess) {
- uint32_t flags = SEC_GET_TRUST_FLAGS(&trust, trustObjectSigning);
-
- // For DISTRUST, we use the CERTDB_TRUSTED or CERTDB_TRUSTED_CA bit,
- // because we can have active distrust for either type of cert. Note that
- // CERTDB_TERMINAL_RECORD means "stop trying to inherit trust" so if the
- // relevant trust bit isn't set then that means the cert must be considered
- // distrusted.
- uint32_t relevantTrustBit = endEntityOrCA == EndEntityOrCA::MustBeCA
- ? CERTDB_TRUSTED_CA
- : CERTDB_TRUSTED;
- if (((flags & (relevantTrustBit | CERTDB_TERMINAL_RECORD)))
- == CERTDB_TERMINAL_RECORD) {
- trustLevel = TrustLevel::ActivelyDistrusted;
- return Success;
- }
- }
-
- // mTrustedRoot is the only trust anchor for this validation.
- if (CERT_CompareCerts(mTrustedRoot.get(), candidateCert.get())) {
- trustLevel = TrustLevel::TrustAnchor;
- return Success;
- }
-
- trustLevel = TrustLevel::InheritsTrust;
- return Success;
-}
-
-Result
-AppTrustDomain::DigestBuf(Input item,
- DigestAlgorithm digestAlg,
- /*out*/ uint8_t* digestBuf,
- size_t digestBufLen)
-{
- return DigestBufNSS(item, digestAlg, digestBuf, digestBufLen);
-}
-
-Result
-AppTrustDomain::CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
- /*optional*/ const Input*,
- /*optional*/ const Input*,
- /*optional*/ const Input*)
-{
- // We don't currently do revocation checking. If we need to distrust an Apps
- // certificate, we will use the active distrust mechanism.
- return Success;
-}
-
-Result
-AppTrustDomain::IsChainValid(const DERArray& certChain, Time time,
- const CertPolicyId& requiredPolicy)
-{
- SECStatus srv = ConstructCERTCertListFromReversedDERArray(certChain,
- mCertChain);
- if (srv != SECSuccess) {
- return MapPRErrorCodeToResult(PR_GetError());
- }
- return Success;
-}
-
-Result
-AppTrustDomain::CheckSignatureDigestAlgorithm(DigestAlgorithm,
- EndEntityOrCA,
- Time)
-{
- // TODO: We should restrict signatures to SHA-256 or better.
- return Success;
-}
-
-Result
-AppTrustDomain::CheckRSAPublicKeyModulusSizeInBits(
- EndEntityOrCA /*endEntityOrCA*/, unsigned int modulusSizeInBits)
-{
- if (modulusSizeInBits < mMinRSABits) {
- return Result::ERROR_INADEQUATE_KEY_SIZE;
- }
- return Success;
-}
-
-Result
-AppTrustDomain::VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
- Input subjectPublicKeyInfo)
-{
- // TODO: We should restrict signatures to SHA-256 or better.
- return VerifyRSAPKCS1SignedDigestNSS(signedDigest, subjectPublicKeyInfo,
- mPinArg);
-}
-
-Result
-AppTrustDomain::CheckECDSACurveIsAcceptable(EndEntityOrCA /*endEntityOrCA*/,
- NamedCurve curve)
-{
- switch (curve) {
- case NamedCurve::secp256r1: // fall through
- case NamedCurve::secp384r1: // fall through
- case NamedCurve::secp521r1:
- return Success;
- }
-
- return Result::ERROR_UNSUPPORTED_ELLIPTIC_CURVE;
-}
-
-Result
-AppTrustDomain::VerifyECDSASignedDigest(const SignedDigest& signedDigest,
- Input subjectPublicKeyInfo)
-{
- return VerifyECDSASignedDigestNSS(signedDigest, subjectPublicKeyInfo,
- mPinArg);
-}
-
-Result
-AppTrustDomain::CheckValidityIsAcceptable(Time /*notBefore*/, Time /*notAfter*/,
- EndEntityOrCA /*endEntityOrCA*/,
- KeyPurposeId /*keyPurpose*/)
-{
- return Success;
-}
-
-Result
-AppTrustDomain::NetscapeStepUpMatchesServerAuth(Time /*notBefore*/,
- /*out*/ bool& matches)
-{
- matches = false;
- return Success;
-}
-
-void
-AppTrustDomain::NoteAuxiliaryExtension(AuxiliaryExtension /*extension*/,
- Input /*extensionData*/)
-{
-}
-
-} } // namespace mozilla::psm
diff --git a/security/apps/AppTrustDomain.h b/security/apps/AppTrustDomain.h
deleted file mode 100644
index e4a8ec5e50..0000000000
--- a/security/apps/AppTrustDomain.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef AppTrustDomain_h
-#define AppTrustDomain_h
-
-#include "pkix/pkixtypes.h"
-#include "mozilla/StaticMutex.h"
-#include "mozilla/UniquePtr.h"
-#include "nsDebug.h"
-#include "nsIX509CertDB.h"
-#include "ScopedNSSTypes.h"
-
-namespace mozilla { namespace psm {
-
-class AppTrustDomain final : public mozilla::pkix::TrustDomain
-{
-public:
- typedef mozilla::pkix::Result Result;
-
- AppTrustDomain(UniqueCERTCertList& certChain, void* pinArg);
-
- SECStatus SetTrustedRoot(AppTrustedRoot trustedRoot);
-
- virtual Result GetCertTrust(mozilla::pkix::EndEntityOrCA endEntityOrCA,
- const mozilla::pkix::CertPolicyId& policy,
- mozilla::pkix::Input candidateCertDER,
- /*out*/ mozilla::pkix::TrustLevel& trustLevel)
- override;
- virtual Result FindIssuer(mozilla::pkix::Input encodedIssuerName,
- IssuerChecker& checker,
- mozilla::pkix::Time time) override;
- virtual Result CheckRevocation(mozilla::pkix::EndEntityOrCA endEntityOrCA,
- const mozilla::pkix::CertID& certID,
- mozilla::pkix::Time time,
- mozilla::pkix::Duration validityDuration,
- /*optional*/ const mozilla::pkix::Input* stapledOCSPresponse,
- /*optional*/ const mozilla::pkix::Input* aiaExtension,
- /*optional*/ const mozilla::pkix::Input* sctExtension) override;
- virtual Result IsChainValid(const mozilla::pkix::DERArray& certChain,
- mozilla::pkix::Time time,
- const mozilla::pkix::CertPolicyId& requiredPolicy) override;
- virtual Result CheckSignatureDigestAlgorithm(
- mozilla::pkix::DigestAlgorithm digestAlg,
- mozilla::pkix::EndEntityOrCA endEntityOrCA,
- mozilla::pkix::Time notBefore) override;
- virtual Result CheckRSAPublicKeyModulusSizeInBits(
- mozilla::pkix::EndEntityOrCA endEntityOrCA,
- unsigned int modulusSizeInBits) override;
- virtual Result VerifyRSAPKCS1SignedDigest(
- const mozilla::pkix::SignedDigest& signedDigest,
- mozilla::pkix::Input subjectPublicKeyInfo) override;
- virtual Result CheckECDSACurveIsAcceptable(
- mozilla::pkix::EndEntityOrCA endEntityOrCA,
- mozilla::pkix::NamedCurve curve) override;
- virtual Result VerifyECDSASignedDigest(
- const mozilla::pkix::SignedDigest& signedDigest,
- mozilla::pkix::Input subjectPublicKeyInfo) override;
- virtual Result CheckValidityIsAcceptable(
- mozilla::pkix::Time notBefore, mozilla::pkix::Time notAfter,
- mozilla::pkix::EndEntityOrCA endEntityOrCA,
- mozilla::pkix::KeyPurposeId keyPurpose) override;
- virtual Result NetscapeStepUpMatchesServerAuth(
- mozilla::pkix::Time notBefore,
- /*out*/ bool& matches) override;
- virtual void NoteAuxiliaryExtension(
- mozilla::pkix::AuxiliaryExtension extension,
- mozilla::pkix::Input extensionData) override;
- virtual Result DigestBuf(mozilla::pkix::Input item,
- mozilla::pkix::DigestAlgorithm digestAlg,
- /*out*/ uint8_t* digestBuf,
- size_t digestBufLen) override;
-
-private:
- /*out*/ UniqueCERTCertList& mCertChain;
- void* mPinArg; // non-owning!
- UniqueCERTCertificate mTrustedRoot;
- unsigned int mMinRSABits;
-
- static StaticMutex sMutex;
- static UniquePtr<unsigned char[]> sDevImportedDERData;
- static unsigned int sDevImportedDERLen;
-};
-
-} } // namespace mozilla::psm
-
-#endif // AppTrustDomain_h
diff --git a/security/apps/addons-public.crt b/security/apps/addons-public.crt
deleted file mode 100644
index 6ab711b996..0000000000
--- a/security/apps/addons-public.crt
+++ /dev/null
Binary files differ
diff --git a/security/apps/addons-stage.crt b/security/apps/addons-stage.crt
deleted file mode 100644
index 73e48cadfe..0000000000
--- a/security/apps/addons-stage.crt
+++ /dev/null
Binary files differ
diff --git a/security/apps/gen_cert_header.py b/security/apps/gen_cert_header.py
deleted file mode 100644
index 0ffe25cf4e..0000000000
--- a/security/apps/gen_cert_header.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-import binascii
-
-def _file_byte_generator(filename):
- with open(filename, "rb") as f:
- contents = f.read()
-
- # Treat empty files the same as a file containing a lone 0;
- # a single-element array will fail cert verifcation just as an
- # empty array would.
- if not contents:
- return ['\0']
-
- return contents
-
-def _create_header(array_name, cert_bytes):
- hexified = ["0x" + binascii.hexlify(byte) for byte in cert_bytes]
- substs = { 'array_name': array_name, 'bytes': ', '.join(hexified) }
- return "const uint8_t %(array_name)s[] = {\n%(bytes)s\n};\n" % substs
-
-# Create functions named the same as the data arrays that we're going to
-# write to the headers, so we don't have to duplicate the names like so:
-#
-# def arrayName(header, cert_filename):
-# header.write(_create_header("arrayName", cert_filename))
-array_names = [
- 'marketplaceProdPublicRoot',
- 'marketplaceProdReviewersRoot',
- 'marketplaceDevPublicRoot',
- 'marketplaceDevReviewersRoot',
- 'marketplaceStageRoot',
- 'trustedAppPublicRoot',
- 'trustedAppTestRoot',
- 'xpcshellRoot',
- 'addonsPublicRoot',
- 'addonsStageRoot',
- 'privilegedPackageRoot',
-]
-
-for n in array_names:
- # Make sure the lambda captures the right string.
- globals()[n] = lambda header, cert_filename, name=n: header.write(_create_header(name, _file_byte_generator(cert_filename)))
diff --git a/security/apps/marketplace-dev-public.crt b/security/apps/marketplace-dev-public.crt
deleted file mode 100644
index 490b8682b7..0000000000
--- a/security/apps/marketplace-dev-public.crt
+++ /dev/null
Binary files differ
diff --git a/security/apps/marketplace-dev-reviewers.crt b/security/apps/marketplace-dev-reviewers.crt
deleted file mode 100644
index 5b8bde9337..0000000000
--- a/security/apps/marketplace-dev-reviewers.crt
+++ /dev/null
Binary files differ
diff --git a/security/apps/marketplace-prod-public.crt b/security/apps/marketplace-prod-public.crt
deleted file mode 100644
index 85c2fed92a..0000000000
--- a/security/apps/marketplace-prod-public.crt
+++ /dev/null
Binary files differ
diff --git a/security/apps/marketplace-prod-reviewers.crt b/security/apps/marketplace-prod-reviewers.crt
deleted file mode 100644
index 53be8c81ed..0000000000
--- a/security/apps/marketplace-prod-reviewers.crt
+++ /dev/null
Binary files differ
diff --git a/security/apps/marketplace-stage.crt b/security/apps/marketplace-stage.crt
deleted file mode 100644
index 84504f3574..0000000000
--- a/security/apps/marketplace-stage.crt
+++ /dev/null
Binary files differ
diff --git a/security/apps/moz.build b/security/apps/moz.build
deleted file mode 100644
index 365379881b..0000000000
--- a/security/apps/moz.build
+++ /dev/null
@@ -1,43 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-UNIFIED_SOURCES += [
- 'AppSignatureVerification.cpp',
- 'AppTrustDomain.cpp',
-]
-
-FINAL_LIBRARY = 'xul'
-
-LOCAL_INCLUDES += [
- '/security/certverifier',
- '/security/manager/ssl',
- '/security/pkix/include',
-]
-
-DEFINES['NSS_ENABLE_ECC'] = 'True'
-for var in ('DLL_PREFIX', 'DLL_SUFFIX'):
- DEFINES[var] = '"%s"' % CONFIG[var]
-
-test_ssl_path = '/security/manager/ssl/tests/unit'
-
-headers_arrays_certs = [
- ('marketplace-prod-public.inc', 'marketplaceProdPublicRoot', 'marketplace-prod-public.crt'),
- ('marketplace-prod-reviewers.inc', 'marketplaceProdReviewersRoot', 'marketplace-prod-reviewers.crt'),
- ('marketplace-dev-public.inc', 'marketplaceDevPublicRoot', 'marketplace-dev-public.crt'),
- ('marketplace-dev-reviewers.inc', 'marketplaceDevReviewersRoot', 'marketplace-dev-reviewers.crt'),
- ('marketplace-stage.inc', 'marketplaceStageRoot', 'marketplace-stage.crt'),
- ('manifest-signing-root.inc', 'trustedAppPublicRoot', 'trusted-app-public.der'),
- ('manifest-signing-test-root.inc', 'trustedAppTestRoot', test_ssl_path + '/test_signed_manifest/trusted_ca1.der'),
- ('xpcshell.inc', 'xpcshellRoot', test_ssl_path + '/test_signed_apps/trusted_ca1.der'),
- ('addons-public.inc', 'addonsPublicRoot', 'addons-public.crt'),
- ('addons-stage.inc', 'addonsStageRoot', 'addons-stage.crt'),
- ('privileged-package-root.inc', 'privilegedPackageRoot', 'privileged-package-root.der'),
-]
-
-for header, array_name, cert in headers_arrays_certs:
- GENERATED_FILES += [header]
- h = GENERATED_FILES[header]
- h.script = 'gen_cert_header.py:' + array_name
- h.inputs = [cert]
diff --git a/security/apps/privileged-package-root.der b/security/apps/privileged-package-root.der
deleted file mode 100644
index 9f77af5823..0000000000
--- a/security/apps/privileged-package-root.der
+++ /dev/null
Binary files differ
diff --git a/security/apps/trusted-app-public.der b/security/apps/trusted-app-public.der
deleted file mode 100644
index e69de29bb2..0000000000
--- a/security/apps/trusted-app-public.der
+++ /dev/null
diff --git a/security/manager/ssl/nsIX509CertDB.idl b/security/manager/ssl/nsIX509CertDB.idl
index 44d8e0588c..1dbef22fbd 100644
--- a/security/manager/ssl/nsIX509CertDB.idl
+++ b/security/manager/ssl/nsIX509CertDB.idl
@@ -265,74 +265,11 @@ interface nsIX509CertDB : nsISupports {
*/
nsIX509Cert constructX509(in string certDER, in unsigned long length);
- /**
- * Verifies the signature on the given JAR file to verify that it has a
- * valid signature. To be considered valid, there must be exactly one
- * signature on the JAR file and that signature must have signed every
- * entry. Further, the signature must come from a certificate that
- * is trusted for code signing.
- *
- * On success, NS_OK, a nsIZipReader, and the trusted certificate that
- * signed the JAR are returned.
- *
- * On failure, an error code is returned.
- *
- * This method returns a nsIZipReader, instead of taking an nsIZipReader
- * as input, to encourage users of the API to verify the signature as the
- * first step in opening the JAR.
- */
- const AppTrustedRoot AppMarketplaceProdPublicRoot = 1;
- const AppTrustedRoot AppMarketplaceProdReviewersRoot = 2;
- const AppTrustedRoot AppMarketplaceDevPublicRoot = 3;
- const AppTrustedRoot AppMarketplaceDevReviewersRoot = 4;
- const AppTrustedRoot AppMarketplaceStageRoot = 5;
- const AppTrustedRoot AppXPCShellRoot = 6;
- const AppTrustedRoot AddonsPublicRoot = 7;
- const AppTrustedRoot AddonsStageRoot = 8;
- const AppTrustedRoot PrivilegedPackageRoot = 9;
- /*
- * If DeveloperImportedRoot is set as trusted root, a CA from local file
- * system will be imported. Only used when preference
- * "network.http.packaged-apps-developer-mode" is set.
- * The path of the CA is specified by preference
- * "network.http.packaged-apps-developer-trusted-root".
- */
- const AppTrustedRoot DeveloperImportedRoot = 10;
- void openSignedAppFileAsync(in AppTrustedRoot trustedRoot,
- in nsIFile aJarFile,
- in nsIOpenSignedAppFileCallback callback);
-
- /**
- * Verifies the signature on a directory representing an unpacked signed
- * JAR file. To be considered valid, there must be exactly one signature
- * on the directory structure and that signature must have signed every
- * entry. Further, the signature must come from a certificate that
- * is trusted for code signing.
- *
- * On success NS_OK and the trusted certificate that signed the
- * unpacked JAR are returned.
- *
- * On failure, an error code is returned.
- */
- void verifySignedDirectoryAsync(in AppTrustedRoot trustedRoot,
- in nsIFile aUnpackedDir,
- in nsIVerifySignedDirectoryCallback callback);
-
- /**
- * Given streams containing a signature and a manifest file, verifies
- * that the signature is valid for the manifest. The signature must
- * come from a certificate that is trusted for code signing and that
- * was issued by the given trusted root.
- *
- * On success, NS_OK and the trusted certificate that signed the
- * Manifest are returned.
- *
- * On failure, an error code is returned.
- */
- void verifySignedManifestAsync(in AppTrustedRoot trustedRoot,
- in nsIInputStream aManifestStream,
- in nsIInputStream aSignatureStream,
- in nsIVerifySignedManifestCallback callback);
+ // Flags to indicate the type of cert root for signed extensions
+ // This can probably be removed eventually.
+ const AppTrustedRoot AddonsPublicRoot = 1;
+ const AppTrustedRoot AddonsStageRoot = 2;
+ const AppTrustedRoot PrivilegedPackageRoot = 3;
/*
* Add a cert to a cert DB from a binary string.