Bug 1768047 - introduce HMAC C++ helper and remove nsICryptoHMAC r=jschanck,necko-reviewers,kershaw,padenot

This patch removes the redundant nsICryptoHMAC interface and implementation,
updates front-end code to use WebCrypto, and changes back-end code to use the
helper class HMAC introduced by this patch.

This also removes the last uses of nsIKeyObject and nsIKeyObjectFactory, and
thus those interfaces and implementations as well.

Differential Revision: https://phabricator.services.mozilla.com/D145656
This commit is contained in:
Dana Keeler 2022-05-12 22:24:29 +00:00
Родитель 351b6fd7fb
Коммит fb67326470
29 изменённых файлов: 289 добавлений и 870 удалений

Просмотреть файл

@ -25,6 +25,7 @@
#include "MainThreadUtils.h"
#include "PLDHashTable.h"
#include "ReferrerInfo.h"
#include "ScopedNSSTypes.h"
#include "ThirdPartyUtil.h"
#include "Units.h"
#include "chrome/common/ipc_message.h"
@ -269,7 +270,6 @@
#include "nsIContentSecurityPolicy.h"
#include "nsIContentSink.h"
#include "nsIContentViewer.h"
#include "nsICryptoHMAC.h"
#include "nsIDOMWindowUtils.h"
#include "nsIDocShell.h"
#include "nsIDocShellTreeItem.h"
@ -290,7 +290,6 @@
#include "nsIInputStream.h"
#include "nsIInterfaceRequestor.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIKeyModule.h"
#include "nsILoadContext.h"
#include "nsILoadGroup.h"
#include "nsILoadInfo.h"
@ -10649,10 +10648,6 @@ nsresult nsContentUtils::AnonymizeId(nsAString& aId,
MOZ_ASSERT(NS_IsMainThread());
nsresult rv;
nsCOMPtr<nsIKeyObjectFactory> factory =
do_GetService("@mozilla.org/security/keyobjectfactory;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCString rawKey;
if (aFormat == OriginFormat::Base64) {
rv = Base64Decode(aOriginKey, rawKey);
@ -10661,26 +10656,28 @@ nsresult nsContentUtils::AnonymizeId(nsAString& aId,
rawKey = aOriginKey;
}
nsCOMPtr<nsIKeyObject> key;
rv = factory->KeyFromString(nsIKeyObject::HMAC, rawKey, getter_AddRefs(key));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsICryptoHMAC> hasher =
do_CreateInstance(NS_CRYPTO_HMAC_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = hasher->Init(nsICryptoHMAC::SHA256, key);
HMAC hmac;
rv = hmac.Begin(
SEC_OID_SHA256,
Span(reinterpret_cast<const uint8_t*>(rawKey.get()), rawKey.Length()));
NS_ENSURE_SUCCESS(rv, rv);
NS_ConvertUTF16toUTF8 id(aId);
rv = hasher->Update(reinterpret_cast<const uint8_t*>(id.get()), id.Length());
rv = hmac.Update(reinterpret_cast<const uint8_t*>(id.get()), id.Length());
NS_ENSURE_SUCCESS(rv, rv);
nsCString mac;
rv = hasher->Finish(true, mac);
nsTArray<uint8_t> macBytes;
rv = hmac.End(macBytes);
NS_ENSURE_SUCCESS(rv, rv);
CopyUTF8toUTF16(mac, aId);
nsCString macBase64;
rv = Base64Encode(
nsDependentCSubstring(reinterpret_cast<const char*>(macBytes.Elements()),
macBytes.Length()),
macBase64);
NS_ENSURE_SUCCESS(rv, rv);
CopyUTF8toUTF16(macBase64, aId);
return NS_OK;
}

Просмотреть файл

@ -48,9 +48,7 @@
#include "nsContentUtils.h"
#include "nsGlobalWindow.h"
#include "nsHashPropertyBag.h"
#include "nsICryptoHMAC.h"
#include "nsIEventTarget.h"
#include "nsIKeyModule.h"
#include "nsIPermissionManager.h"
#include "nsIUUIDGenerator.h"
#include "nsJSUtils.h"

Просмотреть файл

@ -70,27 +70,26 @@ var MIDITestUtils = {
is(expected[i], actual[i], "Packet value " + expected[i] + " matches.");
}
},
stableId: info => {
stableId: async info => {
// This computes the stable ID of a MIDI port according to the logic we
// use in the Web MIDI implementation. See MIDIPortChild::GenerateStableId()
// and nsContentUtils::AnonymizeId().
const Cc = SpecialPowers.Cc;
const Ci = SpecialPowers.Ci;
const id = info.name + info.manufacturer + info.version;
const encoder = new TextEncoder();
const data = encoder.encode(id);
let key = self.origin;
var digest;
let keyObject = Cc["@mozilla.org/security/keyobjectfactory;1"]
.getService(Ci.nsIKeyObjectFactory)
.keyFromString(Ci.nsIKeyObject.HMAC, key);
let cryptoHMAC = Cc["@mozilla.org/security/hmac;1"].createInstance(
Ci.nsICryptoHMAC
const keyBytes = encoder.encode(self.origin);
const key = await crypto.subtle.importKey(
"raw",
keyBytes,
{ name: "HMAC", hash: "SHA-256" },
false,
["sign"]
);
cryptoHMAC.init(Ci.nsICryptoHMAC.SHA256, keyObject);
cryptoHMAC.update(data, data.length);
return cryptoHMAC.finish(true);
const result = new Uint8Array(await crypto.subtle.sign("HMAC", key, data));
let resultString = "";
for (let i = 0; i < result.length; i++) {
resultString += String.fromCharCode(result[i]);
}
return btoa(resultString);
},
};

Просмотреть файл

@ -25,7 +25,7 @@
return;
}
is(midi_access.sysexEnabled, false, "Sysex should be false");
output = midi_access.outputs.get(MIDITestUtils.outputInfo.id);
output = midi_access.outputs.get(await MIDITestUtils.outputInfo.id);
let statePromiseRes;
let statePromise = new Promise((res) => { statePromiseRes = res; });
await output.open();

Просмотреть файл

@ -11,9 +11,9 @@
<script class="testbody" type="application/javascript">
SimpleTest.waitForExplicitFinish();
let objectCompare = (type, props, obj) => {
let objectCompare = async (type, props, obj) => {
for (var prop in props) {
is(props[prop], obj[prop], type + " property value " + prop + " is " + props[prop]);
is(await props[prop], obj[prop], type + " property value " + prop + " is " + props[prop]);
}
};
let failOnCall = (event) => {
@ -26,8 +26,8 @@
ok(true, "MIDI Access Request successful");
is(access.sysexEnabled, false, "Sysex should be false");
access.addEventListener("statechange", failOnCall);
var input_id = MIDITestUtils.inputInfo.id;
var output_id = MIDITestUtils.outputInfo.id;
var input_id = await MIDITestUtils.inputInfo.id;
var output_id = await MIDITestUtils.outputInfo.id;
var inputs = access.inputs;
var outputs = access.outputs;
is(inputs.size, 1, "Should have one input");
@ -36,8 +36,8 @@
ok(outputs.has(output_id), "output list should contain output id");
var input = access.inputs.get(input_id);
var output = access.outputs.get(output_id);
objectCompare("input", MIDITestUtils.inputInfo, input);
objectCompare("output", MIDITestUtils.outputInfo, output);
await objectCompare("input", MIDITestUtils.inputInfo, input);
await objectCompare("output", MIDITestUtils.outputInfo, output);
access.removeEventListener("statechange", failOnCall);
SimpleTest.finish();
};

Просмотреть файл

@ -23,7 +23,7 @@
}
ok(true, "MIDI Access Request successful");
let input = access.inputs.get(MIDITestUtils.inputInfo.id);
let input = access.inputs.get(await MIDITestUtils.inputInfo.id);
let portEventRes;
let accessEventRes;
let portEventPromise = new Promise((resolve, reject) => { portEventRes = resolve; });
@ -66,7 +66,7 @@
ok(event.port.connection === "closed", "connection registered as closed");
};
out_access.addEventListener("statechange", outputEventHandler);
let output_opened = out_access.outputs.get(MIDITestUtils.alwaysClosedTestOutputInfo.id);
let output_opened = out_access.outputs.get(await MIDITestUtils.alwaysClosedTestOutputInfo.id);
try {
await output_opened.open();
ok(false, "Should've failed to open port!");

Просмотреть файл

@ -42,8 +42,8 @@
output.close();
}
input = access.inputs.get(MIDITestUtils.inputInfo.id);
output = access.outputs.get(MIDITestUtils.outputInfo.id);
input = access.inputs.get(await MIDITestUtils.inputInfo.id);
output = access.outputs.get(await MIDITestUtils.outputInfo.id);
input.onstatechange = (event) => { checkCallbacks(event.port); };
output.onstatechange = (event) => { checkCallbacks(event.port); };
// Ports are closed. Fire rest of tests.

Просмотреть файл

@ -58,7 +58,7 @@
access.addEventListener("statechange", accessStateChangeHandler);
// Part 2: open test device, make sure it connects, attach event handler to device object
output = access.outputs.get(MIDITestUtils.outputInfo.id);
output = access.outputs.get(await MIDITestUtils.outputInfo.id);
resetPromises();
output.send([0x90, 0x01, 0x00]);
let accessEvent = await accessPromise;

Просмотреть файл

@ -43,9 +43,9 @@
let access_sysex = await navigator.requestMIDIAccess({ "sysex": true });
ok(true, "MIDI Access Request successful");
ok(true, "Check for sysex message drop");
input = access_regular.inputs.get(MIDITestUtils.inputInfo.id);
output = access_sysex.outputs.get(MIDITestUtils.outputInfo.id);
input_sysex = access_sysex.inputs.get(MIDITestUtils.inputInfo.id);
input = access_regular.inputs.get(await MIDITestUtils.inputInfo.id);
output = access_sysex.outputs.get(await MIDITestUtils.outputInfo.id);
input_sysex = access_sysex.inputs.get(await MIDITestUtils.inputInfo.id);
input_sysex.onmidimessage = checkSysexReceive;
input.onmidimessage = checkNoSysexReceive;
output.send([0xF0, 0x00, 0xF7]);

Просмотреть файл

@ -29,9 +29,9 @@
// Request access without sysex.
let access_sysex = await navigator.requestMIDIAccess({ "sysex": true });
let input_sysex = access_sysex.inputs.get(MIDITestUtils.inputInfo.id);
let input_sysex = access_sysex.inputs.get(await MIDITestUtils.inputInfo.id);
input_sysex.onmidimessage = checkReturn;
let output_sysex = access_sysex.outputs.get(MIDITestUtils.outputInfo.id);
let output_sysex = access_sysex.outputs.get(await MIDITestUtils.outputInfo.id);
output_sysex.send([0xF0, 0x01, 0xF7]);
}
</script>

