--- a/security/apps/AppSignatureVerification.cpp
+++ b/security/apps/AppSignatureVerification.cpp
@@ -5,52 +5,61 @@
* 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/Base64.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 "nsDependentString.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 {
+// The digest must have a lifetime greater than or equal to the returned string.
+inline nsDependentCSubstring
+DigestToDependentString(const Digest& digest)
+{
+ return nsDependentCSubstring(
+ BitwiseCast<char*, unsigned char*>(digest.get().data),
+ digest.get().len);
+}
+
// 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.
@@ -159,21 +168,22 @@ FindAndLoadOneEntry(nsIZipReader * zip,
// 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)
+ const nsCString& digestFromManifest, SECItem& buf)
{
MOZ_ASSERT(buf.len > 0);
- if (digestFromManifest.len != SHA1_LENGTH)
+ if (digestFromManifest.Length() != 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;
}
@@ -212,26 +222,27 @@ VerifyStreamContentDigest(nsIInputStream
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) {
+ nsDependentCSubstring digestStr(DigestToDependentString(digest));
+ if (!digestStr.Equals(digestFromManifest)) {
return NS_ERROR_SIGNED_JAR_MODIFIED_ENTRY;
}
return NS_OK;
}
nsresult
VerifyEntryContentDigest(nsIZipReader* zip, const nsACString& aFilename,
- const SECItem& digestFromManifest, SECItem& buf)
+ const nsCString& 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);
@@ -239,17 +250,17 @@ VerifyEntryContentDigest(nsIZipReader* z
// @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)
+ const nsCString& 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;
}
@@ -435,24 +446,24 @@ CheckManifestVersion(const char* & nextL
// 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)
+ParseSF(const char* filebuf, /*out*/ nsCString& mfDigest)
{
- nsresult rv;
-
const char* nextLineStart = filebuf;
- rv = CheckManifestVersion(nextLineStart, NS_LITERAL_CSTRING(JAR_SF_HEADER));
- if (NS_FAILED(rv))
+ nsresult 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;
}
@@ -466,17 +477,17 @@ ParseSF(const char* filebuf, /*out*/ SEC
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()));
+ rv = Base64Decode(attrValue, mfDigest);
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:
//
@@ -522,33 +533,33 @@ ParseMF(const char* filebuf, nsIZipReade
// Manifest containing no file entries is OK, though useless.
if (*nextLineStart == '\0') {
return NS_OK;
}
}
nsAutoCString curItemName;
- ScopedAutoSECItem digest;
+ nsAutoCString 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) {
+ 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;
@@ -563,39 +574,41 @@ ParseMF(const char* filebuf, nsIZipReade
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();
+ 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.LowerCaseEqualsLiteral("sha1-digest"))
{
- if (digest.len > 0) // multiple SHA1 digests in section
+ if (!digest.IsEmpty()) { // multiple SHA1 digests in section
return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
+ }
- rv = MapSECStatus(ATOB_ConvertAsciiToItem(&digest, attrValue.get()));
- if (NS_FAILED(rv))
+ 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
@@ -749,33 +762,35 @@ OpenSignedAppFile(AppTrustedRoot aTruste
sigBuffer.type = siBuffer;
UniqueCERTCertList builtChain;
rv = VerifySignature(aTrustedRoot, sigBuffer, sfCalculatedDigest.get(),
builtChain);
if (NS_FAILED(rv)) {
return rv;
}
- ScopedAutoSECItem mfDigest;
+ nsAutoCString 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) {
+ nsDependentCSubstring calculatedDigest(
+ DigestToDependentString(mfCalculatedDigest));
+ if (!mfDigest.Equals(calculatedDigest)) {
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);
@@ -1045,17 +1060,17 @@ ParseMFUnpacked(const char* aFilebuf, ns
// Manifest containing no file entries is OK, though useless.
if (*nextLineStart == '\0') {
return NS_OK;
}
}
nsAutoString curItemName;
- ScopedAutoSECItem digest;
+ nsAutoCString digest;
for (;;) {
nsAutoCString curLine;
rv = ReadLine(nextLineStart, curLine);
if (NS_FAILED(rv)) {
return rv;
}
@@ -1063,17 +1078,17 @@ ParseMFUnpacked(const char* aFilebuf, ns
// 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) {
+ 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 (aMfItems.Contains(curItemName)) {
// Duplicate entry
return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
@@ -1091,38 +1106,38 @@ ParseMFUnpacked(const char* aFilebuf, ns
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();
+ 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.LowerCaseEqualsLiteral("sha1-digest")) {
- if (digest.len > 0) {
+ if (!digest.IsEmpty()) {
// multiple SHA1 digests in section
return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
}
- rv = MapSECStatus(ATOB_ConvertAsciiToItem(&digest, attrValue.get()));
+ 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.
@@ -1305,33 +1320,35 @@ VerifySignedDirectory(AppTrustedRoot aTr
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;
+ nsAutoCString 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) {
+ nsDependentCSubstring calculatedDigest(
+ DigestToDependentString(mfCalculatedDigest));
+ if (!mfDigest.Equals(calculatedDigest)) {
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.
--- a/security/certverifier/ExtendedValidation.cpp
+++ b/security/certverifier/ExtendedValidation.cpp
@@ -1,24 +1,26 @@
/* -*- Mode: C++; tab-width: 2; 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 "ExtendedValidation.h"
-#include "base64.h"
#include "cert.h"
#include "certdb.h"
#include "hasht.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Assertions.h"
+#include "mozilla/Base64.h"
#include "mozilla/Casting.h"
#include "mozilla/PodOperations.h"
+#include "nsDependentString.h"
+#include "nsString.h"
#include "pk11pub.h"
#include "pkix/pkixtypes.h"
#include "prerror.h"
struct nsMyTrustedEVInfo
{
// See bug 1338873 about making these fields const.
const char* dotted_oid;
@@ -1244,35 +1246,38 @@ LoadExtendedValidationInfo()
SECStatus srv;
#ifdef DEBUG
// This section of code double-checks that we calculated the correct
// certificate hash given the issuer and serial number and that it is
// actually present in our loaded root certificates module. It is
// unnecessary to check this in non-debug builds since we will safely fall
// back to DV if the EV information is incorrect.
- mozilla::ScopedAutoSECItem derIssuer;
- srv = ATOB_ConvertAsciiToItem(&derIssuer, entry.issuer_base64);
- MOZ_ASSERT(srv == SECSuccess, "Could not base64-decode built-in EV issuer");
- if (srv != SECSuccess) {
- return NS_ERROR_FAILURE;
+ nsAutoCString derIssuer;
+ nsresult rv = Base64Decode(nsDependentCString(entry.issuer_base64),
+ derIssuer);
+ MOZ_ASSERT(NS_SUCCEEDED(rv), "Could not base64-decode built-in EV issuer");
+ if (NS_FAILED(rv)) {
+ return rv;
}
- mozilla::ScopedAutoSECItem serialNumber;
- srv = ATOB_ConvertAsciiToItem(&serialNumber, entry.serial_base64);
- MOZ_ASSERT(srv == SECSuccess, "Could not base64-decode built-in EV serial");
- if (srv != SECSuccess) {
- return NS_ERROR_FAILURE;
+ nsAutoCString serialNumber;
+ rv = Base64Decode(nsDependentCString(entry.serial_base64), serialNumber);
+ MOZ_ASSERT(NS_SUCCEEDED(rv), "Could not base64-decode built-in EV serial");
+ if (NS_FAILED(rv)) {
+ return rv;
}
CERTIssuerAndSN ias;
- ias.derIssuer.data = derIssuer.data;
- ias.derIssuer.len = derIssuer.len;
- ias.serialNumber.data = serialNumber.data;
- ias.serialNumber.len = serialNumber.len;
+ ias.derIssuer.data =
+ BitwiseCast<unsigned char*, const char*>(derIssuer.get());
+ ias.derIssuer.len = derIssuer.Length();
+ ias.serialNumber.data =
+ BitwiseCast<unsigned char*, const char*>(serialNumber.get());
+ ias.serialNumber.len = serialNumber.Length();
ias.serialNumber.type = siUnsignedInteger;
UniqueCERTCertificate cert(CERT_FindCertByIssuerAndSN(nullptr, &ias));
// If an entry is missing in the NSS root database, it may be because the
// root database is out of sync with what we expect (e.g. a different
// version of system NSS is installed).
if (!cert) {
--- a/security/manager/ssl/ContentSignatureVerifier.cpp
+++ b/security/manager/ssl/ContentSignatureVerifier.cpp
@@ -6,28 +6,28 @@
#include "ContentSignatureVerifier.h"
#include "BRNameMatchingPolicy.h"
#include "SharedCertVerifier.h"
#include "cryptohi.h"
#include "keyhi.h"
#include "mozilla/Assertions.h"
+#include "mozilla/Base64.h"
#include "mozilla/Casting.h"
#include "mozilla/Unused.h"
#include "nsCOMPtr.h"
#include "nsContentUtils.h"
#include "nsISupportsPriority.h"
#include "nsIURI.h"
#include "nsNSSComponent.h"
#include "nsPromiseFlatString.h"
#include "nsSecurityHeaderParser.h"
#include "nsStreamUtils.h"
#include "nsWhitespaceTokenizer.h"
-#include "nssb64.h"
#include "pkix/pkix.h"
#include "pkix/pkixtypes.h"
#include "secerr.h"
NS_IMPL_ISUPPORTS(ContentSignatureVerifier,
nsIContentSignatureVerifier,
nsIInterfaceRequestor,
nsIStreamListener)
@@ -95,22 +95,27 @@ ReadChainIntoCertList(const nsACString&
if (token.IsEmpty()) {
continue;
}
if (inBlock) {
if (token.Equals(footer)) {
inBlock = false;
certFound = true;
// base64 decode data, make certs, append to chain
- ScopedAutoSECItem der;
- if (!NSSBase64_DecodeBuffer(nullptr, &der, blockData.BeginReading(),
- blockData.Length())) {
+ nsAutoCString derString;
+ nsresult rv = Base64Decode(blockData, derString);
+ if (NS_FAILED(rv)) {
CSVerifier_LOG(("CSVerifier: decoding the signature failed\n"));
- return NS_ERROR_FAILURE;
+ return rv;
}
+ SECItem der = {
+ siBuffer,
+ BitwiseCast<unsigned char*, const char*>(derString.get()),
+ derString.Length(),
+ };
UniqueCERTCertificate tmpCert(
CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &der, nullptr, false,
true));
if (!tmpCert) {
return NS_ERROR_FAILURE;
}
// if adding tmpCert succeeds, tmpCert will now be owned by aCertList
SECStatus res = CERT_AddCertToListTail(aCertList, tmpCert.get());
@@ -210,25 +215,30 @@ ContentSignatureVerifier::CreateContextI
// in case we were not able to extract a key
if (!mKey) {
CSVerifier_LOG(("CSVerifier: unable to extract a key\n"));
return NS_ERROR_INVALID_SIGNATURE;
}
// Base 64 decode the signature
- ScopedAutoSECItem rawSignatureItem;
- if (!NSSBase64_DecodeBuffer(nullptr, &rawSignatureItem, mSignature.get(),
- mSignature.Length())) {
+ nsAutoCString rawSignature;
+ rv = Base64Decode(mSignature, rawSignature);
+ if (NS_FAILED(rv)) {
CSVerifier_LOG(("CSVerifier: decoding the signature failed\n"));
- return NS_ERROR_FAILURE;
+ return rv;
}
// get signature object
ScopedAutoSECItem signatureItem;
+ SECItem rawSignatureItem = {
+ siBuffer,
+ BitwiseCast<unsigned char*, const char*>(rawSignature.get()),
+ rawSignature.Length(),
+ };
// We have a raw ecdsa signature r||s so we have to DER-encode it first
// Note that we have to check rawSignatureItem->len % 2 here as
// DSAU_EncodeDerSigWithLen asserts this
if (rawSignatureItem.len == 0 || rawSignatureItem.len % 2 != 0) {
CSVerifier_LOG(("CSVerifier: signature length is bad\n"));
return NS_ERROR_FAILURE;
}
if (DSAU_EncodeDerSigWithLen(&signatureItem, &rawSignatureItem,
--- a/security/manager/ssl/PublicKeyPinningService.cpp
+++ b/security/manager/ssl/PublicKeyPinningService.cpp
@@ -10,17 +10,16 @@
#include "mozilla/BinarySearch.h"
#include "mozilla/Casting.h"
#include "mozilla/Logging.h"
#include "mozilla/Telemetry.h"
#include "nsDependentString.h"
#include "nsISiteSecurityService.h"
#include "nsServiceManagerUtils.h"
#include "nsSiteSecurityService.h"
-#include "nssb64.h"
#include "pkix/pkixtypes.h"
#include "seccomon.h"
#include "sechash.h"
#include "StaticHPKPins.h" // autogenerated by genHPKPStaticpins.js
using namespace mozilla;
using namespace mozilla::pkix;
--- a/security/manager/ssl/nsCryptoHash.cpp
+++ b/security/manager/ssl/nsCryptoHash.cpp
@@ -3,19 +3,20 @@
* 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 "nsCryptoHash.h"
#include <algorithm>
-#include "base64.h"
#include "mozilla/ArrayUtils.h"
+#include "mozilla/Base64.h"
#include "mozilla/Casting.h"
+#include "nsDependentString.h"
#include "nsIInputStream.h"
#include "nsIKeyModule.h"
#include "nsString.h"
#include "pk11pub.h"
#include "sechash.h"
using namespace mozilla;
@@ -218,28 +219,22 @@ nsCryptoHash::Finish(bool ascii, nsACStr
}
uint32_t hashLen = 0;
unsigned char buffer[HASH_LENGTH_MAX];
HASH_End(mHashContext.get(), buffer, &hashLen, HASH_LENGTH_MAX);
mInitialized = false;
- if (ascii)
- {
- UniquePORTString asciiData(BTOA_DataToAscii(buffer, hashLen));
- NS_ENSURE_TRUE(asciiData, NS_ERROR_OUT_OF_MEMORY);
-
- _retval.Assign(asciiData.get());
- }
- else
- {
- _retval.Assign((const char*)buffer, hashLen);
+ if (ascii) {
+ nsDependentCSubstring dataStr(BitwiseCast<char*>(buffer), hashLen);
+ return Base64Encode(dataStr, _retval);
}
+ _retval.Assign(BitwiseCast<char*>(buffer), hashLen);
return NS_OK;
}
//---------------------------------------------
// Implementing nsICryptoHMAC
//---------------------------------------------
NS_IMPL_ISUPPORTS(nsCryptoHMAC, nsICryptoHMAC)
@@ -423,28 +418,22 @@ nsCryptoHMAC::Finish(bool aASCII, nsACSt
uint32_t hashLen = 0;
unsigned char buffer[HASH_LENGTH_MAX];
SECStatus srv = PK11_DigestFinal(mHMACContext.get(), buffer, &hashLen,
HASH_LENGTH_MAX);
if (srv != SECSuccess) {
return NS_ERROR_FAILURE;
}
- if (aASCII)
- {
- UniquePORTString asciiData(BTOA_DataToAscii(buffer, hashLen));
- NS_ENSURE_TRUE(asciiData, NS_ERROR_OUT_OF_MEMORY);
-
- _retval.Assign(asciiData.get());
- }
- else
- {
- _retval.Assign((const char*)buffer, hashLen);
+ if (aASCII) {
+ nsDependentCSubstring dataStr(BitwiseCast<char*>(buffer), hashLen);
+ return Base64Encode(dataStr, _retval);
}
+ _retval.Assign(BitwiseCast<char*>(buffer), hashLen);
return NS_OK;
}
NS_IMETHODIMP
nsCryptoHMAC::Reset()
{
nsNSSShutDownPreventionLock locker;
if (isAlreadyShutDown()) {
--- a/security/manager/ssl/nsDataSignatureVerifier.cpp
+++ b/security/manager/ssl/nsDataSignatureVerifier.cpp
@@ -4,22 +4,22 @@
#include "nsDataSignatureVerifier.h"
#include "ScopedNSSTypes.h"
#include "SharedCertVerifier.h"
#include "cms.h"
#include "cryptohi.h"
#include "keyhi.h"
+#include "mozilla/Base64.h"
#include "mozilla/Casting.h"
#include "mozilla/Unused.h"
#include "nsCOMPtr.h"
#include "nsNSSComponent.h"
#include "nsString.h"
-#include "nssb64.h"
#include "pkix/pkixnss.h"
#include "pkix/pkixtypes.h"
#include "secerr.h"
using namespace mozilla;
using namespace mozilla::pkix;
using namespace mozilla::psm;
@@ -64,48 +64,62 @@ nsDataSignatureVerifier::VerifyData(cons
// Allocate an arena to handle the majority of the allocations
UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
if (!arena) {
return NS_ERROR_OUT_OF_MEMORY;
}
// Base 64 decode the key
- SECItem keyItem;
- PORT_Memset(&keyItem, 0, sizeof(SECItem));
- if (!NSSBase64_DecodeBuffer(arena.get(), &keyItem,
- PromiseFlatCString(aPublicKey).get(),
- aPublicKey.Length())) {
- return NS_ERROR_FAILURE;
+ // For compatibility reasons we need to remove all whitespace first, since
+ // Base64Decode() will not accept invalid characters.
+ nsAutoCString b64KeyNoWhitespace(aPublicKey);
+ b64KeyNoWhitespace.StripWhitespace();
+ nsAutoCString key;
+ nsresult rv = Base64Decode(b64KeyNoWhitespace, key);
+ if (NS_FAILED(rv)) {
+ return rv;
}
// Extract the public key from the data
+ SECItem keyItem = {
+ siBuffer,
+ BitwiseCast<unsigned char*, const char*>(key.get()),
+ key.Length(),
+ };
UniqueCERTSubjectPublicKeyInfo pki(
SECKEY_DecodeDERSubjectPublicKeyInfo(&keyItem));
if (!pki) {
return NS_ERROR_FAILURE;
}
UniqueSECKEYPublicKey publicKey(SECKEY_ExtractPublicKey(pki.get()));
if (!publicKey) {
return NS_ERROR_FAILURE;
}
// Base 64 decode the signature
- SECItem signatureItem;
- PORT_Memset(&signatureItem, 0, sizeof(SECItem));
- if (!NSSBase64_DecodeBuffer(arena.get(), &signatureItem,
- PromiseFlatCString(aSignature).get(),
- aSignature.Length())) {
- return NS_ERROR_FAILURE;
+ // For compatibility reasons we need to remove all whitespace first, since
+ // Base64Decode() will not accept invalid characters.
+ nsAutoCString b64SignatureNoWhitespace(aSignature);
+ b64SignatureNoWhitespace.StripWhitespace();
+ nsAutoCString signature;
+ rv = Base64Decode(b64SignatureNoWhitespace, signature);
+ if (NS_FAILED(rv)) {
+ return rv;
}
// Decode the signature and algorithm
CERTSignedData sigData;
PORT_Memset(&sigData, 0, sizeof(CERTSignedData));
+ SECItem signatureItem = {
+ siBuffer,
+ BitwiseCast<unsigned char*, const char*>(signature.get()),
+ signature.Length(),
+ };
SECStatus srv = SEC_QuickDERDecodeItem(arena.get(), &sigData,
CERT_SignatureDataTemplate,
&signatureItem);
if (srv != SECSuccess) {
return NS_ERROR_FAILURE;
}
// Perform the final verification
--- a/security/manager/ssl/nsKeygenHandler.cpp
+++ b/security/manager/ssl/nsKeygenHandler.cpp
@@ -1,24 +1,27 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* 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 "base64.h"
+#include "nsKeygenHandler.h"
+
#include "cryptohi.h"
#include "keyhi.h"
#include "mozilla/Assertions.h"
+#include "mozilla/Base64.h"
+#include "mozilla/Casting.h"
+#include "nsDependentString.h"
#include "nsIContent.h"
#include "nsIDOMHTMLSelectElement.h"
#include "nsIGenKeypairInfoDlg.h"
#include "nsIServiceManager.h"
#include "nsITokenDialogs.h"
-#include "nsKeygenHandler.h"
#include "nsKeygenHandlerContent.h"
#include "nsKeygenThread.h"
#include "nsNSSComponent.h" // for PIPNSS string bundle calls.
#include "nsNSSHelper.h"
#include "nsReadableUtils.h"
#include "nsUnicharUtils.h"
#include "nsXULAppAPI.h"
#include "nspr.h"
@@ -401,32 +404,33 @@ nsKeygenFormProcessor::GetPublicKey(cons
const nsAString& aKeyParams)
{
nsNSSShutDownPreventionLock locker;
if (isAlreadyShutDown()) {
return NS_ERROR_NOT_AVAILABLE;
}
nsresult rv = NS_ERROR_FAILURE;
- UniquePORTString keystring;
+ nsAutoCString keystring;
char *keyparamsString = nullptr;
uint32_t keyGenMechanism;
PK11SlotInfo *slot = nullptr;
PK11RSAGenParams rsaParams;
mozilla::UniqueSECItem ecParams;
SECOidTag algTag;
int keysize = 0;
void *params = nullptr; // Non-owning.
SECKEYPrivateKey *privateKey = nullptr;
SECKEYPublicKey *publicKey = nullptr;
CERTSubjectPublicKeyInfo *spkInfo = nullptr;
SECStatus srv = SECFailure;
SECItem spkiItem;
SECItem pkacItem;
SECItem signedItem;
+ nsDependentCSubstring signedItemStr;
CERTPublicKeyAndChallenge pkac;
pkac.challenge.data = nullptr;
nsCOMPtr<nsIGeneratingKeypairInfoDialogs> dialogs;
nsKeygenThread *KeygenRunnable = 0;
nsCOMPtr<nsIKeygenThread> runnable;
// permanent and sensitive flags for keygen
PK11AttrFlags attrFlags = PK11_ATTR_TOKEN | PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE;
@@ -615,24 +619,25 @@ nsKeygenFormProcessor::GetPublicKey(cons
privateKey, algTag);
if (srv != SECSuccess) {
goto loser;
}
/*
* Convert the signed public key and challenge into base64/ascii.
*/
- keystring = UniquePORTString(
- BTOA_DataToAscii(signedItem.data, signedItem.len));
- if (!keystring) {
- rv = NS_ERROR_OUT_OF_MEMORY;
+ signedItemStr.Assign(
+ mozilla::BitwiseCast<char*, unsigned char*>(signedItem.data),
+ signedItem.len);
+ rv = mozilla::Base64Encode(signedItemStr, keystring);
+ if (NS_FAILED(rv)) {
goto loser;
}
- CopyASCIItoUTF16(keystring.get(), aOutPublicKey);
+ CopyASCIItoUTF16(keystring, aOutPublicKey);
rv = NS_OK;
loser:
if (srv != SECSuccess) {
if ( privateKey ) {
PK11_DestroyTokenObject(privateKey->pkcs11Slot,privateKey->pkcs11ID);
}
--- a/security/manager/ssl/nsKeygenHandler.h
+++ b/security/manager/ssl/nsKeygenHandler.h
@@ -9,16 +9,17 @@
#include "ScopedNSSTypes.h"
#include "keythi.h"
#include "nsCOMPtr.h"
#include "nsError.h"
#include "nsIFormProcessor.h"
#include "nsIInterfaceRequestor.h"
#include "nsNSSShutDown.h"
+#include "nsString.h"
#include "nsTArray.h"
#include "secmodt.h"
nsresult GetSlotWithMechanism(uint32_t mechanism,
nsIInterfaceRequestor* ctx,
PK11SlotInfo** retSlot,
nsNSSShutDownPreventionLock& /*proofOfLock*/);
--- a/security/manager/ssl/nsSiteSecurityService.cpp
+++ b/security/manager/ssl/nsSiteSecurityService.cpp
@@ -3,17 +3,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsSiteSecurityService.h"
#include "CertVerifier.h"
#include "PublicKeyPinningService.h"
#include "ScopedNSSTypes.h"
#include "SharedCertVerifier.h"
-#include "base64.h"
#include "mozilla/Assertions.h"
#include "mozilla/Base64.h"
#include "mozilla/dom/PContent.h"
#include "mozilla/dom/ToJSValue.h"
#include "mozilla/LinkedList.h"
#include "mozilla/Logging.h"
#include "mozilla/Preferences.h"
#include "nsArrayEnumerator.h"
--- a/security/manager/ssl/tests/unit/test_datasignatureverifier.js
+++ b/security/manager/ssl/tests/unit/test_datasignatureverifier.js
@@ -115,17 +115,23 @@ const signatures = [
// Key 1, Data 1, SHA512 hash algorithm
"MIGTMA0GCSqGSIb3DQEBDQUAA4GBAF0+XYD/r0Annz1GJ24GTkAlWY/OixCSV6Ix" +
"OMM7P2d/jgOP+ICKIpxqaSE0CbkLiegUiidIOWvFqDxQJWlAAukDUWISGFfJMFxX" +
"3jzJ0bBfeNY/1Qo8jMQopcNco/NlNgoSKAUOBtk31aFgNoVC3kWUk6pO97KEiJ+e" +
"bQp9Z2/M",
// Invalid signature data ("foobar" base 64 encoded)
-"Zm9vYmFy"
+"Zm9vYmFy",
+
+// Key 1, Data 1, SHA512 hash algorithm, with embedded whitespace.
+`MIGTMA0GCSqGSIb3DQEBDQUAA4GBAF0+XYD/r0Annz1GJ24GTkAlWY/OixCSV6Ix
+ OMM7P2d/jgOP+ICKIpxqaSE0CbkLiegUiidIOWvFqDxQJWlAAukDUWISGFfJMFxX
+ 3jzJ0bBfeNY/1Qo8jMQopcNco/NlNgoSKAUOBtk31aFgNoVC3kWUk6pO97KEiJ+e
+ bQp9Z2/M`,
];
const tests = [
// Data Signature Key Expected Throws
// Pass cases
[0, 0, 0, true, false], // 0
[0, 1, 0, true, false], // 1
[0, 2, 0, true, false], // 2
@@ -164,16 +170,19 @@ const tests = [
[0, 13, 0, false, false], // 33
[1, 14, 0, false, false], // 34
[1, 15, 0, false, false], // 35
// Invalid data cases
[0, 0, 2, false, true], // 36
[0, 1, 2, false, true], // 37
[0, 16, 0, false, true], // 38
[1, 16, 0, false, true], // 39
+ // Test embedded whitespace (e.g. signature read directly from file) is
+ // ignored for backwards compatibility purposes.
+ [1, 17, 1, true, false],
];
function run_test() {
let verifier = Cc["@mozilla.org/security/datasignatureverifier;1"]
.createInstance(Ci.nsIDataSignatureVerifier);
for (let testCase of tests) {
let testShouldThrow = testCase[4];
--- a/security/manager/ssl/tests/unit/test_hash_algorithms.js
+++ b/security/manager/ssl/tests/unit/test_hash_algorithms.js
@@ -71,19 +71,18 @@ const ALGORITHMS = [
{
initString: "sha512",
initConstant: Ci.nsICryptoHash.SHA512,
hexHashes: [
"07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6",
"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e",
],
b64Hashes: [
- // TODO(Bug 1338897): Stop inserting CRLFs every 64 characters.
- "B+VH2VhvanP3P7rAQ17XaVEhj7fQyNeIownXhUNru2Quk6JSqVTyORJUfR6KO17W\r\n4b/XCXghIz+gU489uFT+5g==",
- "z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwv\r\nY7kxvUdBeoGlODJ6+SfaPg==",
+ "B+VH2VhvanP3P7rAQ17XaVEhj7fQyNeIownXhUNru2Quk6JSqVTyORJUfR6KO17W4b/XCXghIz+gU489uFT+5g==",
+ "z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg==",
],
},
];
function doHash(algo, value, cmp) {
let hash = Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash);
hash.initWithString(algo);
--- a/security/manager/ssl/tests/unit/test_hmac.js
+++ b/security/manager/ssl/tests/unit/test_hmac.js
@@ -87,18 +87,17 @@ function testVectors() {
{
algoID: Ci.nsICryptoHMAC.SHA384, algoName: "SHA-384",
expectedDigest: "af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649",
expectedBase64: "r0XS43ZIQDFhf3jStYprG5x+9GT1oBtH5C7Dc2MiRF6OIkDKXmnix4syOez6shZJ",
},
{
algoID: Ci.nsICryptoHMAC.SHA512, algoName: "SHA-512",
expectedDigest: "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737",
- // TODO(Bug 1338897): Stop inserting CRLFs every 64 characters.
- expectedBase64: "Fkt6e/z4GeLjlfvnO1bgo4e9ZCIugx/WECcM1+olBVSXWL91wFqZSm0DT2X48Ob9\r\nyuqxo01Ka0tjbgcKOLznNw==",
+ expectedBase64: "Fkt6e/z4GeLjlfvnO1bgo4e9ZCIugx/WECcM1+olBVSXWL91wFqZSm0DT2X48Ob9yuqxo01Ka0tjbgcKOLznNw==",
},
];
for (let vector of vectors) {
let digest = getHMAC(dataTestVector, keyTestVector, vector.algoID, false);
equal(hexify(digest), vector.expectedDigest,
`Actual and expected ${vector.algoName} digests should match`);
let b64Digest = getHMAC(dataTestVector, keyTestVector, vector.algoID, true);
--- a/security/manager/ssl/tests/unit/tlsserver/cmd/GenerateOCSPResponse.cpp
+++ b/security/manager/ssl/tests/unit/tlsserver/cmd/GenerateOCSPResponse.cpp
@@ -10,17 +10,16 @@
*/
#include <stdio.h>
#include <string>
#include <vector>
#include "mozilla/ArrayUtils.h"
-#include "base64.h"
#include "cert.h"
#include "nspr.h"
#include "nss.h"
#include "plarenas.h"
#include "prerror.h"
#include "ssl.h"
#include "secerr.h"
--- a/security/nss.symbols
+++ b/security/nss.symbols
@@ -11,17 +11,16 @@
# excluded on Windows, but it doesn't matter because the symbols are already
# exported in NSPR (Windows peculiarity).
PR_*
PL_*
#endif
#include ../db/sqlite3/src/sqlite.symbols
ATOB_AsciiToData
ATOB_AsciiToData_Util
-ATOB_ConvertAsciiToItem
ATOB_ConvertAsciiToItem_Util
BTOA_ConvertItemToAscii_Util
BTOA_DataToAscii
BTOA_DataToAscii_Util
CERT_AddCertToListHead
CERT_AddCertToListTail
CERT_AddExtension
CERT_AddExtensionByOID
@@ -175,17 +174,16 @@ HASH_Begin
HASH_Create
HASH_Destroy
HASH_End
HASH_GetHashObject
HASH_GetType
HASH_HashBuf
HASH_ResultLenByOidTag
HASH_Update
-NSSBase64_DecodeBuffer
NSSBase64_EncodeItem_Util
NSS_CMSContentInfo_GetContent
NSS_CMSContentInfo_SetContent_Data
NSS_CMSContentInfo_SetContent_EnvelopedData
NSS_CMSContentInfo_SetContent_SignedData
NSS_CMSDecoder_Cancel
NSS_CMSDecoder_Finish
NSS_CMSDecoder_Start
@@ -504,17 +502,16 @@ SEC_GetSignatureAlgorithmOidTag
SEC_IA5StringTemplate @DATA@
SEC_IA5StringTemplate_Util @DATA@
SEC_IntegerTemplate @DATA@
SEC_IntegerTemplate_Util @DATA@
SECITEM_AllocArray
SECITEM_AllocItem
SECITEM_AllocItem_Util
SECITEM_ArenaDupItem_Util
-SECITEM_CompareItem
SECITEM_CompareItem_Util
SECITEM_CopyItem
SECITEM_CopyItem_Util
SECITEM_DupArray
SECITEM_DupItem
SECITEM_DupItem_Util
SECITEM_FreeItem
SECITEM_FreeItem_Util