diff --git a/security/apps/AppSignatureVerification.cpp b/security/apps/AppSignatureVerification.cpp deleted file mode 100644 index 829322c6db..0000000000 --- a/security/apps/AppSignatureVerification.cpp +++ /dev/null @@ -1,1367 +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/. */ - -#include "nsNSSCertificateDB.h" - -#include "AppTrustDomain.h" -#include "CryptoTask.h" -#include "NSSCertDBTrustDomain.h" -#include "ScopedNSSTypes.h" -#include "SharedCertVerifier.h" -#include "certdb.h" -#include "cms.h" -#include "cosec.h" -#include "mozilla/Base64.h" -#include "mozilla/Casting.h" -#include "mozilla/Logging.h" -#include "mozilla/Preferences.h" -#include "mozilla/RefPtr.h" -#include "mozilla/UniquePtr.h" -#include "mozilla/Unused.h" -#include "nsCOMPtr.h" -#include "nsComponentManagerUtils.h" -#include "nsDependentString.h" -#include "nsHashKeys.h" -#include "nsIFile.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 "mozpkix/pkix.h" -#include "mozpkix/pkixnss.h" -#include "plstr.h" -#include "secmime.h" - -using namespace mozilla::pkix; -using namespace mozilla; -using namespace mozilla::psm; - -extern mozilla::LazyLogModule gPIPNSSLog; - -namespace { - -// A convenient way to pair the bytes of a digest with the algorithm that -// purportedly produced those bytes. Only SHA-1 and SHA-256 are supported. -struct DigestWithAlgorithm { - nsresult ValidateLength() const { - size_t hashLen; - switch (mAlgorithm) { - case SEC_OID_SHA256: - hashLen = SHA256_LENGTH; - break; - case SEC_OID_SHA1: - hashLen = SHA1_LENGTH; - break; - default: - MOZ_ASSERT_UNREACHABLE( - "unsupported hash type in DigestWithAlgorithm::ValidateLength"); - return NS_ERROR_FAILURE; - } - if (mDigest.Length() != hashLen) { - return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID; - } - return NS_OK; - } - - nsAutoCString mDigest; - SECOidTag mAlgorithm; -}; - -// The digest must have a lifetime greater than or equal to the returned string. -inline nsDependentCSubstring DigestToDependentString(const Digest& digest) { - return nsDependentCSubstring( - BitwiseCast(digest.get().data), digest.get().len); -} - -// Reads a maximum of 8MB from a stream into the supplied buffer. -// The reason for the 8MB 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& 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 8MB (which - // should be much larger than necessary for our purposes) to avoid OOM. - static const uint32_t MAX_LENGTH = 8 * 1000 * 1000; - 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(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(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 loads it. Fails if there are no matches or if -// there is more than one match. If bufDigest is not null then on success -// bufDigest will contain the digeset of the entry using the given digest -// algorithm. -nsresult FindAndLoadOneEntry( - nsIZipReader* zip, const nsACString& searchPattern, - /*out*/ nsACString& filename, - /*out*/ SECItem& buf, - /*optional, in*/ SECOidTag digestAlgorithm = SEC_OID_SHA1, - /*optional, out*/ Digest* bufDigest = nullptr) { - nsCOMPtr 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 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(digestAlgorithm, 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 DigestWithAlgorithm& digestFromManifest, - SECItem& buf) { - MOZ_ASSERT(buf.len > 0); - nsresult rv = digestFromManifest.ValidateLength(); - if (NS_FAILED(rv)) { - return 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(digestFromManifest.mAlgorithm)); - 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(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(digestFromManifest.mAlgorithm, digestContext); - NS_ENSURE_SUCCESS(rv, rv); - - nsDependentCSubstring digestStr(DigestToDependentString(digest)); - if (!digestStr.Equals(digestFromManifest.mDigest)) { - return NS_ERROR_SIGNED_JAR_MODIFIED_ENTRY; - } - - return NS_OK; -} - -nsresult VerifyEntryContentDigest(nsIZipReader* zip, - const nsACString& aFilename, - const DigestWithAlgorithm& digestFromManifest, - SECItem& buf) { - nsCOMPtr 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); -} - -// 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_COSE_MF_SEARCH_STRING "(M|/M)ETA-INF/cose.manifest$" -#define JAR_SF_SEARCH_STRING "(M|/M)ETA-INF/*.(SF|sf)$" -#define JAR_RSA_SEARCH_STRING "(M|/M)ETA-INF/*.(RSA|rsa)$" -#define JAR_COSE_SEARCH_STRING "(M|/M)ETA-INF/cose.sig$" -#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) based on the JDK 8 JAR Specification. -// -// The SF file must contain a SHA*-Digest-Manifest attribute in the main -// section (where the * is either 1 or 256, depending on the given digest -// algorithm). 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. -// -// filebuf must be null-terminated. On output, mfDigest will contain the -// decoded value of the appropriate SHA*-DigestManifest, if found. -nsresult ParseSF(const char* filebuf, SECOidTag digestAlgorithm, - /*out*/ nsAutoCString& mfDigest) { - const char* digestNameToFind = nullptr; - switch (digestAlgorithm) { - case SEC_OID_SHA256: - digestNameToFind = "sha256-digest-manifest"; - break; - case SEC_OID_SHA1: - digestNameToFind = "sha1-digest-manifest"; - break; - default: - MOZ_ASSERT_UNREACHABLE("bad argument to ParseSF"); - return NS_ERROR_FAILURE; - } - - const char* nextLineStart = filebuf; - nsresult rv = - CheckManifestVersion(nextLineStart, NS_LITERAL_CSTRING(JAR_SF_HEADER)); - if (NS_FAILED(rv)) { - return rv; - } - - 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). We didn't find the - // SHA*-Digest-Manifest we were looking for. - return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID; - } - - nsAutoCString attrName; - nsAutoCString attrValue; - rv = ParseAttribute(curLine, attrName, attrValue); - if (NS_FAILED(rv)) { - return rv; - } - - if (attrName.EqualsIgnoreCase(digestNameToFind)) { - rv = Base64Decode(attrValue, mfDigest); - if (NS_FAILED(rv)) { - return rv; - } - - // There could be multiple SHA*-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 SHA*-Digest-Manifest - // attributes. - return NS_OK; - } - - // ignore unrecognized attributes - } - - MOZ_ASSERT_UNREACHABLE("somehow exited loop in ParseSF without returning"); - return NS_ERROR_FAILURE; -} - -// 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. Each file's contents are verified against the entry in the manifest with -// the digest algorithm that matches the given one. This algorithm comes from -// the signature file. If the signature file has a SHA-256 digest, then SHA-256 -// entries must be present in the manifest file. If the signature file only has -// a SHA-1 digest, then only SHA-1 digests will be used in the manifest file. -nsresult ParseMF(const char* filebuf, nsIZipReader* zip, - SECOidTag digestAlgorithm, - /*out*/ nsTHashtable& mfItems, - ScopedAutoSECItem& buf) { - const char* digestNameToFind = nullptr; - switch (digestAlgorithm) { - case SEC_OID_SHA256: - digestNameToFind = "sha256-digest"; - break; - case SEC_OID_SHA1: - digestNameToFind = "sha1-digest"; - break; - default: - MOZ_ASSERT_UNREACHABLE("bad argument to ParseMF"); - return NS_ERROR_FAILURE; - } - - const char* nextLineStart = filebuf; - nsresult 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; - nsAutoCString 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.IsEmpty()) { - // 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. - DigestWithAlgorithm digestWithAlgorithm = {digest, digestAlgorithm}; - rv = VerifyEntryContentDigest(zip, curItemName, digestWithAlgorithm, 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.Truncate(); - - 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.EqualsIgnoreCase(digestNameToFind)) { - if (!digest.IsEmpty()) { // multiple SHA* digests in section - return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID; - } - - rv = Base64Decode(attrValue, digest); - 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; -} - -nsresult VerifyCertificate(CERTCertificate* signerCert, - AppTrustedRoot trustedRoot, - /*out*/ UniqueCERTCertList& builtChain) { - if (NS_WARN_IF(!signerCert)) { - return NS_ERROR_INVALID_ARG; - } - // TODO: pinArg is null. - AppTrustDomain trustDomain(builtChain, nullptr); - nsresult rv = trustDomain.SetTrustedRoot(trustedRoot); - if (NS_FAILED(rv)) { - return rv; - } - Input certDER; - mozilla::pkix::Result result = - certDER.Init(signerCert->derCert.data, signerCert->derCert.len); - if (result != Success) { - return mozilla::psm::GetXPCOMFromNSSError(MapResultToPRErrorCode(result)); - } - - result = BuildCertChain( - trustDomain, certDER, Now(), EndEntityOrCA::MustBeEndEntity, - KeyUsage::digitalSignature, KeyPurposeId::id_kp_codeSigning, - CertPolicyId::anyPolicy, nullptr /*stapledOCSPResponse*/); - if (result == 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) - result = Success; - } - if (result != Success) { - return mozilla::psm::GetXPCOMFromNSSError(MapResultToPRErrorCode(result)); - } - - return NS_OK; -} - -// Given a SECOidTag representing a digest algorithm (either SEC_OID_SHA1 or -// SEC_OID_SHA256), returns the first signerInfo in the given signedData that -// purports to have been created using that digest algorithm, or nullptr if -// there is none. -// The returned signerInfo is owned by signedData, so the caller must ensure -// that the lifetime of the signerInfo is contained by the lifetime of the -// signedData. -NSSCMSSignerInfo* GetSignerInfoForDigestAlgorithm(NSSCMSSignedData* signedData, - SECOidTag digestAlgorithm) { - MOZ_ASSERT(digestAlgorithm == SEC_OID_SHA1 || - digestAlgorithm == SEC_OID_SHA256); - if (digestAlgorithm != SEC_OID_SHA1 && digestAlgorithm != SEC_OID_SHA256) { - return nullptr; - } - - int numSigners = NSS_CMSSignedData_SignerInfoCount(signedData); - if (numSigners < 1) { - return nullptr; - } - for (int i = 0; i < numSigners; i++) { - NSSCMSSignerInfo* signerInfo = - NSS_CMSSignedData_GetSignerInfo(signedData, i); - // NSS_CMSSignerInfo_GetDigestAlgTag isn't exported from NSS. - SECOidData* digestAlgOID = SECOID_FindOID(&signerInfo->digestAlg.algorithm); - if (!digestAlgOID) { - continue; - } - if (digestAlgorithm == digestAlgOID->offset) { - return signerInfo; - } - } - return nullptr; -} - -nsresult VerifySignature(AppTrustedRoot trustedRoot, const SECItem& buffer, - const SECItem& detachedSHA1Digest, - const SECItem& detachedSHA256Digest, - /*out*/ SECOidTag& digestAlgorithm, - /*out*/ UniqueCERTCertList& builtChain) { - if (NS_WARN_IF(!buffer.data || buffer.len == 0 || !detachedSHA1Digest.data || - detachedSHA1Digest.len == 0 || !detachedSHA256Digest.data || - detachedSHA256Digest.len == 0)) { - return NS_ERROR_INVALID_ARG; - } - - UniqueNSSCMSMessage cmsMsg(NSS_CMSMessage_CreateFromDER( - const_cast(&buffer), nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr)); - if (!cmsMsg) { - return NS_ERROR_CMS_VERIFY_NOT_SIGNED; - } - - if (!NSS_CMSMessage_IsSigned(cmsMsg.get())) { - return NS_ERROR_CMS_VERIFY_NOT_SIGNED; - } - - NSSCMSContentInfo* cinfo = NSS_CMSMessage_ContentLevel(cmsMsg.get(), 0); - if (!cinfo) { - return NS_ERROR_CMS_VERIFY_NO_CONTENT_INFO; - } - - // We're expecting this to be a PKCS#7 signedData content info. - if (NSS_CMSContentInfo_GetContentTypeTag(cinfo) != - SEC_OID_PKCS7_SIGNED_DATA) { - return NS_ERROR_CMS_VERIFY_NO_CONTENT_INFO; - } - - // signedData is non-owning - NSSCMSSignedData* signedData = - static_cast(NSS_CMSContentInfo_GetContent(cinfo)); - if (!signedData) { - return NS_ERROR_CMS_VERIFY_NO_CONTENT_INFO; - } - - // Parse the certificates into CERTCertificate objects held in memory so - // verifyCertificate will be able to find them during path building. - UniqueCERTCertList certs(CERT_NewCertList()); - if (!certs) { - return NS_ERROR_OUT_OF_MEMORY; - } - if (signedData->rawCerts) { - for (size_t i = 0; signedData->rawCerts[i]; ++i) { - UniqueCERTCertificate cert(CERT_NewTempCertificate( - CERT_GetDefaultCertDB(), signedData->rawCerts[i], nullptr, false, - true)); - // Skip certificates that fail to parse - if (!cert) { - continue; - } - - if (CERT_AddCertToListTail(certs.get(), cert.get()) != SECSuccess) { - return NS_ERROR_OUT_OF_MEMORY; - } - - Unused << cert.release(); // Ownership transferred to the cert list. - } - } - - NSSCMSSignerInfo* signerInfo = - GetSignerInfoForDigestAlgorithm(signedData, SEC_OID_SHA256); - const SECItem* detachedDigest = &detachedSHA256Digest; - digestAlgorithm = SEC_OID_SHA256; - if (!signerInfo) { - signerInfo = GetSignerInfoForDigestAlgorithm(signedData, SEC_OID_SHA1); - if (!signerInfo) { - return NS_ERROR_CMS_VERIFY_NOT_SIGNED; - } - detachedDigest = &detachedSHA1Digest; - digestAlgorithm = SEC_OID_SHA1; - } - - // Get the end-entity certificate. - CERTCertificate* signerCert = NSS_CMSSignerInfo_GetSigningCertificate( - signerInfo, CERT_GetDefaultCertDB()); - if (!signerCert) { - return NS_ERROR_CMS_VERIFY_ERROR_PROCESSING; - } - - nsresult rv = VerifyCertificate(signerCert, trustedRoot, builtChain); - if (NS_FAILED(rv)) { - return rv; - } - - // Ensure that the PKCS#7 data OID is present as the PKCS#9 contentType. - const char* pkcs7DataOidString = "1.2.840.113549.1.7.1"; - ScopedAutoSECItem pkcs7DataOid; - if (SEC_StringToOID(nullptr, &pkcs7DataOid, pkcs7DataOidString, 0) != - SECSuccess) { - return NS_ERROR_CMS_VERIFY_ERROR_PROCESSING; - } - - return MapSECStatus(NSS_CMSSignerInfo_Verify( - signerInfo, const_cast(detachedDigest), &pkcs7DataOid)); -} - -class CoseVerificationContext { - public: - explicit CoseVerificationContext(AppTrustedRoot aTrustedRoot) - : mTrustedRoot(aTrustedRoot), mCertDER(nullptr), mCertDERLen(0) {} - ~CoseVerificationContext() {} - - AppTrustedRoot GetTrustedRoot() { return mTrustedRoot; } - nsresult SetCert(SECItem* aCertDER) { - mCertDERLen = aCertDER->len; - mCertDER = MakeUnique(mCertDERLen); - if (!mCertDER) { - return NS_ERROR_OUT_OF_MEMORY; - } - memcpy(mCertDER.get(), aCertDER->data, mCertDERLen); - return NS_OK; - } - uint8_t* GetCert() { return mCertDER.get(); } - unsigned int GetCertLen() { return mCertDERLen; } - - private: - AppTrustedRoot mTrustedRoot; - UniquePtr mCertDER; - unsigned int mCertDERLen; -}; - -// Verification function called from cose-rust. -// Returns true if everything goes well and the signature and certificate chain -// are good, false in any other case. -bool CoseVerificationCallback(const uint8_t* aPayload, size_t aPayloadLen, - const uint8_t** aCertChain, size_t aCertChainLen, - const size_t* aCertsLen, const uint8_t* aEECert, - size_t aEECertLen, const uint8_t* aSignature, - size_t aSignatureLen, uint8_t aSignatureAlgorithm, - void* ctx) { - if (!ctx || !aPayload || !aEECert || !aSignature) { - return false; - } - // The ctx here is a pointer to a CoseVerificationContext object - CoseVerificationContext* context = static_cast(ctx); - AppTrustedRoot aTrustedRoot = context->GetTrustedRoot(); - - CK_MECHANISM_TYPE mechanism; - SECOidTag oid; - uint32_t hash_length; - SECItem param = {siBuffer, nullptr, 0}; - switch (aSignatureAlgorithm) { - case ES256: - mechanism = CKM_ECDSA; - oid = SEC_OID_SHA256; - hash_length = SHA256_LENGTH; - break; - case ES384: - mechanism = CKM_ECDSA; - oid = SEC_OID_SHA384; - hash_length = SHA384_LENGTH; - break; - case ES512: - mechanism = CKM_ECDSA; - oid = SEC_OID_SHA512; - hash_length = SHA512_LENGTH; - break; - default: - return false; - } - - uint8_t hashBuf[HASH_LENGTH_MAX]; - SECStatus rv = PK11_HashBuf(oid, hashBuf, aPayload, aPayloadLen); - if (rv != SECSuccess) { - return false; - } - SECItem hashItem = {siBuffer, hashBuf, hash_length}; - CERTCertDBHandle* dbHandle = CERT_GetDefaultCertDB(); - if (!dbHandle) { - return false; - } - SECItem derCert = {siBuffer, const_cast(aEECert), - static_cast(aEECertLen)}; - UniqueCERTCertificate cert( - CERT_NewTempCertificate(dbHandle, &derCert, nullptr, false, true)); - if (!cert) { - return false; - } - UniqueSECKEYPublicKey key(CERT_ExtractPublicKey(cert.get())); - if (!key) { - return false; - } - SECItem signatureItem = {siBuffer, const_cast(aSignature), - static_cast(aSignatureLen)}; - rv = PK11_VerifyWithMechanism(key.get(), mechanism, ¶m, &signatureItem, - &hashItem, nullptr); - if (rv != SECSuccess) { - return false; - } - - // Load intermediate certs into NSS so we can verify the cert chain. - UniqueCERTCertList tempCerts(CERT_NewCertList()); - for (size_t i = 0; i < aCertChainLen; ++i) { - SECItem derCert = {siBuffer, const_cast(aCertChain[i]), - static_cast(aCertsLen[i])}; - UniqueCERTCertificate tempCert( - CERT_NewTempCertificate(dbHandle, &derCert, nullptr, false, true)); - // Skip certs that we can't parse. If it was one we needed, the verification - // will fail later. - if (!tempCert) { - continue; - } - if (CERT_AddCertToListTail(tempCerts.get(), tempCert.get()) != SECSuccess) { - return false; - } - Unused << tempCert.release(); - } - - UniqueCERTCertList builtChain; - nsresult nrv = VerifyCertificate(cert.get(), aTrustedRoot, builtChain); - bool result = true; - if (NS_FAILED(nrv)) { - result = false; - } - - // Passing back the signing certificate in form of the DER cert. - nrv = context->SetCert(&cert->derCert); - if (NS_FAILED(nrv)) { - result = false; - } - - return result; -} - -nsresult VerifyAppManifest(SECOidTag aDigestToUse, nsCOMPtr aZip, - nsTHashtable& aIgnoredFiles, - const SECItem& aManifestBuffer) { - // 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 items; - - nsresult rv = - ParseMF(BitwiseCast(aManifestBuffer.data), aZip, - aDigestToUse, items, buf); - if (NS_FAILED(rv)) { - return rv; - } - - // Verify every entry in the file. - nsCOMPtr entries; - rv = aZip->FindEntries(EmptyCString(), getter_AddRefs(entries)); - if (NS_FAILED(rv)) { - return rv; - } - if (!entries) { - return NS_ERROR_UNEXPECTED; - } - - 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())); - - if (entryFilename.Length() == 0) { - return NS_ERROR_SIGNED_JAR_ENTRY_INVALID; - } - - // The files that comprise the signature mechanism are not covered by the - // signature. Ignore these files. - if (aIgnoredFiles.Contains(entryFilename)) { - continue; - } - - // Entries with names that end in "/" are directory entries, which are not - // signed. - // - // Since bug 1415991 we don't support unpacked JARs. The "/" entries are - // therefore harmless. - if (entryFilename.Last() == '/') { - 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 NS_OK; -} - -// This corresponds to the preference "security.signed_app_signatures.policy". -// The lowest order bit determines which PKCS#7 algorithms are accepted. -// xxx_0_: SHA-1 and/or SHA-256 PKCS#7 allowed -// xxx_1_: SHA-256 PKCS#7 allowed -// The next two bits determine whether COSE is required and PKCS#7 is allowed -// x_00_x: COSE disabled, ignore files, PKCS#7 must verify -// x_01_x: COSE is verified if present, PKCS#7 must verify -// x_10_x: COSE is required, PKCS#7 must verify if present -// x_11_x: COSE is required, PKCS#7 disabled (fail when present) -class SignaturePolicy { - public: - explicit SignaturePolicy(int32_t preference) - : mProcessCose(true), - mCoseRequired(false), - mProcessPK7(true), - mPK7Required(true), - mSHA1Allowed(true), - mSHA256Allowed(true) { - mCoseRequired = (preference & 0b100) != 0; - mProcessCose = (preference & 0b110) != 0; - mPK7Required = (preference & 0b100) == 0; - mProcessPK7 = (preference & 0b110) != 0b110; - if ((preference & 0b1) == 0) { - mSHA1Allowed = true; - mSHA256Allowed = true; - } else { - mSHA1Allowed = false; - mSHA256Allowed = true; - } - } - ~SignaturePolicy() {} - bool ProcessCOSE() { return mProcessCose; } - bool COSERequired() { return mCoseRequired; } - bool PK7Required() { return mPK7Required; } - bool ProcessPK7() { return mProcessPK7; } - bool IsPK7HashAllowed(SECOidTag aHashAlg) { - if (aHashAlg == SEC_OID_SHA256 && mSHA256Allowed) { - return true; - } - if (aHashAlg == SEC_OID_SHA1 && mSHA1Allowed) { - return true; - } - return false; - } - - private: - bool mProcessCose; - bool mCoseRequired; - bool mProcessPK7; - bool mPK7Required; - bool mSHA1Allowed; - bool mSHA256Allowed; -}; - -nsresult VerifyCOSESignature(AppTrustedRoot aTrustedRoot, nsIZipReader* aZip, - SignaturePolicy& aPolicy, - nsTHashtable& aIgnoredFiles, - /* out */ bool& aVerified, - /* out */ UniqueSECItem* aCoseCertItem) { - NS_ENSURE_ARG_POINTER(aZip); - NS_ENSURE_ARG_POINTER(aCoseCertItem); - bool required = aPolicy.COSERequired(); - aVerified = false; - - // Read COSE signature file. - nsAutoCString coseFilename; - ScopedAutoSECItem coseBuffer; - nsresult rv = - FindAndLoadOneEntry(aZip, NS_LITERAL_CSTRING(JAR_COSE_SEARCH_STRING), - coseFilename, coseBuffer); - if (NS_FAILED(rv)) { - return required ? NS_ERROR_SIGNED_JAR_WRONG_SIGNATURE : NS_OK; - } - - // Verify COSE signature. - nsAutoCString mfFilename; - ScopedAutoSECItem manifestBuffer; - rv = FindAndLoadOneEntry(aZip, NS_LITERAL_CSTRING(JAR_COSE_MF_SEARCH_STRING), - mfFilename, manifestBuffer); - if (NS_FAILED(rv)) { - return required ? NS_ERROR_SIGNED_JAR_WRONG_SIGNATURE : rv; - } - MOZ_ASSERT(manifestBuffer.len >= 1); - MOZ_ASSERT(coseBuffer.len >= 1); - CoseVerificationContext context(aTrustedRoot); - bool coseVerification = verify_cose_signature_ffi( - manifestBuffer.data, manifestBuffer.len - 1, coseBuffer.data, - coseBuffer.len - 1, &context, CoseVerificationCallback); - if (!coseVerification) { - return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID; - } - // CoseVerificationCallback sets the context certificate to the first cert - // it encounters. - const SECItem derCert = {siBuffer, context.GetCert(), context.GetCertLen()}; - aCoseCertItem->reset(SECITEM_DupItem(&derCert)); - if (!aCoseCertItem) { - return NS_ERROR_FAILURE; - } - - // aIgnoredFiles contains the PKCS#7 manifest and signature files iff the - // PKCS#7 verification was successful. - aIgnoredFiles.PutEntry(mfFilename); - aIgnoredFiles.PutEntry(coseFilename); - rv = VerifyAppManifest(SEC_OID_SHA256, aZip, aIgnoredFiles, manifestBuffer); - if (NS_FAILED(rv)) { - return rv; - } - - aVerified = true; - return NS_OK; -} - -nsresult VerifyPK7Signature( - AppTrustedRoot aTrustedRoot, nsIZipReader* aZip, SignaturePolicy& aPolicy, - /* out */ nsTHashtable& aIgnoredFiles, - /* out */ bool& aVerified, - /* out */ UniqueCERTCertList& aBuiltChain) { - NS_ENSURE_ARG_POINTER(aZip); - bool required = aPolicy.PK7Required(); - aVerified = false; - - // Signature (RSA) file - nsAutoCString sigFilename; - ScopedAutoSECItem sigBuffer; - nsresult rv = FindAndLoadOneEntry( - aZip, nsLiteralCString(JAR_RSA_SEARCH_STRING), sigFilename, sigBuffer); - if (NS_FAILED(rv)) { - return required ? NS_ERROR_SIGNED_JAR_NOT_SIGNED : NS_OK; - } - - // Signature (SF) file - nsAutoCString sfFilename; - ScopedAutoSECItem sfBuffer; - rv = FindAndLoadOneEntry(aZip, NS_LITERAL_CSTRING(JAR_SF_SEARCH_STRING), - sfFilename, sfBuffer); - if (NS_FAILED(rv)) { - return required ? NS_ERROR_SIGNED_JAR_MANIFEST_INVALID : NS_OK; - } - - // Calculate both the SHA-1 and SHA-256 hashes of the signature file - we - // don't know what algorithm the PKCS#7 signature used. - Digest sfCalculatedSHA1Digest; - rv = sfCalculatedSHA1Digest.DigestBuf(SEC_OID_SHA1, sfBuffer.data, - sfBuffer.len - 1); - if (NS_FAILED(rv)) { - return rv; - } - Digest sfCalculatedSHA256Digest; - rv = sfCalculatedSHA256Digest.DigestBuf(SEC_OID_SHA256, sfBuffer.data, - sfBuffer.len - 1); - if (NS_FAILED(rv)) { - return rv; - } - - // Verify PKCS#7 signature. - // If we get here, the signature has to verify even if PKCS#7 is not required. - sigBuffer.type = siBuffer; - SECOidTag digestToUse; - rv = - VerifySignature(aTrustedRoot, sigBuffer, sfCalculatedSHA1Digest.get(), - sfCalculatedSHA256Digest.get(), digestToUse, aBuiltChain); - if (NS_FAILED(rv)) { - return rv; - } - - // Check the digest used for the signature against the policy. - if (!aPolicy.IsPK7HashAllowed(digestToUse)) { - return NS_ERROR_SIGNED_JAR_WRONG_SIGNATURE; - } - - nsAutoCString mfDigest; - rv = ParseSF(BitwiseCast(sfBuffer.data), digestToUse, - mfDigest); - if (NS_FAILED(rv)) { - return rv; - } - - // Read PK7 manifest (MF) file. - ScopedAutoSECItem manifestBuffer; - Digest mfCalculatedDigest; - nsAutoCString mfFilename; - rv = FindAndLoadOneEntry(aZip, NS_LITERAL_CSTRING(JAR_MF_SEARCH_STRING), - mfFilename, manifestBuffer, digestToUse, - &mfCalculatedDigest); - if (NS_FAILED(rv)) { - return rv; - } - - nsDependentCSubstring calculatedDigest( - DigestToDependentString(mfCalculatedDigest)); - if (!mfDigest.Equals(calculatedDigest)) { - return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID; - } - - // Verify PKCS7 manifest file hashes. - aIgnoredFiles.PutEntry(sfFilename); - aIgnoredFiles.PutEntry(sigFilename); - aIgnoredFiles.PutEntry(mfFilename); - rv = VerifyAppManifest(digestToUse, aZip, aIgnoredFiles, manifestBuffer); - if (NS_FAILED(rv)) { - aIgnoredFiles.Clear(); - return rv; - } - - aVerified = true; - return NS_OK; -} - -nsresult OpenSignedAppFile(AppTrustedRoot aTrustedRoot, nsIFile* aJarFile, - SignaturePolicy aPolicy, - /* 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 zip = do_CreateInstance(kZipReaderCID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - rv = zip->Open(aJarFile); - NS_ENSURE_SUCCESS(rv, rv); - - bool pk7Verified = false; - bool coseVerified = false; - nsTHashtable ignoredFiles; - UniqueCERTCertList pk7BuiltChain; - UniqueSECItem coseCertItem; - - // First we have to verify the PKCS#7 signature if there is one. - // This signature covers all files (except for the signature files itself), - // including the COSE signature files. Only when this verification is - // successful the respective files will be ignored in the subsequent COSE - // signature verification. - if (aPolicy.ProcessPK7()) { - rv = VerifyPK7Signature(aTrustedRoot, zip, aPolicy, ignoredFiles, - pk7Verified, pk7BuiltChain); - if (NS_FAILED(rv)) { - return rv; - } - } - - if (aPolicy.ProcessCOSE()) { - rv = VerifyCOSESignature(aTrustedRoot, zip, aPolicy, ignoredFiles, - coseVerified, &coseCertItem); - if (NS_FAILED(rv)) { - return rv; - } - } - - if ((aPolicy.PK7Required() && !pk7Verified) || - (aPolicy.COSERequired() && !coseVerified)) { - return NS_ERROR_SIGNED_JAR_WRONG_SIGNATURE; - } - - // 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. - if (aSignerCert) { - // The COSE certificate is authoritative. - if (aPolicy.COSERequired() || (coseCertItem && coseCertItem->len != 0)) { - if (!coseCertItem || coseCertItem->len == 0) { - return NS_ERROR_FAILURE; - } - CERTCertDBHandle* dbHandle = CERT_GetDefaultCertDB(); - if (!dbHandle) { - return NS_ERROR_FAILURE; - } - UniqueCERTCertificate cert(CERT_NewTempCertificate( - dbHandle, coseCertItem.get(), nullptr, false, true)); - if (!cert) { - return NS_ERROR_FAILURE; - } - nsCOMPtr signerCert = nsNSSCertificate::Create(cert.get()); - if (!signerCert) { - return NS_ERROR_OUT_OF_MEMORY; - } - signerCert.forget(aSignerCert); - } else { - CERTCertListNode* signerCertNode = CERT_LIST_HEAD(pk7BuiltChain); - if (!signerCertNode || CERT_LIST_END(signerCertNode, pk7BuiltChain) || - !signerCertNode->cert) { - return NS_ERROR_FAILURE; - } - nsCOMPtr signerCert = - nsNSSCertificate::Create(signerCertNode->cert); - NS_ENSURE_TRUE(signerCert, NS_ERROR_OUT_OF_MEMORY); - signerCert.forget(aSignerCert); - } - } - - return NS_OK; -} - -class OpenSignedAppFileTask final : public CryptoTask { - public: - OpenSignedAppFileTask(AppTrustedRoot aTrustedRoot, nsIFile* aJarFile, - SignaturePolicy aPolicy, - nsIOpenSignedAppFileCallback* aCallback) - : mTrustedRoot(aTrustedRoot), - mJarFile(aJarFile), - mPolicy(aPolicy), - mCallback(new nsMainThreadPtrHolder( - "OpenSignedAppFileTask::mCallback", aCallback)) {} - - private: - virtual nsresult CalculateResult() override { - return OpenSignedAppFile(mTrustedRoot, mJarFile, mPolicy, - getter_AddRefs(mZipReader), - getter_AddRefs(mSignerCert)); - } - - virtual void CallCallback(nsresult rv) override { - (void)mCallback->OpenSignedAppFileFinished(rv, mZipReader, mSignerCert); - } - - const AppTrustedRoot mTrustedRoot; - const nsCOMPtr mJarFile; - const SignaturePolicy mPolicy; - nsMainThreadPtrHandle mCallback; - nsCOMPtr mZipReader; // out - nsCOMPtr mSignerCert; // out -}; - -static const int32_t sDefaultSignaturePolicy = 0b10; - -} // unnamed namespace - -NS_IMETHODIMP -nsNSSCertificateDB::OpenSignedAppFileAsync( - AppTrustedRoot aTrustedRoot, nsIFile* aJarFile, - nsIOpenSignedAppFileCallback* aCallback) { - NS_ENSURE_ARG_POINTER(aJarFile); - NS_ENSURE_ARG_POINTER(aCallback); - if (!NS_IsMainThread()) { - return NS_ERROR_NOT_SAME_THREAD; - } - int32_t policyInt = - Preferences::GetInt("security.signed_app_signatures.policy", - static_cast(sDefaultSignaturePolicy)); - SignaturePolicy policy(policyInt); - RefPtr task( - new OpenSignedAppFileTask(aTrustedRoot, aJarFile, policy, aCallback)); - return task->Dispatch(); -} diff --git a/security/apps/AppTrustDomain.cpp b/security/apps/AppTrustDomain.cpp deleted file mode 100644 index 86c11e6b5a..0000000000 --- a/security/apps/AppTrustDomain.cpp +++ /dev/null @@ -1,327 +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/. */ - -#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 "mozpkix/pkixnss.h" -#include "prerror.h" - -// Generated by gen_cert_header.py, which gets called by the build system. -#include "xpcshell.inc" -// Add-on signing Certificates -#include "addons-public.inc" -#include "addons-public-intermediate.inc" -#include "addons-stage.inc" -// Privileged Package Certificates -#include "privileged-package-root.inc" - -using namespace mozilla::pkix; - -extern mozilla::LazyLogModule gPIPNSSLog; - -static char kDevImportedDER[] = "network.http.signed-packages.developer-root"; - -namespace mozilla { -namespace psm { - -StaticMutex AppTrustDomain::sMutex; -UniquePtr AppTrustDomain::sDevImportedDERData; -unsigned int AppTrustDomain::sDevImportedDERLen = 0; - -AppTrustDomain::AppTrustDomain(UniqueCERTCertList& certChain, void* pinArg) - : mCertChain(certChain), mPinArg(pinArg) {} - -nsresult 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::AppXPCShellRoot: - trustedDER.data = const_cast(xpcshellRoot); - trustedDER.len = mozilla::ArrayLength(xpcshellRoot); - break; - - case nsIX509CertDB::AddonsPublicRoot: - trustedDER.data = const_cast(addonsPublicRoot); - trustedDER.len = mozilla::ArrayLength(addonsPublicRoot); - break; - - case nsIX509CertDB::AddonsStageRoot: - trustedDER.data = const_cast(addonsStageRoot); - trustedDER.len = mozilla::ArrayLength(addonsStageRoot); - break; - - case nsIX509CertDB::PrivilegedPackageRoot: - trustedDER.data = const_cast(privilegedPackageRoot); - trustedDER.len = mozilla::ArrayLength(privilegedPackageRoot); - break; - - case nsIX509CertDB::DeveloperImportedRoot: { - StaticMutexAutoLock lock(sMutex); - if (!sDevImportedDERData) { - MOZ_ASSERT(!NS_IsMainThread()); - nsCOMPtr file(do_CreateInstance("@mozilla.org/file/local;1")); - if (!file) { - return NS_ERROR_FAILURE; - } - nsAutoCString path; - Preferences::GetCString(kDevImportedDER, path); - nsresult rv = file->InitWithNativePath(path); - if (NS_FAILED(rv)) { - return rv; - } - - nsCOMPtr inputStream; - rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), file, -1, - -1, nsIFileInputStream::CLOSE_ON_EOF); - if (NS_FAILED(rv)) { - return rv; - } - - uint64_t length; - rv = inputStream->Available(&length); - if (NS_FAILED(rv)) { - return rv; - } - - auto data = MakeUnique(length); - rv = inputStream->Read(data.get(), length, &sDevImportedDERLen); - if (NS_FAILED(rv)) { - return rv; - } - - MOZ_ASSERT(length == sDevImportedDERLen); - sDevImportedDERData.reset( - BitwiseCast(data.release())); - } - - trustedDER.data = sDevImportedDERData.get(); - trustedDER.len = sDevImportedDERLen; - break; - } - - default: - return NS_ERROR_INVALID_ARG; - } - - mTrustedRoot.reset(CERT_NewTempCertificate( - CERT_GetDefaultCertDB(), &trustedDER, nullptr, false, true)); - if (!mTrustedRoot) { - return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); - } - - // If we're verifying add-ons signed by our production root, we want to make - // sure a valid intermediate certificate is available for path building. - // Merely holding this alive in memory makes it available for NSS to find in - // AppTrustDomain::FindIssuer. - if (trustedRoot == nsIX509CertDB::AddonsPublicRoot) { - SECItem intermediateDER = { - siBuffer, - const_cast(addonsPublicIntermediate), - static_cast( - mozilla::ArrayLength(addonsPublicIntermediate)), - }; - mAddonsIntermediate.reset(CERT_NewTempCertificate( - CERT_GetDefaultCertDB(), &intermediateDER, nullptr, false, true)); - if (!mAddonsIntermediate) { - return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); - } - } - - return NS_OK; -} - -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*) { - // 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) { - MOZ_ASSERT(requiredPolicy.IsAnyPolicy()); - 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 < 2048u) { - 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 psm -} // namespace mozilla diff --git a/security/apps/AppTrustDomain.h b/security/apps/AppTrustDomain.h deleted file mode 100644 index efdd9ddf27..0000000000 --- a/security/apps/AppTrustDomain.h +++ /dev/null @@ -1,87 +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/. */ - -#ifndef AppTrustDomain_h -#define AppTrustDomain_h - -#include "mozpkix/pkixtypes.h" -#include "mozilla/StaticMutex.h" -#include "mozilla/UniquePtr.h" -#include "nsDebug.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); - - nsresult 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) 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; - UniqueCERTCertificate mAddonsIntermediate; - - static StaticMutex sMutex; - static UniquePtr sDevImportedDERData; - static unsigned int sDevImportedDERLen; -}; - -} // namespace psm -} // namespace mozilla - -#endif // AppTrustDomain_h diff --git a/security/apps/addons-public-intermediate.crt b/security/apps/addons-public-intermediate.crt deleted file mode 100644 index d37979bf38..0000000000 Binary files a/security/apps/addons-public-intermediate.crt and /dev/null differ diff --git a/security/apps/addons-public.crt b/security/apps/addons-public.crt deleted file mode 100644 index 6ab711b996..0000000000 Binary files a/security/apps/addons-public.crt and /dev/null differ diff --git a/security/apps/addons-stage.crt b/security/apps/addons-stage.crt deleted file mode 100644 index 73e48cadfe..0000000000 Binary files a/security/apps/addons-stage.crt and /dev/null differ diff --git a/security/apps/gen_cert_header.py b/security/apps/gen_cert_header.py deleted file mode 100644 index 3dab4b3f86..0000000000 --- a/security/apps/gen_cert_header.py +++ /dev/null @@ -1,43 +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 = [ - 'xpcshellRoot', - 'addonsPublicRoot', - 'addonsPublicIntermediate', - '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/moz.build b/security/apps/moz.build deleted file mode 100644 index da6fecb3dc..0000000000 --- a/security/apps/moz.build +++ /dev/null @@ -1,49 +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/. - -with Files("**"): - BUG_COMPONENT = ("Core", "Security: PSM") - -UNIFIED_SOURCES += [ - 'AppSignatureVerification.cpp', - 'AppTrustDomain.cpp', -] - -include('/ipc/chromium/chromium-config.mozbuild') - -FINAL_LIBRARY = 'xul' - -LOCAL_INCLUDES += [ - '/security/certverifier', - '/security/manager/ssl', - '/third_party/rust/cose-c/include', -] - -DEFINES['NSS_ENABLE_ECC'] = 'True' -for var in ('DLL_PREFIX', 'DLL_SUFFIX'): - DEFINES[var] = '"%s"' % CONFIG[var] - -if CONFIG['CC_TYPE'] in ('clang', 'gcc'): - CXXFLAGS += [ - '-Wextra', - ] - - # Gecko headers aren't warning-free enough for us to enable these warnings. - CXXFLAGS += [ - '-Wno-unused-parameter', - ] - -test_ssl_path = '/security/manager/ssl/tests/unit' - -headers_arrays_certs = [ - ('xpcshell.inc', 'xpcshellRoot', test_ssl_path + '/test_signed_apps/xpcshellTestRoot.der'), - ('addons-public.inc', 'addonsPublicRoot', 'addons-public.crt'), - ('addons-public-intermediate.inc', 'addonsPublicIntermediate', 'addons-public-intermediate.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: - GeneratedFile(header, script='gen_cert_header.py', - entry_point=array_name, 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 Binary files a/security/apps/privileged-package-root.der and /dev/null differ diff --git a/security/certverifier/NSSCertDBTrustDomain.cpp b/security/certverifier/NSSCertDBTrustDomain.cpp index 1211865185..986772182a 100644 --- a/security/certverifier/NSSCertDBTrustDomain.cpp +++ b/security/certverifier/NSSCertDBTrustDomain.cpp @@ -568,7 +568,7 @@ static Result GetOCSPAuthorityInfoAccessLocation(const UniquePLArenaPool& arena, Result NSSCertDBTrustDomain::CheckRevocation( EndEntityOrCA endEntityOrCA, const CertID& certID, Time time, - Duration validityDuration, + Time validityPeriodBeginning, Duration validityDuration, /*optional*/ const Input* stapledOCSPResponse, /*optional*/ const Input* aiaExtension) { // Actively distrusted certificates will have already been blocked by diff --git a/security/certverifier/NSSCertDBTrustDomain.h b/security/certverifier/NSSCertDBTrustDomain.h index 2a37b2485a..3673f4d9d3 100644 --- a/security/certverifier/NSSCertDBTrustDomain.h +++ b/security/certverifier/NSSCertDBTrustDomain.h @@ -204,6 +204,7 @@ class NSSCertDBTrustDomain : public mozilla::pkix::TrustDomain { virtual Result CheckRevocation( mozilla::pkix::EndEntityOrCA endEntityOrCA, const mozilla::pkix::CertID& certID, mozilla::pkix::Time time, + mozilla::pkix::Time validityPeriodBeginning, mozilla::pkix::Duration validityDuration, /*optional*/ const mozilla::pkix::Input* stapledOCSPResponse, /*optional*/ const mozilla::pkix::Input* aiaExtension) override; diff --git a/security/certverifier/OCSPVerificationTrustDomain.cpp b/security/certverifier/OCSPVerificationTrustDomain.cpp index 77fa49277e..f6726ab453 100644 --- a/security/certverifier/OCSPVerificationTrustDomain.cpp +++ b/security/certverifier/OCSPVerificationTrustDomain.cpp @@ -34,7 +34,7 @@ Result OCSPVerificationTrustDomain::IsChainValid(const DERArray&, Time, } Result OCSPVerificationTrustDomain::CheckRevocation(EndEntityOrCA, - const CertID&, Time, + const CertID&, Time, Time, Duration, const Input*, const Input*) { // We do not expect this to be called for OCSP signers diff --git a/security/certverifier/OCSPVerificationTrustDomain.h b/security/certverifier/OCSPVerificationTrustDomain.h index fc7c5eb112..95efec5048 100644 --- a/security/certverifier/OCSPVerificationTrustDomain.h +++ b/security/certverifier/OCSPVerificationTrustDomain.h @@ -65,6 +65,7 @@ class OCSPVerificationTrustDomain : public mozilla::pkix::TrustDomain { virtual Result CheckRevocation( mozilla::pkix::EndEntityOrCA endEntityOrCA, const mozilla::pkix::CertID& certID, mozilla::pkix::Time time, + mozilla::pkix::Time validityPeriodBeginning, mozilla::pkix::Duration validityDuration, /*optional*/ const mozilla::pkix::Input* stapledOCSPResponse, /*optional*/ const mozilla::pkix::Input* aiaExtension) override; diff --git a/security/ct/CTLogVerifier.cpp b/security/ct/CTLogVerifier.cpp index 5616d8a5eb..d5b4b68db2 100644 --- a/security/ct/CTLogVerifier.cpp +++ b/security/ct/CTLogVerifier.cpp @@ -36,7 +36,7 @@ class SignatureParamsTrustDomain final : public TrustDomain { return Result::FATAL_ERROR_LIBRARY_FAILURE; } - Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration, + Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Time, Duration, const Input*, const Input*) override { return Result::FATAL_ERROR_LIBRARY_FAILURE; } diff --git a/security/ct/tests/gtest/CTTestUtils.cpp b/security/ct/tests/gtest/CTTestUtils.cpp index 70e63f2c2e..b40e9ee05b 100644 --- a/security/ct/tests/gtest/CTTestUtils.cpp +++ b/security/ct/tests/gtest/CTTestUtils.cpp @@ -673,8 +673,8 @@ class OCSPExtensionTrustDomain : public TrustDomain { return pkix::Result::FATAL_ERROR_LIBRARY_FAILURE; } - pkix::Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration, - const Input*, const Input*) override { + pkix::Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Time, + Duration, const Input*, const Input*) override { ADD_FAILURE(); return pkix::Result::FATAL_ERROR_LIBRARY_FAILURE; } diff --git a/security/manager/locales/en-US/chrome/pippki/pippki.dtd b/security/manager/locales/en-US/chrome/pippki/pippki.dtd index 3ae167d64e..5ab475f49e 100644 --- a/security/manager/locales/en-US/chrome/pippki/pippki.dtd +++ b/security/manager/locales/en-US/chrome/pippki/pippki.dtd @@ -2,7 +2,7 @@ - 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/. --> - + @@ -10,7 +10,7 @@ - + diff --git a/security/manager/locales/en-US/chrome/pippki/pippki.properties b/security/manager/locales/en-US/chrome/pippki/pippki.properties index 699efbceda..d07f1ffd56 100644 --- a/security/manager/locales/en-US/chrome/pippki/pippki.properties +++ b/security/manager/locales/en-US/chrome/pippki/pippki.properties @@ -80,7 +80,6 @@ pw_not_wanted=Warning! You have decided not to use a Master Password. pw_empty_warning=Your stored web and email passwords, form data, and private keys will not be protected. pw_change2empty_in_fips_mode=You are currently in FIPS mode. FIPS requires a non-empty Master Password. enable_fips=Enable FIPS -disable_fips=Disable FIPS resetPasswordConfirmationTitle=Reset Master Password resetPasswordConfirmationMessage=Your password has been reset. diff --git a/security/manager/pki/nsNSSDialogs.cpp b/security/manager/pki/nsNSSDialogs.cpp index 133329978e..6b426de00d 100644 --- a/security/manager/pki/nsNSSDialogs.cpp +++ b/security/manager/pki/nsNSSDialogs.cpp @@ -77,7 +77,7 @@ nsNSSDialogs::SetPassword(nsIInterfaceRequestor* ctx, nsIPK11Token* token, } rv = nsNSSDialogHelper::openDialog( - parent, "chrome://pippki/content/changepassword.xul", block); + parent, "chrome://pippki/content/changepassword.xhtml", block); if (NS_FAILED(rv)) return rv; @@ -120,7 +120,7 @@ nsNSSDialogs::ConfirmDownloadCACert(nsIInterfaceRequestor* ctx, // Get the parent window for the dialog nsCOMPtr parent = do_GetInterface(ctx); rv = nsNSSDialogHelper::openDialog( - parent, "chrome://pippki/content/downloadcert.xul", argArray); + parent, "chrome://pippki/content/downloadcert.xhtml", argArray); if (NS_FAILED(rv)) { return rv; } @@ -227,7 +227,7 @@ nsNSSDialogs::ChooseCertificate(const nsACString& hostname, int32_t port, } rv = nsNSSDialogHelper::openDialog( - nullptr, "chrome://pippki/content/clientauthask.xul", argArray); + nullptr, "chrome://pippki/content/clientauthask.xhtml", argArray); if (NS_FAILED(rv)) { return rv; } @@ -265,7 +265,7 @@ nsNSSDialogs::SetPKCS12FilePassword(nsIInterfaceRequestor* ctx, nsCOMPtr parent = do_GetInterface(ctx); nsCOMPtr retVals = new nsHashPropertyBag(); nsresult rv = nsNSSDialogHelper::openDialog( - parent, "chrome://pippki/content/setp12password.xul", retVals); + parent, "chrome://pippki/content/setp12password.xhtml", retVals); if (NS_FAILED(rv)) { return rv; } @@ -342,7 +342,7 @@ nsNSSDialogs::DisplayProtectedAuth(nsIInterfaceRequestor* aCtx, nsCOMPtr newWindow; rv = windowWatcher->OpenWindow( - parent, "chrome://pippki/content/protectedAuth.xul", "_blank", + parent, "chrome://pippki/content/protectedAuth.xhtml", "_blank", "centerscreen,chrome,modal,titlebar,close=no", runnable, getter_AddRefs(newWindow)); diff --git a/security/manager/pki/resources/content/certManager.js b/security/manager/pki/resources/content/certManager.js index 49a0916b20..99db3b583b 100644 --- a/security/manager/pki/resources/content/certManager.js +++ b/security/manager/pki/resources/content/certManager.js @@ -333,7 +333,7 @@ function editCerts() { for (let cert of selected_certs) { window.openDialog( - "chrome://pippki/content/editcacert.xul", + "chrome://pippki/content/editcacert.xhtml", "", "chrome,centerscreen,modal", cert @@ -461,7 +461,7 @@ function deleteCerts() { deleteConfirmed: false, }; window.openDialog( - "chrome://pippki/content/deletecert.xul", + "chrome://pippki/content/deletecert.xhtml", "", "chrome,centerscreen,modal", selTabID, @@ -534,7 +534,7 @@ async function addEmailCert() { function addException() { window.openDialog( - "chrome://pippki/content/exceptionDialog.xul", + "chrome://pippki/content/exceptionDialog.xhtml", "", "chrome,centerscreen,modal" ); diff --git a/security/manager/pki/resources/content/certManager.xul b/security/manager/pki/resources/content/certManager.xhtml similarity index 81% rename from security/manager/pki/resources/content/certManager.xul rename to security/manager/pki/resources/content/certManager.xhtml index bc2f810d4c..b4353ac0d3 100644 --- a/security/manager/pki/resources/content/certManager.xul +++ b/security/manager/pki/resources/content/certManager.xhtml @@ -5,17 +5,17 @@ - + - + @@ -39,6 +39,15 @@ + @@ -118,6 +127,15 @@ + @@ -156,6 +174,15 @@ + @@ -191,3 +218,4 @@ + diff --git a/security/manager/pki/resources/content/certViewer.js b/security/manager/pki/resources/content/certViewer.js index bb01859025..086aaf08ae 100644 --- a/security/manager/pki/resources/content/certViewer.js +++ b/security/manager/pki/resources/content/certViewer.js @@ -6,7 +6,7 @@ "use strict"; /** - * @file Implements functionality for certViewer.xul and its general and details + * @file Implements functionality for certViewer.xhtml and its general and details * tabs. * @argument {nsISupports} window.arguments[0] * The cert to view, queryable to nsIX509Cert. @@ -46,11 +46,11 @@ function AddCertChain(node, chain) { */ function AddUsage(l10nId) { let verifyInfoBox = document.getElementById("verify_info_box"); - let text = document.createXULElement("textbox"); + let text = document.createElementNS("http://www.w3.org/1999/xhtml", "input"); document.l10n.setAttributes(text, l10nId); text.setAttribute("data-l10n-attrs", "value"); text.setAttribute("style", "margin: 2px 5px"); - text.setAttribute("readonly", "true"); + text.setAttribute("readonly", "readonly"); text.setAttribute("class", "scrollfield"); verifyInfoBox.appendChild(text); } diff --git a/security/manager/pki/resources/content/certViewer.xul b/security/manager/pki/resources/content/certViewer.xhtml similarity index 82% rename from security/manager/pki/resources/content/certViewer.xul rename to security/manager/pki/resources/content/certViewer.xhtml index 055c5035a6..038196cc78 100644 --- a/security/manager/pki/resources/content/certViewer.xul +++ b/security/manager/pki/resources/content/certViewer.xhtml @@ -5,16 +5,19 @@ - + - + @@ -29,16 +32,24 @@ table { border-spacing: 0.5ch 2px; } - td > textbox { + td > input { width: 100%; } th { - vertical-align: top; + vertical-align: middle; text-align: start; } th[scope="row"] { font-weight: normal; } + input:-moz-read-only, + textarea:-moz-read-only { + background: none; + border: none; + width: 100%; + padding-block: 0; + margin-inline: 0; + } @@ -59,19 +70,19 @@ - + - + - + - + @@ -81,15 +92,15 @@ - + - + - + @@ -99,11 +110,11 @@ - + - + @@ -114,13 +125,13 @@ -