Просмотреть файл

@ -36,8 +36,8 @@
ok(true, "MIDI Access Request successful");
is(access.sysexEnabled, false, "Sysex should be false");
input = access.inputs.get(MIDITestUtils.inputInfo.id);
output = access.outputs.get(MIDITestUtils.outputInfo.id);
input = access.inputs.get(await MIDITestUtils.inputInfo.id);
output = access.outputs.get(await MIDITestUtils.outputInfo.id);
input.onmidimessage = checkReturn;
// trigger the packet timing sorting tests
output.send([0x90, 0x03, 0x00], 0);

Просмотреть файл

@ -15,7 +15,7 @@
async function runTests() {
await MIDITestUtils.permissionSetup(true);
const access = await navigator.requestMIDIAccess({ sysex: true });
const output = access.outputs.get(MIDITestUtils.stateTestOutputInfo.id);
const output = access.outputs.get(await MIDITestUtils.stateTestOutputInfo.id);
// Note on(off).

Просмотреть файл

@ -781,11 +781,6 @@
*/
#define NS_CRYPTO_HASH_CONTRACTID "@mozilla.org/security/hash;1"
/**
* Must implement nsICryptoHMAC.
*/
#define NS_CRYPTO_HMAC_CONTRACTID "@mozilla.org/security/hmac;1"
/******************************************************************************
* Categories
*/

Просмотреть файл

@ -36,6 +36,10 @@
# include "mozilla/mozalloc_oom.h"
#endif
// Normally this would be included from nsNSSComponent.h, but that file includes
// this file.
bool EnsureNSSInitializedChromeOrContent();
namespace mozilla {
// NSPR APIs use PRStatus/PR_GetError and NSS APIs use SECStatus/PR_GetError to
@ -66,6 +70,18 @@ inline void SECKEYEncryptedPrivateKeyInfo_true(
SECKEY_DestroyEncryptedPrivateKeyInfo(epki, true);
}
// If this was created via PK11_ListFixedKeysInSlot, we may have a list of keys,
// in which case we have to free them all (and if not, this will still free the
// one key).
inline void FreeOneOrMoreSymKeys(PK11SymKey* keys) {
PK11SymKey* next;
while (keys) {
next = PK11_GetNextSymKey(keys);
PK11_FreeSymKey(keys);
keys = next;
}
}
} // namespace internal
// Emulates MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE, but for UniquePtrs.
@ -77,6 +93,69 @@ inline void SECKEYEncryptedPrivateKeyInfo_true(
MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePK11Context, PK11Context,
internal::PK11_DestroyContext_true)
MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePK11SlotInfo, PK11SlotInfo,
PK11_FreeSlot)
MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePK11SymKey, PK11SymKey,
internal::FreeOneOrMoreSymKeys)
// Common base class for Digest and HMAC. Should not be used directly.
// Subclasses must implement a `Begin` function that initializes
// `mDigestContext` and calls `SetLength`.
class DigestBase {
protected:
explicit DigestBase() : mLen(0), mDigestContext(nullptr) {}
public:
nsresult Update(Span<const uint8_t> in) {
return Update(in.Elements(), in.Length());
}
nsresult Update(const unsigned char* buf, const uint32_t len) {
if (!mDigestContext) {
return NS_ERROR_NOT_INITIALIZED;
}
return MapSECStatus(PK11_DigestOp(mDigestContext.get(), buf, len));
}
nsresult End(/*out*/ nsTArray<uint8_t>& out) {
if (!mDigestContext) {
return NS_ERROR_NOT_INITIALIZED;
}
out.SetLength(mLen);
uint32_t len;
nsresult rv = MapSECStatus(
PK11_DigestFinal(mDigestContext.get(), out.Elements(), &len, mLen));
NS_ENSURE_SUCCESS(rv, rv);
mDigestContext = nullptr;
NS_ENSURE_TRUE(len == mLen, NS_ERROR_UNEXPECTED);
return NS_OK;
}
protected:
nsresult SetLength(SECOidTag hashType) {
switch (hashType) {
case SEC_OID_MD5:
mLen = MD5_LENGTH;
break;
case SEC_OID_SHA1:
mLen = SHA1_LENGTH;
break;
case SEC_OID_SHA256:
mLen = SHA256_LENGTH;
break;
default:
return NS_ERROR_INVALID_ARG;
}
return NS_OK;
}
private:
uint8_t mLen;
protected:
UniquePK11Context mDigestContext;
};
/** A more convenient way of dealing with digests calculated into
* stack-allocated buffers. NSS must be initialized on the main thread before
@ -104,9 +183,9 @@ MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePK11Context, PK11Context,
* rv = digest.End(digestArray);
* NS_ENSURE_SUCCESS(rv, rv)
*/
class Digest {
class Digest : public DigestBase {
public:
explicit Digest() : mLen(0), mDigestContext(nullptr) {}
explicit Digest() : DigestBase() {}
static nsresult DigestBuf(SECOidTag hashAlg, Span<const uint8_t> buf,
/*out*/ nsTArray<uint8_t>& out) {
@ -136,6 +215,9 @@ class Digest {
}
nsresult Begin(SECOidTag hashAlg) {
if (!EnsureNSSInitializedChromeOrContent()) {
return NS_ERROR_FAILURE;
}
if (hashAlg != SEC_OID_SHA1 && hashAlg != SEC_OID_SHA256) {
return NS_ERROR_INVALID_ARG;
}
@ -149,60 +231,69 @@ class Digest {
NS_ENSURE_SUCCESS(rv, rv);
return MapSECStatus(PK11_DigestBegin(mDigestContext.get()));
}
};
nsresult Update(Span<const uint8_t> in) {
return Update(in.Elements(), in.Length());
}
// A helper class to calculate HMACs over some data given a key.
// Only SHA256 and, sadly, MD5 are supported at the moment.
// Typical usage:
// (ensure NSS is initialized)
// (obtain raw bytes for a key, some data to calculate the HMAC for)
// HMAC hmac;
// nsresult rv = hmac.Begin(SEC_OID_SHA256, Span(key));
// NS_ENSURE_SUCCESS(rv, rv);
// rv = hmac.Update(buf, len);
// NS_ENSURE_SUCCESS(rv, rv);
// nsTArray<uint8_t> calculatedHmac;
// rv = hmac.End(calculatedHmac);
// NS_ENSURE_SUCCESS(rv, rv);
class HMAC : public DigestBase {
public:
explicit HMAC() : DigestBase() {}
nsresult Update(const unsigned char* buf, const uint32_t len) {
if (!mDigestContext) {
return NS_ERROR_NOT_INITIALIZED;
nsresult Begin(SECOidTag hashAlg, Span<const uint8_t> key) {
if (!EnsureNSSInitializedChromeOrContent()) {
return NS_ERROR_FAILURE;
}
return MapSECStatus(PK11_DigestOp(mDigestContext.get(), buf, len));
}
nsresult End(/*out*/ nsTArray<uint8_t>& out) {
if (!mDigestContext) {
return NS_ERROR_NOT_INITIALIZED;
}
out.SetLength(mLen);
uint32_t len;
nsresult rv = MapSECStatus(
PK11_DigestFinal(mDigestContext.get(), out.Elements(), &len, mLen));
NS_ENSURE_SUCCESS(rv, rv);
mDigestContext = nullptr;
NS_ENSURE_TRUE(len == mLen, NS_ERROR_UNEXPECTED);
return NS_OK;
}
private:
nsresult SetLength(SECOidTag hashType) {
#ifdef _MSC_VER
# pragma warning(push)
// C4061: enumerator 'symbol' in switch of enum 'symbol' is not
// explicitly handled.
# pragma warning(disable : 4061)
#endif
switch (hashType) {
case SEC_OID_SHA1:
mLen = SHA1_LENGTH;
break;
CK_MECHANISM_TYPE mechType;
switch (hashAlg) {
case SEC_OID_SHA256:
mLen = SHA256_LENGTH;
mechType = CKM_SHA256_HMAC;
break;
case SEC_OID_MD5:
mechType = CKM_MD5_HMAC;
break;
default:
return NS_ERROR_INVALID_ARG;
}
#ifdef _MSC_VER
# pragma warning(pop)
#endif
if (key.Length() > std::numeric_limits<unsigned int>::max()) {
return NS_ERROR_INVALID_ARG;
}
// SECItem's data field is a non-const unsigned char*. The good news is the
// data won't be mutated, but the bad news is the constness needs to be
// casted away.
SECItem keyItem = {siBuffer, const_cast<unsigned char*>(key.Elements()),
static_cast<unsigned int>(key.Length())};
UniquePK11SlotInfo slot(PK11_GetInternalSlot());
if (!slot) {
return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
}
UniquePK11SymKey symKey(
PK11_ImportSymKey(slot.get(), CKM_GENERIC_SECRET_KEY_GEN,
PK11_OriginUnwrap, CKA_SIGN, &keyItem, nullptr));
if (!symKey) {
return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
}
SECItem emptyData = {siBuffer, nullptr, 0};
mDigestContext = UniquePK11Context(PK11_CreateContextBySymKey(
mechType, CKA_SIGN, symKey.get(), &emptyData));
if (!mDigestContext) {
return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
}
return NS_OK;
nsresult rv = SetLength(hashAlg);
NS_ENSURE_SUCCESS(rv, rv);
return MapSECStatus(PK11_DigestBegin(mDigestContext.get()));
}
uint8_t mLen;
UniquePK11Context mDigestContext;
};
namespace internal {
@ -271,18 +362,6 @@ inline void VFY_DestroyContext_true(VFYContext* ctx) {
VFY_DestroyContext(ctx, true);
}
// If this was created via PK11_ListFixedKeysInSlot, we may have a list of keys,
// in which case we have to free them all (and if not, this will still free the
// one key).
inline void FreeOneOrMoreSymKeys(PK11SymKey* keys) {
PK11SymKey* next;
while (keys) {
next = PK11_GetNextSymKey(keys);
PK11_FreeSymKey(keys);
keys = next;
}
}
} // namespace internal
MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueCERTCertificate, CERTCertificate,
@ -321,12 +400,8 @@ MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniqueNSSCMSSignedData, NSSCMSSignedData,
MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePK11GenericObject,
PK11GenericObject,
PK11_DestroyGenericObject)
MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePK11SlotInfo, PK11SlotInfo,
PK11_FreeSlot)
MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePK11SlotList, PK11SlotList,
PK11_FreeSlotList)
MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePK11SymKey, PK11SymKey,
internal::FreeOneOrMoreSymKeys)
MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePLArenaPool, PLArenaPool,
internal::PORT_FreeArena_false)

Просмотреть файл

@ -78,24 +78,6 @@ Classes = [
'type': 'nsCryptoHash',
'legacy_constructor': 'mozilla::psm::NSSConstructor<nsCryptoHash>',
},
{
'cid': '{a496d0a2-dff7-4e23-bd65-1ca742fa178a}',
'contract_ids': ['@mozilla.org/security/hmac;1'],
'type': 'nsCryptoHMAC',
'legacy_constructor': 'mozilla::psm::NSSConstructor<nsCryptoHMAC>',
},
{
'cid': '{9d383ddd-6856-4187-8485-f36195b29a0e}',
'contract_ids': ['@mozilla.org/security/keyobject;1'],
'type': 'nsKeyObject',
'legacy_constructor': 'mozilla::psm::NSSConstructor<nsKeyObject>',
},
{
'cid': '{2a35dd47-b026-4e8d-b6b7-5740f61ab902}',
'contract_ids': ['@mozilla.org/security/keyobjectfactory;1'],
'type': 'nsKeyObjectFactory',
'legacy_constructor': 'mozilla::psm::NSSConstructor<nsKeyObjectFactory>',
},
{
'cid': '{45a5fe2f-c350-4b86-962d-02d5aaaa955a}',
'contract_ids': ['@mozilla.org/security/contentsignatureverifier;1'],

Просмотреть файл

@ -25,8 +25,6 @@ XPIDL_SOURCES += [
"nsIClientAuthRememberService.idl",
"nsIContentSignatureVerifier.idl",
"nsICryptoHash.idl",
"nsICryptoHMAC.idl",
"nsIKeyModule.idl",
"nsILocalCertService.idl",
"nsINSSComponent.idl",
"nsINSSErrorsService.idl",
@ -116,7 +114,6 @@ UNIFIED_SOURCES += [
"nsCertOverrideService.cpp",
"nsClientAuthRemember.cpp",
"nsCryptoHash.cpp",
"nsKeyModule.cpp",
"nsNSSCallbacks.cpp",
"nsNSSCertHelper.cpp",
"nsNSSCertificate.cpp",

Просмотреть файл

@ -13,7 +13,6 @@
#include "mozilla/Casting.h"
#include "nsDependentString.h"
#include "nsIInputStream.h"
#include "nsIKeyModule.h"
#include "nsString.h"
#include "pk11pub.h"
#include "sechash.h"
@ -176,159 +175,3 @@ nsCryptoHash::Finish(bool ascii, nsACString& _retval) {
_retval.Assign(BitwiseCast<char*>(buffer), hashLen);
return NS_OK;
}
//---------------------------------------------
// Implementing nsICryptoHMAC
//---------------------------------------------
NS_IMPL_ISUPPORTS(nsCryptoHMAC, nsICryptoHMAC)
nsCryptoHMAC::nsCryptoHMAC() : mHMACContext(nullptr) {}
NS_IMETHODIMP
nsCryptoHMAC::Init(uint32_t aAlgorithm, nsIKeyObject* aKeyObject) {
if (mHMACContext) {
mHMACContext = nullptr;
}
CK_MECHANISM_TYPE mechType;
switch (aAlgorithm) {
case nsICryptoHMAC::MD5:
mechType = CKM_MD5_HMAC;
break;
case nsICryptoHMAC::SHA1:
mechType = CKM_SHA_1_HMAC;
break;
case nsICryptoHMAC::SHA256:
mechType = CKM_SHA256_HMAC;
break;
case nsICryptoHMAC::SHA384:
mechType = CKM_SHA384_HMAC;
break;
case nsICryptoHMAC::SHA512:
mechType = CKM_SHA512_HMAC;
break;
default:
return NS_ERROR_INVALID_ARG;
}
NS_ENSURE_ARG_POINTER(aKeyObject);
nsresult rv;
int16_t keyType;
rv = aKeyObject->GetType(&keyType);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(keyType == nsIKeyObject::SYM_KEY, NS_ERROR_INVALID_ARG);
PK11SymKey* key;
// GetKeyObj doesn't addref the key
rv = aKeyObject->GetKeyObj(&key);
NS_ENSURE_SUCCESS(rv, rv);
SECItem rawData;
rawData.data = 0;
rawData.len = 0;
mHMACContext.reset(
PK11_CreateContextBySymKey(mechType, CKA_SIGN, key, &rawData));
NS_ENSURE_TRUE(mHMACContext, NS_ERROR_FAILURE);
if (PK11_DigestBegin(mHMACContext.get()) != SECSuccess) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
NS_IMETHODIMP
nsCryptoHMAC::Update(const uint8_t* aData, uint32_t aLen) {
if (!mHMACContext) return NS_ERROR_NOT_INITIALIZED;
if (!aData) return NS_ERROR_INVALID_ARG;
if (PK11_DigestOp(mHMACContext.get(), aData, aLen) != SECSuccess) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
NS_IMETHODIMP
nsCryptoHMAC::UpdateFromStream(nsIInputStream* aStream, uint32_t aLen) {
if (!mHMACContext) return NS_ERROR_NOT_INITIALIZED;
if (!aStream) return NS_ERROR_INVALID_ARG;
uint64_t n;
nsresult rv = aStream->Available(&n);
if (NS_FAILED(rv)) return rv;
// if the user has passed UINT32_MAX, then read
// everything in the stream
uint64_t len = aLen;
if (aLen == UINT32_MAX) len = n;
// So, if the stream has NO data available for the hash,
// or if the data available is less then what the caller
// requested, we can not fulfill the HMAC update. In this
// case, just return NS_ERROR_NOT_AVAILABLE indicating
// that there is not enough data in the stream to satisify
// the request.
if (n == 0 || n < len) return NS_ERROR_NOT_AVAILABLE;
char buffer[STREAM_BUFFER_SIZE];
while (len > 0) {
uint64_t readLimit = std::min<uint64_t>(STREAM_BUFFER_SIZE, len);
uint32_t read;
rv = aStream->Read(buffer, AssertedCast<uint32_t>(readLimit), &read);
if (NS_FAILED(rv)) {
return rv;
}
if (read == 0) {
return NS_BASE_STREAM_CLOSED;
}
rv = Update(BitwiseCast<uint8_t*>(buffer), read);
if (NS_FAILED(rv)) {
return rv;
}
len -= read;
}
return NS_OK;
}
NS_IMETHODIMP
nsCryptoHMAC::Finish(bool aASCII, nsACString& _retval) {
if (!mHMACContext) return NS_ERROR_NOT_INITIALIZED;
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) {
nsDependentCSubstring dataStr(BitwiseCast<char*>(buffer), hashLen);
return Base64Encode(dataStr, _retval);
}
_retval.Assign(BitwiseCast<char*>(buffer), hashLen);
return NS_OK;
}
NS_IMETHODIMP
nsCryptoHMAC::Reset() {
if (PK11_DigestBegin(mHMACContext.get()) != SECSuccess) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}

Просмотреть файл

@ -9,7 +9,6 @@
#include "ScopedNSSTypes.h"
#include "hasht.h"
#include "nsICryptoHMAC.h"
#include "nsICryptoHash.h"
#include "secmodt.h"
@ -21,12 +20,6 @@ class nsIInputStream;
0x96, 0xff, 0x87, 0xb0, 0x00, 0x5c, 0xfe, 0xf7 \
} \
}
#define NS_CRYPTO_HMAC_CID \
{ \
0xa496d0a2, 0xdff7, 0x4e23, { \
0xbd, 0x65, 0x1c, 0xa7, 0x42, 0xfa, 0x17, 0x8a \
} \
}
class nsCryptoHash final : public nsICryptoHash {
public:
@ -42,17 +35,4 @@ class nsCryptoHash final : public nsICryptoHash {
bool mInitialized;
};
class nsCryptoHMAC : public nsICryptoHMAC {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICRYPTOHMAC
nsCryptoHMAC();
private:
virtual ~nsCryptoHMAC() = default;
mozilla::UniquePK11Context mHMACContext;
};
#endif // nsCryptoHash_h

Просмотреть файл

@ -1,106 +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 "nsISupports.idl"
interface nsIInputStream;
interface nsIKeyObject;
/**
* nsICryptoHMAC
* This interface provides HMAC signature algorithms.
*/
[scriptable, uuid(8FEB4C7C-1641-4a7b-BC6D-1964E2099497)]
interface nsICryptoHMAC : nsISupports
{
/**
* Hashing Algorithms. These values are to be used by the |init| method to
* indicate which hashing function to use. These values map onto the values
* defined in mozilla/security/nss/lib/softoken/pkcs11t.h and are switched
* to a CKM_*_HMAC constant.
*/
// 1 used to mean MD2.
const short MD5 = 2;
const short SHA1 = 3;
const short SHA256 = 4;
const short SHA384 = 5;
const short SHA512 = 6;
/**
* Initialize the hashing object. This method may be
* called multiple times with different algorithm types.
*
* @param aAlgorithm the algorithm type to be used.
* This value must be one of the above valid
* algorithm types.
*
* @param aKeyObject
* Object holding a key. To create the key object use for instance:
* var keyObject = Components.classes["@mozilla.org/security/keyobjectfactory;1"]
* .getService(Components.interfaces.nsIKeyObjectFactory)
* .keyFromString(Components.interfaces.nsIKeyObject.HMAC, rawKeyData);
*
* WARNING: This approach is not FIPS compliant.
*
* @throws NS_ERROR_INVALID_ARG if an unsupported algorithm
* type is passed.
*
* NOTE: This method must be called before any other method on this
* interface is called.
*/
[must_use]
void init(in unsigned long aAlgorithm, in nsIKeyObject aKeyObject);
/**
* @param aData a buffer to calculate the hash over
*
* @param aLen the length of the buffer |aData|
*
* @throws NS_ERROR_NOT_INITIALIZED If |init| has not been called.
*/
[must_use]
void update([const, array, size_is(aLen)] in octet aData, in unsigned long aLen);
/**
* Calculates and updates a new hash based on a given data stream.
*
* @param aStream an input stream to read from.
*
* @param aLen How much to read from the given |aStream|. Passing UINT32_MAX
* indicates that all data available will be used to update the hash.
*
* @throws NS_ERROR_NOT_INITIALIZED If |init| has not been called.
*
* @throws NS_ERROR_NOT_AVAILABLE If the requested amount of data to be
* calculated into the hash is not available.
*
*/
[must_use]
void updateFromStream(in nsIInputStream aStream, in unsigned long aLen);
/**
* Completes this HMAC object and produces the actual HMAC digest data.
*
* @param aASCII If true then the returned value is a base64 encoded string.
* If false, then the returned value is binary data.
*
* @return a hash of the data that was read by this object. This can
* be either binary data or base 64 encoded.
*
* @throws NS_ERROR_NOT_INITIALIZED If |init| has not been called.
*
* NOTE: This method may be called any time after |init|
* is called. This call resets the object to its
* pre-init state.
*/
[must_use]
ACString finish(in boolean aASCII);
/**
* Reinitialize HMAC context to be reused with the same settings (the key
* and hash algorithm) but on a different set of data.
*/
[must_use]
void reset();
};

Просмотреть файл

@ -1,41 +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 "nsISupports.idl"
%{ C++
/* forward declaration */
typedef struct PK11SymKeyStr PK11SymKey;
%}
[ptr] native PK11SymKeyPtr(PK11SymKey);
// An opaque key object.
[scriptable, uuid(ee2dc516-ba7b-4e77-89fe-c43b886ef715)]
interface nsIKeyObject : nsISupports
{
// Key types
const short SYM_KEY = 1;
// Algorithm types
const short HMAC = 257;
// The nsIKeyObject will take ownership of the key and be responsible
// for freeing the key memory when destroyed.
[noscript, must_use]
void initKey(in short aAlgorithm, in PK11SymKeyPtr aKey);
// Returns a pointer to the underlying key object.
[noscript, must_use]
PK11SymKeyPtr getKeyObj();
[must_use]
short getType();
};
[scriptable, uuid(838bdbf1-8244-448f-8bcd-cede70227d75)]
interface nsIKeyObjectFactory : nsISupports
{
[must_use]
nsIKeyObject keyFromString(in short aAlgorithm, in ACString aKey);
};

Просмотреть файл

@ -1,102 +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 "nsCOMPtr.h"
#include "nsComponentManagerUtils.h"
#include "nsKeyModule.h"
#include "nsString.h"
using namespace mozilla;
using namespace mozilla::psm;
NS_IMPL_ISUPPORTS(nsKeyObject, nsIKeyObject)
nsKeyObject::nsKeyObject() : mSymKey(nullptr) {}
//////////////////////////////////////////////////////////////////////////////
// nsIKeyObject
NS_IMETHODIMP
nsKeyObject::InitKey(int16_t aAlgorithm, PK11SymKey* aKey) {
if (!aKey || aAlgorithm != nsIKeyObject::HMAC) {
return NS_ERROR_INVALID_ARG;
}
mSymKey.reset(aKey);
return NS_OK;
}
NS_IMETHODIMP
nsKeyObject::GetKeyObj(PK11SymKey** _retval) {
if (!_retval) {
return NS_ERROR_INVALID_ARG;
}
*_retval = nullptr;
if (!mSymKey) {
return NS_ERROR_NOT_INITIALIZED;
}
*_retval = mSymKey.get();
return NS_OK;
}
NS_IMETHODIMP
nsKeyObject::GetType(int16_t* _retval) {
if (!_retval) {
return NS_ERROR_INVALID_ARG;
}
*_retval = nsIKeyObject::SYM_KEY;
return NS_OK;
}
//////////////////////////////////////////////////////////////////////////////
// nsIKeyObjectFactory
NS_IMPL_ISUPPORTS(nsKeyObjectFactory, nsIKeyObjectFactory)
NS_IMETHODIMP
nsKeyObjectFactory::KeyFromString(int16_t aAlgorithm, const nsACString& aKey,
nsIKeyObject** _retval) {
if (!_retval || aAlgorithm != nsIKeyObject::HMAC) {
return NS_ERROR_INVALID_ARG;
}
CK_MECHANISM_TYPE cipherMech = CKM_GENERIC_SECRET_KEY_GEN;
CK_ATTRIBUTE_TYPE cipherOperation = CKA_SIGN;
nsresult rv;
nsCOMPtr<nsIKeyObject> key(
do_CreateInstance(NS_KEYMODULEOBJECT_CONTRACTID, &rv));
if (NS_FAILED(rv)) {
return rv;
}
// Convert the raw string into a SECItem
const nsCString& flatKey = PromiseFlatCString(aKey);
SECItem keyItem;
keyItem.data = (unsigned char*)flatKey.get();
keyItem.len = flatKey.Length();
UniquePK11SlotInfo slot(PK11_GetBestSlot(cipherMech, nullptr));
if (!slot) {
return NS_ERROR_FAILURE;
}
UniquePK11SymKey symKey(PK11_ImportSymKey(slot.get(), cipherMech,
PK11_OriginUnwrap, cipherOperation,
&keyItem, nullptr));
if (!symKey) {
return NS_ERROR_FAILURE;
}
rv = key->InitKey(aAlgorithm, symKey.release());
if (NS_FAILED(rv)) {
return rv;
}
key.swap(*_retval);
return NS_OK;
}

Просмотреть файл

@ -1,59 +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 nsKeyModule_h
#define nsKeyModule_h
#include "ScopedNSSTypes.h"
#include "nsIKeyModule.h"
#include "pk11pub.h"
#define NS_KEYMODULEOBJECT_CID \
{ \
0x9d383ddd, 0x6856, 0x4187, { \
0x84, 0x85, 0xf3, 0x61, 0x95, 0xb2, 0x9a, 0x0e \
} \
}
#define NS_KEYMODULEOBJECT_CONTRACTID "@mozilla.org/security/keyobject;1"
#define NS_KEYMODULEOBJECTFACTORY_CID \
{ \
0x2a35dd47, 0xb026, 0x4e8d, { \
0xb6, 0xb7, 0x57, 0x40, 0xf6, 0x1a, 0xb9, 0x02 \
} \
}
#define NS_KEYMODULEOBJECTFACTORY_CONTRACTID \
"@mozilla.org/security/keyobjectfactory;1"
class nsKeyObject final : public nsIKeyObject {
public:
nsKeyObject();
NS_DECL_ISUPPORTS
NS_DECL_NSIKEYOBJECT
private:
~nsKeyObject() = default;
// Disallow copy constructor
nsKeyObject(nsKeyObject&);
mozilla::UniquePK11SymKey mSymKey;
};
class nsKeyObjectFactory final : public nsIKeyObjectFactory {
public:
nsKeyObjectFactory() = default;
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIKEYOBJECTFACTORY
private:
~nsKeyObjectFactory() = default;
// Disallow copy constructor
nsKeyObjectFactory(nsKeyObjectFactory&);
};
#endif // nsKeyModule_h

Просмотреть файл

@ -49,10 +49,10 @@ UniqueCERTCertList FindClientCertificatesWithPrivateKeys();
} \
}
extern bool EnsureNSSInitializedChromeOrContent();
extern bool HandleTLSPrefChange(const nsCString& aPref);
extern void SetValidationOptionsCommon();
extern void NSSShutdownForSocketProcess();
bool EnsureNSSInitializedChromeOrContent();
bool HandleTLSPrefChange(const nsCString& aPref);
void SetValidationOptionsCommon();
void NSSShutdownForSocketProcess();
// Implementation of the PSM component interface.
class nsNSSComponent final : public nsINSSComponent, public nsIObserver {

Просмотреть файл

@ -18,7 +18,6 @@
#include "mozilla/SyncRunnable.h"
#include "nsCURILoader.h"
#include "nsCryptoHash.h"
#include "nsKeyModule.h"
#include "nsNSSCertificate.h"
#include "nsNSSCertificateDB.h"
#include "nsNSSComponent.h"
@ -114,9 +113,6 @@ IMPL(nsNSSCertificate, nullptr, ProcessRestriction::AnyProcess)
IMPL(nsNSSCertificateDB, nullptr)
IMPL(nsCertTree, nullptr)
IMPL(nsCryptoHash, nullptr, ProcessRestriction::AnyProcess)
IMPL(nsCryptoHMAC, nullptr, ProcessRestriction::AnyProcess)
IMPL(nsKeyObject, nullptr, ProcessRestriction::AnyProcess)
IMPL(nsKeyObjectFactory, nullptr, ProcessRestriction::AnyProcess)
IMPL(ContentSignatureVerifier, nullptr)
IMPL(nsRandomGenerator, nullptr, ProcessRestriction::AnyProcess)
IMPL(TransportSecurityInfo, nullptr, ProcessRestriction::AnyProcess)

Просмотреть файл

@ -22,10 +22,7 @@
#include "mozilla/Telemetry.h"
#include "nsCOMPtr.h"
#include "nsComponentManagerUtils.h"
#include "nsICryptoHMAC.h"
#include "nsICryptoHash.h"
#include "nsIKeyModule.h"
#include "nsKeyModule.h"
#include "nsNativeCharsetUtils.h"
#include "nsNetCID.h"
#include "nsUnicharUtils.h"
@ -596,10 +593,6 @@ static nsresult GenerateType3Msg(const nsString& domain,
if (ntlmv2) {
// NTLMv2 mode, the default
nsString userUpper, domainUpper;
nsAutoCString ntlmHashStr;
nsAutoCString ntlmv2HashStr;
nsAutoCString lmv2ResponseStr;
nsAutoCString ntlmv2ResponseStr;
// temporary buffers for unicode strings
nsAutoString ucsDomainUpperBuf;
@ -632,49 +625,24 @@ static nsresult GenerateType3Msg(const nsString& domain,
#endif
NTLM_Hash(password, ntlmHash);
ntlmHashStr = nsAutoCString(
mozilla::BitwiseCast<const char*, const uint8_t*>(ntlmHash),
NTLM_HASH_LEN);
nsCOMPtr<nsIKeyObjectFactory> keyFactory =
do_CreateInstance(NS_KEYMODULEOBJECTFACTORY_CONTRACTID, &rv);
HMAC ntlmv2HashHmac;
rv = ntlmv2HashHmac.Begin(SEC_OID_MD5, Span(ntlmHash, NTLM_HASH_LEN));
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsIKeyObject> ntlmKey =
do_CreateInstance(NS_KEYMODULEOBJECT_CONTRACTID, &rv);
rv = ntlmv2HashHmac.Update(static_cast<const uint8_t*>(userUpperPtr),
userUpperLen);
if (NS_FAILED(rv)) {
return rv;
}
rv = keyFactory->KeyFromString(nsIKeyObject::HMAC, ntlmHashStr,
getter_AddRefs(ntlmKey));
rv = ntlmv2HashHmac.Update(static_cast<const uint8_t*>(domainUpperPtr),
domainUpperLen);
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsICryptoHMAC> hasher =
do_CreateInstance(NS_CRYPTO_HMAC_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
return rv;
}
rv = hasher->Init(nsICryptoHMAC::MD5, ntlmKey);
if (NS_FAILED(rv)) {
return rv;
}
rv =
hasher->Update(static_cast<const uint8_t*>(userUpperPtr), userUpperLen);
if (NS_FAILED(rv)) {
return rv;
}
rv = hasher->Update(static_cast<const uint8_t*>(domainUpperPtr),
domainUpperLen);
if (NS_FAILED(rv)) {
return rv;
}
rv = hasher->Finish(false, ntlmv2HashStr);
nsTArray<uint8_t> ntlmv2Hash;
rv = ntlmv2HashHmac.End(ntlmv2Hash);
if (NS_FAILED(rv)) {
return rv;
}
@ -682,41 +650,30 @@ static nsresult GenerateType3Msg(const nsString& domain,
uint8_t client_random[NTLM_CHAL_LEN];
PK11_GenerateRandom(client_random, NTLM_CHAL_LEN);
nsCOMPtr<nsIKeyObject> ntlmv2Key =
do_CreateInstance(NS_KEYMODULEOBJECT_CONTRACTID, &rv);
HMAC lmv2ResponseHmac;
rv = lmv2ResponseHmac.Begin(SEC_OID_MD5, Span(ntlmv2Hash));
if (NS_FAILED(rv)) {
return rv;
}
rv = lmv2ResponseHmac.Update(msg.challenge, NTLM_CHAL_LEN);
if (NS_FAILED(rv)) {
return rv;
}
rv = lmv2ResponseHmac.Update(client_random, NTLM_CHAL_LEN);
if (NS_FAILED(rv)) {
return rv;
}
nsTArray<uint8_t> lmv2Response;
rv = lmv2ResponseHmac.End(lmv2Response);
if (NS_FAILED(rv)) {
return rv;
}
// Prepare the LMv2 response
rv = keyFactory->KeyFromString(nsIKeyObject::HMAC, ntlmv2HashStr,
getter_AddRefs(ntlmv2Key));
if (NS_FAILED(rv)) {
return rv;
}
rv = hasher->Init(nsICryptoHMAC::MD5, ntlmv2Key);
if (NS_FAILED(rv)) {
return rv;
}
rv = hasher->Update(msg.challenge, NTLM_CHAL_LEN);
if (NS_FAILED(rv)) {
return rv;
}
rv = hasher->Update(client_random, NTLM_CHAL_LEN);
if (NS_FAILED(rv)) {
return rv;
}
rv = hasher->Finish(false, lmv2ResponseStr);
if (NS_FAILED(rv)) {
return rv;
}
if (lmv2ResponseStr.Length() != NTLMv2_HASH_LEN) {
if (lmv2Response.Length() != NTLMv2_HASH_LEN) {
return NS_ERROR_UNEXPECTED;
}
memcpy(lmResp, lmv2ResponseStr.get(), NTLMv2_HASH_LEN);
memcpy(lmResp, lmv2Response.Elements(), NTLMv2_HASH_LEN);
memcpy(lmResp + NTLMv2_HASH_LEN, client_random, NTLM_CHAL_LEN);
memset(ntlmv2_blob1, 0, NTLMv2_BLOB1_LEN);
@ -731,32 +688,34 @@ static nsresult GenerateType3Msg(const nsString& domain,
mozilla::LittleEndian::writeUint64(&ntlmv2_blob1[8], nt_time);
PK11_GenerateRandom(&ntlmv2_blob1[16], NTLM_CHAL_LEN);
rv = hasher->Init(nsICryptoHMAC::MD5, ntlmv2Key);
HMAC ntlmv2ResponseHmac;
rv = ntlmv2ResponseHmac.Begin(SEC_OID_MD5, Span(ntlmv2Hash));
if (NS_FAILED(rv)) {
return rv;
}
rv = hasher->Update(msg.challenge, NTLM_CHAL_LEN);
rv = ntlmv2ResponseHmac.Update(msg.challenge, NTLM_CHAL_LEN);
if (NS_FAILED(rv)) {
return rv;
}
rv = hasher->Update(ntlmv2_blob1, NTLMv2_BLOB1_LEN);
rv = ntlmv2ResponseHmac.Update(ntlmv2_blob1, NTLMv2_BLOB1_LEN);
if (NS_FAILED(rv)) {
return rv;
}
rv = hasher->Update(msg.targetInfo, msg.targetInfoLen);
rv = ntlmv2ResponseHmac.Update(msg.targetInfo, msg.targetInfoLen);
if (NS_FAILED(rv)) {
return rv;
}
rv = hasher->Finish(false, ntlmv2ResponseStr);
nsTArray<uint8_t> ntlmv2Response;
rv = ntlmv2ResponseHmac.End(ntlmv2Response);
if (NS_FAILED(rv)) {
return rv;
}
if (ntlmv2ResponseStr.Length() != NTLMv2_RESP_LEN) {
if (ntlmv2Response.Length() != NTLMv2_RESP_LEN) {
return NS_ERROR_UNEXPECTED;
}
memcpy(ntlmv2Resp, ntlmv2ResponseStr.get(), NTLMv2_RESP_LEN);
memcpy(ntlmv2Resp, ntlmv2Response.Elements(), NTLMv2_RESP_LEN);
ntlmRespLen = NTLMv2_RESP_LEN + NTLMv2_BLOB1_LEN;
ntlmRespLen += msg.targetInfoLen;
if (!ntlmRespLen.isValid()) {

Просмотреть файл

@ -0,0 +1,63 @@
#include <string>
#include "gtest/gtest.h"
#include "ScopedNSSTypes.h"
#include "mozilla/Span.h"
#include "nss.h"
#include "secoidt.h"
// From RFC 2202
const unsigned char kTestKey[] = "Jefe";
const unsigned char kTestInput[] = "what do ya want for nothing?";
struct HMACTestCase {
SECOidTag hashAlg;
std::basic_string<uint8_t> expectedOutput;
};
#define EXPECTED_RESULT(val) \
std::basic_string<uint8_t>(reinterpret_cast<const uint8_t*>(val), \
sizeof(val) - 1)
static const HMACTestCase HMACTestCases[] = {
{
SEC_OID_MD5,
EXPECTED_RESULT(
"\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38"),
},
{
SEC_OID_SHA256,
EXPECTED_RESULT(
"\x5b\xdc\xc1\x46\xbf\x60\x75\x4e\x6a\x04\x24\x26\x08\x95\x75\xc7"
"\x5a\x00\x3f\x08\x9d\x27\x39\x83\x9d\xec\x58\xb9\x64\xec\x38\x43"),
},
};
#undef EXPECTED_RESULT
class psm_HMAC : public ::testing::Test,
public ::testing::WithParamInterface<HMACTestCase> {
public:
void SetUp() override { NSS_NoDB_Init(nullptr); }
};
TEST_P(psm_HMAC, Test) {
mozilla::HMAC hmac;
const HMACTestCase& testCase(GetParam());
nsresult rv = hmac.Begin(testCase.hashAlg,
mozilla::Span(kTestKey, sizeof(kTestKey) - 1));
ASSERT_TRUE(NS_SUCCEEDED(rv));
rv = hmac.Update(reinterpret_cast<const unsigned char*>(kTestInput),
sizeof(kTestInput) - 1);
ASSERT_TRUE(NS_SUCCEEDED(rv));
nsTArray<uint8_t> output;
rv = hmac.End(output);
ASSERT_TRUE(NS_SUCCEEDED(rv));
EXPECT_EQ(output.Length(), testCase.expectedOutput.length());
for (size_t i = 0; i < output.Length(); i++) {
EXPECT_EQ(output[i], testCase.expectedOutput[i]);
}
}
INSTANTIATE_TEST_SUITE_P(psm_HMAC, psm_HMAC,
::testing::ValuesIn(HMACTestCases));

Просмотреть файл

@ -9,6 +9,7 @@ SOURCES += [
"CoseTest.cpp",
"DataStorageTest.cpp",
"DeserializeCertTest.cpp",
"HMACTest.cpp",
"MD4Test.cpp",
"OCSPCacheTest.cpp",
"TLSIntoleranceTest.cpp",

Просмотреть файл

@ -1,157 +0,0 @@
"use strict";
// This file tests various aspects of the nsICryptoHMAC implementation for all
// of the supported algorithms.
function getHMAC(data, key, alg, returnBase64) {
let converter = Cc[
"@mozilla.org/intl/scriptableunicodeconverter"
].createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "utf8";
let dataArray = converter.convertToByteArray(data);
let keyObject = Cc["@mozilla.org/security/keyobjectfactory;1"]
.getService(Ci.nsIKeyObjectFactory)
.keyFromString(Ci.nsIKeyObject.HMAC, key);
let cryptoHMAC = Cc["@mozilla.org/security/hmac;1"].createInstance(
Ci.nsICryptoHMAC
);
cryptoHMAC.init(alg, keyObject);
cryptoHMAC.update(dataArray, dataArray.length);
let digest1 = cryptoHMAC.finish(returnBase64);
cryptoHMAC.reset();
cryptoHMAC.update(dataArray, dataArray.length);
let digest2 = cryptoHMAC.finish(returnBase64);
let stream = converter.convertToInputStream(data);
cryptoHMAC.reset();
cryptoHMAC.updateFromStream(stream, stream.available());
let digestFromStream = cryptoHMAC.finish(returnBase64);
equal(
digest1,
digest2,
"Initial digest and digest after calling reset() should match"
);
equal(
digest1,
digestFromStream,
"Digest from buffer and digest from stream should match"
);
return digest1;
}
function testHMAC(alg) {
const key1 = "MyKey_ABCDEFGHIJKLMN";
const key2 = "MyKey_01234567890123";
const dataA = "Secret message";
const dataB = "Secres message";
let digest1a = getHMAC(key1, dataA, alg, false);
let digest2 = getHMAC(key2, dataA, alg, false);
let digest1b = getHMAC(key1, dataA, alg, false);
equal(
digest1a,
digest1b,
"The digests for the same key, data and algorithm should match"
);
notEqual(
digest1a,
digest2,
"The digests for different keys should not match"
);
let digest1 = getHMAC(key1, dataA, alg, false);
digest2 = getHMAC(key1, dataB, alg, false);
notEqual(digest1, digest2, "The digests for different data should not match");
}
function testVectors() {
const keyTestVector = "Jefe";
const dataTestVector = "what do ya want for nothing?";
// The base 64 values aren't in either of the RFCs below; they were just
// calculated using the hex vectors.
const vectors = [
// RFC 2202 section 2 test case 2.
{
algoID: Ci.nsICryptoHMAC.MD5,
algoName: "MD5",
expectedDigest: "750c783e6ab0b503eaa86e310a5db738",
expectedBase64: "dQx4PmqwtQPqqG4xCl23OA==",
},
// RFC 2202 section 2 test case 3.
{
algoID: Ci.nsICryptoHMAC.SHA1,
algoName: "SHA-1",
expectedDigest: "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79",
expectedBase64: "7/zfauXrL6LSdBbV8YTfnCWafHk=",
},
// RFC 4231 section 4.3.
{
algoID: Ci.nsICryptoHMAC.SHA256,
algoName: "SHA-256",
expectedDigest:
"5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843",
expectedBase64: "W9zBRr9gdU5qBCQmCJV1x1oAPwidJzmDnexYuWTsOEM=",
},
{
algoID: Ci.nsICryptoHMAC.SHA384,
algoName: "SHA-384",
expectedDigest:
"af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649",
expectedBase64:
"r0XS43ZIQDFhf3jStYprG5x+9GT1oBtH5C7Dc2MiRF6OIkDKXmnix4syOez6shZJ",
},
{
algoID: Ci.nsICryptoHMAC.SHA512,
algoName: "SHA-512",
expectedDigest:
"164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737",
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);
equal(
b64Digest,
vector.expectedBase64,
`Actual and expected ${vector.algoName} base64 digest should match`
);
}
}
function run_test() {
testVectors();
testHMAC(Ci.nsICryptoHMAC.MD5);
testHMAC(Ci.nsICryptoHMAC.SHA1);
testHMAC(Ci.nsICryptoHMAC.SHA256);
testHMAC(Ci.nsICryptoHMAC.SHA384);
testHMAC(Ci.nsICryptoHMAC.SHA512);
// Our buffer size for working with streams is 4096 bytes. This tests we
// handle larger inputs.
let digest = getHMAC(" ".repeat(4100), "test", Ci.nsICryptoHMAC.MD5, false);
equal(
hexify(digest),
"befbc875f73a088cf04e77f2b1286010",
"Actual and expected digest for large stream should match"
);
}

Просмотреть файл

@ -140,7 +140,6 @@ run-sequentially = hardcoded ports
[test_hash_algorithms_wrap.js]
# bug 1124289 - run_test_in_child violates the sandbox on android
skip-if = toolkit == 'android'
[test_hmac.js]
[test_intermediate_basic_usage_constraints.js]
[test_intermediate_preloads.js]
run-sequentially = hardcoded ports