зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
351b6fd7fb
Коммит
fb67326470
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче