зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1338897 - Avoid using NSS Base64 functions in PSM. r=keeler
The NSS Base64 functions are less safe and convenient to use than the XPCOM ones. They're also an unnecessary dependency on NSS. The NSS Base64 functions behave slightly differently than the XPCOM ones: 1. ATOB_ConvertAsciiToItem() / NSSBase64_DecodeBuffer() silently ignore invalid characters like CRLF, space and so on. Base64Decode() will return an error if these characters are encountered. 2. BTOA_DataToAscii() will produce output that has CRLF inserted every 64 characters. Base64Encode() doesn't do this. For the reasons listed below, no unexpected compatibility issues should arise: 1. AppSignatureVerification.cpp already filters out CRLF and spaces for Manifest and Signature values before decoding. 2. ExtendedValidation.cpp is only given what should be valid hard-coded input to decode. 3. ContentSignatureVerifier.cpp already splits on CRLF for when it needs to decode PEM certs. Spaces shouldn't be likely. For Content-Signature header verification, examination of real input to a running instance of Firefox suggests CRLF and spaces will not be present in the header to decode. 4. nsCryptoHash.cpp encode is affected, but we actually don't want the CRLF behaviour. 5. nsDataSignatureVerifier.cpp decode is affected, but we add whitespace stripping to maintain backwards compatibility. 6. nsKeygenHandler.cpp encode is affected, but the previous CRLF behaviour was arguably a bug, since neither WHATWG or W3C specs specified this. MozReview-Commit-ID: IWMFxqVZMeX --HG-- extra : rebase_source : 4863b2e5eabef0555e8e1ebe39216d0d9393f3e9
This commit is contained in:
Родитель
ff25bd957c
Коммит
7995951109
|
@ -10,8 +10,8 @@
|
|||
#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"
|
||||
|
@ -19,6 +19,7 @@
|
|||
#include "nsCOMPtr.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsDataSignatureVerifier.h"
|
||||
#include "nsDependentString.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsIDirectoryEnumerator.h"
|
||||
#include "nsIFile.h"
|
||||
|
@ -31,7 +32,6 @@
|
|||
#include "nsProxyRelease.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nssb64.h"
|
||||
#include "pkix/pkix.h"
|
||||
#include "pkix/pkixnss.h"
|
||||
#include "plstr.h"
|
||||
|
@ -46,6 +46,15 @@ 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
|
||||
|
@ -164,11 +173,12 @@ FindAndLoadOneEntry(nsIZipReader * zip,
|
|||
// 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;
|
||||
|
@ -217,7 +227,8 @@ VerifyStreamContentDigest(nsIInputStream* stream,
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -226,7 +237,7 @@ VerifyStreamContentDigest(nsIInputStream* stream,
|
|||
|
||||
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));
|
||||
|
@ -244,7 +255,7 @@ VerifyEntryContentDigest(nsIZipReader* zip, const nsACString& aFilename,
|
|||
// @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;
|
||||
|
@ -440,14 +451,14 @@ CheckManifestVersion(const char* & nextLineStart,
|
|||
// 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 (;;) {
|
||||
|
@ -471,7 +482,7 @@ ParseSF(const char* filebuf, /*out*/ SECItem & mfDigest)
|
|||
}
|
||||
|
||||
if (attrName.LowerCaseEqualsLiteral("sha1-digest-manifest")) {
|
||||
rv = MapSECStatus(ATOB_ConvertAsciiToItem(&mfDigest, attrValue.get()));
|
||||
rv = Base64Decode(attrValue, mfDigest);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -527,7 +538,7 @@ ParseMF(const char* filebuf, nsIZipReader * zip,
|
|||
}
|
||||
|
||||
nsAutoCString curItemName;
|
||||
ScopedAutoSECItem digest;
|
||||
nsAutoCString digest;
|
||||
|
||||
for (;;) {
|
||||
nsAutoCString curLine;
|
||||
|
@ -543,7 +554,7 @@ ParseMF(const char* filebuf, nsIZipReader * zip,
|
|||
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;
|
||||
|
@ -568,7 +579,7 @@ ParseMF(const char* filebuf, nsIZipReader * zip,
|
|||
// 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
|
||||
}
|
||||
|
@ -585,12 +596,14 @@ ParseMF(const char* filebuf, nsIZipReader * zip,
|
|||
// (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;
|
||||
}
|
||||
|
@ -754,7 +767,7 @@ OpenSignedAppFile(AppTrustedRoot aTrustedRoot, nsIFile* aJarFile,
|
|||
return rv;
|
||||
}
|
||||
|
||||
ScopedAutoSECItem mfDigest;
|
||||
nsAutoCString mfDigest;
|
||||
rv = ParseSF(BitwiseCast<char*, unsigned char*>(sfBuffer.data), mfDigest);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
@ -770,7 +783,9 @@ OpenSignedAppFile(AppTrustedRoot aTrustedRoot, nsIFile* aJarFile,
|
|||
return rv;
|
||||
}
|
||||
|
||||
if (SECITEM_CompareItem(&mfDigest, &mfCalculatedDigest.get()) != SECEqual) {
|
||||
nsDependentCSubstring calculatedDigest(
|
||||
DigestToDependentString(mfCalculatedDigest));
|
||||
if (!mfDigest.Equals(calculatedDigest)) {
|
||||
return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
|
||||
}
|
||||
|
||||
|
@ -1050,7 +1065,7 @@ ParseMFUnpacked(const char* aFilebuf, nsIFile* aDir,
|
|||
}
|
||||
|
||||
nsAutoString curItemName;
|
||||
ScopedAutoSECItem digest;
|
||||
nsAutoCString digest;
|
||||
|
||||
for (;;) {
|
||||
nsAutoCString curLine;
|
||||
|
@ -1068,7 +1083,7 @@ ParseMFUnpacked(const char* aFilebuf, nsIFile* aDir,
|
|||
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;
|
||||
|
@ -1096,7 +1111,7 @@ ParseMFUnpacked(const char* aFilebuf, nsIFile* aDir,
|
|||
// 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
|
||||
}
|
||||
|
@ -1112,12 +1127,12 @@ ParseMFUnpacked(const char* aFilebuf, nsIFile* aDir,
|
|||
|
||||
// (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;
|
||||
}
|
||||
|
@ -1310,7 +1325,7 @@ VerifySignedDirectory(AppTrustedRoot aTrustedRoot,
|
|||
|
||||
// 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;
|
||||
|
@ -1326,7 +1341,9 @@ VerifySignedDirectory(AppTrustedRoot aTrustedRoot,
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,14 +6,16 @@
|
|||
|
||||
#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"
|
||||
|
@ -1249,25 +1251,28 @@ LoadExtendedValidationInfo()
|
|||
// 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));
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#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"
|
||||
|
@ -22,7 +23,6 @@
|
|||
#include "nsSecurityHeaderParser.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsWhitespaceTokenizer.h"
|
||||
#include "nssb64.h"
|
||||
#include "pkix/pkix.h"
|
||||
#include "pkix/pkixtypes.h"
|
||||
#include "secerr.h"
|
||||
|
@ -100,12 +100,17 @@ ReadChainIntoCertList(const nsACString& aCertChain, CERTCertList* aCertList,
|
|||
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));
|
||||
|
@ -215,15 +220,20 @@ ContentSignatureVerifier::CreateContextInternal(const nsACString& aData,
|
|||
}
|
||||
|
||||
// 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
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include "nsISiteSecurityService.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsSiteSecurityService.h"
|
||||
#include "nssb64.h"
|
||||
#include "pkix/pkixtypes.h"
|
||||
#include "seccomon.h"
|
||||
#include "sechash.h"
|
||||
|
|
|
@ -8,9 +8,10 @@
|
|||
|
||||
#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"
|
||||
|
@ -223,18 +224,12 @@ nsCryptoHash::Finish(bool ascii, nsACString & _retval)
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -428,18 +423,12 @@ nsCryptoHMAC::Finish(bool aASCII, nsACString & _retval)
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,12 +9,12 @@
|
|||
#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"
|
||||
|
@ -69,15 +69,22 @@ nsDataSignatureVerifier::VerifyData(const nsACString& aData,
|
|||
}
|
||||
|
||||
// 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) {
|
||||
|
@ -90,17 +97,24 @@ nsDataSignatureVerifier::VerifyData(const nsACString& aData,
|
|||
}
|
||||
|
||||
// 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);
|
||||
|
|
|
@ -4,16 +4,19 @@
|
|||
* 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.
|
||||
|
@ -406,7 +409,7 @@ nsKeygenFormProcessor::GetPublicKey(const nsAString& aValue,
|
|||
}
|
||||
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
UniquePORTString keystring;
|
||||
nsAutoCString keystring;
|
||||
char *keyparamsString = nullptr;
|
||||
uint32_t keyGenMechanism;
|
||||
PK11SlotInfo *slot = nullptr;
|
||||
|
@ -422,6 +425,7 @@ nsKeygenFormProcessor::GetPublicKey(const nsAString& aValue,
|
|||
SECItem spkiItem;
|
||||
SECItem pkacItem;
|
||||
SECItem signedItem;
|
||||
nsDependentCSubstring signedItemStr;
|
||||
CERTPublicKeyAndChallenge pkac;
|
||||
pkac.challenge.data = nullptr;
|
||||
nsCOMPtr<nsIGeneratingKeypairInfoDialogs> dialogs;
|
||||
|
@ -620,14 +624,15 @@ nsKeygenFormProcessor::GetPublicKey(const nsAString& aValue,
|
|||
/*
|
||||
* 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;
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "nsIFormProcessor.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsNSSShutDown.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "secmodt.h"
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#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"
|
||||
|
|
|
@ -120,7 +120,13 @@ const signatures = [
|
|||
"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 = [
|
||||
|
@ -169,6 +175,9 @@ const tests = [
|
|||
[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() {
|
||||
|
|
|
@ -76,9 +76,8 @@ const ALGORITHMS = [
|
|||
"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==",
|
||||
],
|
||||
},
|
||||
];
|
||||
|
|
|
@ -92,8 +92,7 @@ function testVectors() {
|
|||
{
|
||||
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==",
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
|
||||
#include "base64.h"
|
||||
#include "cert.h"
|
||||
#include "nspr.h"
|
||||
#include "nss.h"
|
||||
|
|
|
@ -16,7 +16,6 @@ PL_*
|
|||
#include ../db/sqlite3/src/sqlite.symbols
|
||||
ATOB_AsciiToData
|
||||
ATOB_AsciiToData_Util
|
||||
ATOB_ConvertAsciiToItem
|
||||
ATOB_ConvertAsciiToItem_Util
|
||||
BTOA_ConvertItemToAscii_Util
|
||||
BTOA_DataToAscii
|
||||
|
@ -180,7 +179,6 @@ HASH_GetType
|
|||
HASH_HashBuf
|
||||
HASH_ResultLenByOidTag
|
||||
HASH_Update
|
||||
NSSBase64_DecodeBuffer
|
||||
NSSBase64_EncodeItem_Util
|
||||
NSS_CMSContentInfo_GetContent
|
||||
NSS_CMSContentInfo_SetContent_Data
|
||||
|
@ -509,7 +507,6 @@ SECITEM_AllocArray
|
|||
SECITEM_AllocItem
|
||||
SECITEM_AllocItem_Util
|
||||
SECITEM_ArenaDupItem_Util
|
||||
SECITEM_CompareItem
|
||||
SECITEM_CompareItem_Util
|
||||
SECITEM_CopyItem
|
||||
SECITEM_CopyItem_Util
|
||||
|
|
Загрузка…
Ссылка в новой задаче