diff options
author | Moonchild <moonchild@palemoon.org> | 2022-07-22 00:16:06 +0000 |
---|---|---|
committer | Moonchild <moonchild@palemoon.org> | 2022-07-22 02:30:42 +0000 |
commit | c6c045a7f7d19110986c60965da56f6864ea600b (patch) | |
tree | 425f1291d3d428d9edc3c1ff6d981ba6289d4e64 /security | |
parent | a5421542e5fbeb2167cbdd4b2e19e7482a227ca7 (diff) | |
download | uxp-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.cpp | 1559 | ||||
-rw-r--r-- | security/apps/AppTrustDomain.cpp | 388 | ||||
-rw-r--r-- | security/apps/AppTrustDomain.h | 89 | ||||
-rw-r--r-- | security/apps/addons-public.crt | bin | 1637 -> 0 bytes | |||
-rw-r--r-- | security/apps/addons-stage.crt | bin | 1895 -> 0 bytes | |||
-rw-r--r-- | security/apps/gen_cert_header.py | 45 | ||||
-rw-r--r-- | security/apps/marketplace-dev-public.crt | bin | 964 -> 0 bytes | |||
-rw-r--r-- | security/apps/marketplace-dev-reviewers.crt | bin | 1012 -> 0 bytes | |||
-rw-r--r-- | security/apps/marketplace-prod-public.crt | bin | 1177 -> 0 bytes | |||
-rw-r--r-- | security/apps/marketplace-prod-reviewers.crt | bin | 1171 -> 0 bytes | |||
-rw-r--r-- | security/apps/marketplace-stage.crt | bin | 1157 -> 0 bytes | |||
-rw-r--r-- | security/apps/moz.build | 43 | ||||
-rw-r--r-- | security/apps/privileged-package-root.der | bin | 930 -> 0 bytes | |||
-rw-r--r-- | security/apps/trusted-app-public.der | 0 | ||||
-rw-r--r-- | security/manager/ssl/nsIX509CertDB.idl | 73 |
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 Binary files differdeleted file mode 100644 index 6ab711b996..0000000000 --- a/security/apps/addons-public.crt +++ /dev/null diff --git a/security/apps/addons-stage.crt b/security/apps/addons-stage.crt Binary files differdeleted file mode 100644 index 73e48cadfe..0000000000 --- a/security/apps/addons-stage.crt +++ /dev/null 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 Binary files differdeleted file mode 100644 index 490b8682b7..0000000000 --- a/security/apps/marketplace-dev-public.crt +++ /dev/null diff --git a/security/apps/marketplace-dev-reviewers.crt b/security/apps/marketplace-dev-reviewers.crt Binary files differdeleted file mode 100644 index 5b8bde9337..0000000000 --- a/security/apps/marketplace-dev-reviewers.crt +++ /dev/null diff --git a/security/apps/marketplace-prod-public.crt b/security/apps/marketplace-prod-public.crt Binary files differdeleted file mode 100644 index 85c2fed92a..0000000000 --- a/security/apps/marketplace-prod-public.crt +++ /dev/null diff --git a/security/apps/marketplace-prod-reviewers.crt b/security/apps/marketplace-prod-reviewers.crt Binary files differdeleted file mode 100644 index 53be8c81ed..0000000000 --- a/security/apps/marketplace-prod-reviewers.crt +++ /dev/null diff --git a/security/apps/marketplace-stage.crt b/security/apps/marketplace-stage.crt Binary files differdeleted file mode 100644 index 84504f3574..0000000000 --- a/security/apps/marketplace-stage.crt +++ /dev/null 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 Binary files differdeleted file mode 100644 index 9f77af5823..0000000000 --- a/security/apps/privileged-package-root.der +++ /dev/null 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. |