зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1260318 - Scope U2F Soft Tokens to a single AppID r=qdot,rbarnes
This change includes the FIDO "App ID" as part of the function used to generate the wrapping key used in the NSS-based U2F soft token, cryptographically binding the "Key Handle" to the site that Key Handle is intended for. This is a breaking change with existing registered U2F keys, but since our soft token is hidden behind a pref, it does not attempt to be backward-compatible. - Updated for rbarnes' and qdot's reviews comments. Thanks! - Made more strict in size restrictions, and added a version field to help us be this strict. - Bugfix for an early unprotected buffer use (Thanks again rbarnes!) MozReview-Commit-ID: Jf6gNPauT4Y --HG-- extra : rebase_source : 52d10287d10698292e1480e04f580f6f8b4847cb
This commit is contained in:
Родитель
09bc17720b
Коммит
8effd5c124
|
@ -3435,6 +3435,7 @@ ContentParent::RecvNSSU2FTokenIsCompatibleVersion(const nsString& aVersion,
|
|||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvNSSU2FTokenIsRegistered(nsTArray<uint8_t>&& aKeyHandle,
|
||||
nsTArray<uint8_t>&& aApplication,
|
||||
bool* aIsValidKeyHandle)
|
||||
{
|
||||
MOZ_ASSERT(aIsValidKeyHandle);
|
||||
|
@ -3445,6 +3446,7 @@ ContentParent::RecvNSSU2FTokenIsRegistered(nsTArray<uint8_t>&& aKeyHandle,
|
|||
}
|
||||
|
||||
nsresult rv = nssToken->IsRegistered(aKeyHandle.Elements(), aKeyHandle.Length(),
|
||||
aApplication.Elements(), aApplication.Length(),
|
||||
aIsValidKeyHandle);
|
||||
if (NS_FAILED(rv)) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
|
|
|
@ -803,6 +803,7 @@ private:
|
|||
bool* aIsCompatible) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvNSSU2FTokenIsRegistered(nsTArray<uint8_t>&& aKeyHandle,
|
||||
nsTArray<uint8_t>&& aApplication,
|
||||
bool* aIsValidKeyHandle) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvNSSU2FTokenRegister(nsTArray<uint8_t>&& aApplication,
|
||||
|
|
|
@ -766,9 +766,10 @@ parent:
|
|||
* Return whether the provided KeyHandle belongs to this Token
|
||||
*
|
||||
* |keyHandle| Key Handle to evaluate.
|
||||
* |application| The FIDO Application data that is associated with this key.
|
||||
* Returns |True| if the Key Handle is ours.
|
||||
*/
|
||||
sync NSSU2FTokenIsRegistered(uint8_t[] keyHandle)
|
||||
sync NSSU2FTokenIsRegistered(uint8_t[] keyHandle, uint8_t[] application)
|
||||
returns (bool isValidKeyHandle);
|
||||
|
||||
/**
|
||||
|
|
|
@ -211,9 +211,11 @@ U2FPrepTask::Execute()
|
|||
|
||||
U2FIsRegisteredTask::U2FIsRegisteredTask(const Authenticator& aAuthenticator,
|
||||
const LocalRegisteredKey& aRegisteredKey,
|
||||
const CryptoBuffer& aAppParam,
|
||||
AbstractThread* aMainThread)
|
||||
: U2FPrepTask(aAuthenticator, aMainThread)
|
||||
, mRegisteredKey(aRegisteredKey)
|
||||
, mAppParam(aAppParam)
|
||||
{}
|
||||
|
||||
U2FIsRegisteredTask::~U2FIsRegisteredTask()
|
||||
|
@ -248,6 +250,7 @@ U2FIsRegisteredTask::Run()
|
|||
|
||||
bool isRegistered = false;
|
||||
rv = mAuthenticator->IsRegistered(keyHandle.Elements(), keyHandle.Length(),
|
||||
mAppParam.Elements(), mAppParam.Length(),
|
||||
&isRegistered);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mPromise.Reject(ErrorCode::OTHER_ERROR, __func__);
|
||||
|
@ -378,6 +381,7 @@ U2FSignTask::Run()
|
|||
|
||||
bool isRegistered = false;
|
||||
rv = mAuthenticator->IsRegistered(mKeyHandle.Elements(), mKeyHandle.Length(),
|
||||
mAppParam.Elements(), mAppParam.Length(),
|
||||
&isRegistered);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mPromise.Reject(ErrorCode::OTHER_ERROR, __func__);
|
||||
|
@ -618,13 +622,30 @@ U2FRegisterRunnable::Run()
|
|||
status->Stop(appIdResult);
|
||||
}
|
||||
|
||||
// Produce the AppParam from the current AppID
|
||||
nsCString cAppId = NS_ConvertUTF16toUTF8(mAppId);
|
||||
CryptoBuffer appParam;
|
||||
if (!appParam.SetLength(SHA256_LENGTH, fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Note: This could use nsICryptoHash to avoid having to interact with NSS
|
||||
// directly.
|
||||
SECStatus srv;
|
||||
srv = PK11_HashBuf(SEC_OID_SHA256, appParam.Elements(),
|
||||
reinterpret_cast<const uint8_t*>(cAppId.BeginReading()),
|
||||
cAppId.Length());
|
||||
if (srv != SECSuccess) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// First, we must determine if any of the RegisteredKeys are already
|
||||
// registered, e.g., in the whitelist.
|
||||
for (LocalRegisteredKey key : mRegisteredKeys) {
|
||||
nsTArray<RefPtr<U2FPrepPromise>> prepPromiseList;
|
||||
for (const Authenticator& token : mAuthenticators) {
|
||||
RefPtr<U2FIsRegisteredTask> compTask =
|
||||
new U2FIsRegisteredTask(token, key, mAbstractMainThread);
|
||||
new U2FIsRegisteredTask(token, key, appParam, mAbstractMainThread);
|
||||
prepPromiseList.AppendElement(compTask->Execute());
|
||||
}
|
||||
|
||||
|
@ -668,23 +689,6 @@ U2FRegisterRunnable::Run()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// Since we're continuing, we hash the AppID into the AppParam
|
||||
nsCString cAppId = NS_ConvertUTF16toUTF8(mAppId);
|
||||
CryptoBuffer appParam;
|
||||
if (!appParam.SetLength(SHA256_LENGTH, fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Note: This could use nsICryptoHash to avoid having to interact with NSS
|
||||
// directly.
|
||||
SECStatus srv;
|
||||
srv = PK11_HashBuf(SEC_OID_SHA256, appParam.Elements(),
|
||||
reinterpret_cast<const uint8_t*>(cAppId.BeginReading()),
|
||||
cAppId.Length());
|
||||
if (srv != SECSuccess) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Now proceed to actually register a new key.
|
||||
for (LocalRegisterRequest req : mRegisterRequests) {
|
||||
// Hash the ClientData into the ChallengeParam
|
||||
|
|
|
@ -86,6 +86,7 @@ class U2FIsRegisteredTask final : public U2FPrepTask
|
|||
public:
|
||||
U2FIsRegisteredTask(const Authenticator& aAuthenticator,
|
||||
const LocalRegisteredKey& aRegisteredKey,
|
||||
const CryptoBuffer& aAppParam,
|
||||
AbstractThread* aMainThread);
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
@ -93,6 +94,7 @@ private:
|
|||
~U2FIsRegisteredTask();
|
||||
|
||||
LocalRegisteredKey mRegisteredKey;
|
||||
CryptoBuffer mAppParam;
|
||||
};
|
||||
|
||||
class U2FTask : public Runnable
|
||||
|
|
|
@ -37,9 +37,11 @@ NSSU2FTokenRemote::IsCompatibleVersion(const nsAString& aVersionString,
|
|||
|
||||
NS_IMETHODIMP
|
||||
NSSU2FTokenRemote::IsRegistered(uint8_t* aKeyHandle, uint32_t aKeyHandleLen,
|
||||
uint8_t* aAppParam, uint32_t aAppParamLen,
|
||||
bool* aIsRegistered)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aKeyHandle);
|
||||
NS_ENSURE_ARG_POINTER(aAppParam);
|
||||
NS_ENSURE_ARG_POINTER(aIsRegistered);
|
||||
|
||||
nsTArray<uint8_t> keyHandle;
|
||||
|
@ -48,9 +50,15 @@ NSSU2FTokenRemote::IsRegistered(uint8_t* aKeyHandle, uint32_t aKeyHandleLen,
|
|||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsTArray<uint8_t> appParam;
|
||||
if (!appParam.ReplaceElementsAt(0, appParam.Length(), aAppParam,
|
||||
aAppParamLen)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
ContentChild* cc = ContentChild::GetSingleton();
|
||||
MOZ_ASSERT(cc);
|
||||
if (!cc->SendNSSU2FTokenIsRegistered(keyHandle, aIsRegistered)) {
|
||||
if (!cc->SendNSSU2FTokenIsRegistered(keyHandle, appParam, aIsRegistered)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
|
|
|
@ -380,7 +380,8 @@ WebAuthentication::U2FAuthMakeCredential(
|
|||
return;
|
||||
}
|
||||
|
||||
nsresult rv = aToken->IsRegistered(data, len, &isRegistered);
|
||||
nsresult rv = aToken->IsRegistered(data, len, aRpIdHash.Elements(),
|
||||
aRpIdHash.Length(), &isRegistered);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRequest->SetFailure(rv);
|
||||
return;
|
||||
|
@ -558,6 +559,8 @@ WebAuthentication::U2FAuthGetAssertion(const RefPtr<AssertionRequest>& aRequest,
|
|||
bool isRegistered = false;
|
||||
nsresult rv = aToken->IsRegistered(allowedCredential.Elements(),
|
||||
allowedCredential.Length(),
|
||||
aRpIdHash.Elements(),
|
||||
aRpIdHash.Length(),
|
||||
&isRegistered);
|
||||
|
||||
// 4.1.2.8.b If any authenticator returns a status indicating that the user
|
||||
|
|
|
@ -23,10 +23,13 @@ interface nsIU2FToken : nsISupports {
|
|||
* Return whether the provided KeyHandle belongs to this Token
|
||||
*
|
||||
* @param keyHandle Key Handle to evaluate.
|
||||
* @param application The FIDO Application data to associate with the key.
|
||||
* @return True if the Key Handle is ours.
|
||||
*/
|
||||
void isRegistered([array, size_is(keyHandleLen)] in octet keyHandle,
|
||||
in uint32_t keyHandleLen,
|
||||
[array, size_is(applicationLen)] in octet application,
|
||||
in uint32_t applicationLen,
|
||||
[retval] out boolean result);
|
||||
|
||||
/**
|
||||
|
|
|
@ -46,6 +46,8 @@ const uint32_t kParamLen = 32;
|
|||
const uint32_t kPublicKeyLen = 65;
|
||||
const uint32_t kWrappedKeyBufLen = 256;
|
||||
const uint32_t kWrappingKeyByteLen = 128/8;
|
||||
const uint32_t kSaltByteLen = 64/8;
|
||||
const uint32_t kVersion1KeyHandleLen = 162;
|
||||
NS_NAMED_LITERAL_STRING(kEcAlgorithm, WEBCRYPTO_NAMED_CURVE_P256);
|
||||
|
||||
const PRTime kOneDay = PRTime(PR_USEC_PER_SEC)
|
||||
|
@ -55,6 +57,10 @@ const PRTime kOneDay = PRTime(PR_USEC_PER_SEC)
|
|||
const PRTime kExpirationSlack = kOneDay; // Pre-date for clock skew
|
||||
const PRTime kExpirationLife = kOneDay;
|
||||
|
||||
enum SoftTokenHandle {
|
||||
Version1 = 0,
|
||||
};
|
||||
|
||||
static mozilla::LazyLogModule gNSSTokenLog("webauth_u2f");
|
||||
|
||||
nsNSSU2FToken::nsNSSU2FToken()
|
||||
|
@ -380,17 +386,48 @@ nsNSSU2FToken::Init()
|
|||
}
|
||||
|
||||
// Convert a Private Key object into an opaque key handle, using AES Key Wrap
|
||||
// and aWrappingKey to convert aPrivKey.
|
||||
// with the long-lived aPersistentKey mixed with aAppParam to convert aPrivKey.
|
||||
// The key handle's format is version || saltLen || salt || wrappedPrivateKey
|
||||
static UniqueSECItem
|
||||
KeyHandleFromPrivateKey(const UniquePK11SlotInfo& aSlot,
|
||||
const UniquePK11SymKey& aWrappingKey,
|
||||
const UniquePK11SymKey& aPersistentKey,
|
||||
uint8_t* aAppParam, uint32_t aAppParamLen,
|
||||
const UniqueSECKEYPrivateKey& aPrivKey,
|
||||
const nsNSSShutDownPreventionLock&)
|
||||
{
|
||||
MOZ_ASSERT(aSlot);
|
||||
MOZ_ASSERT(aWrappingKey);
|
||||
MOZ_ASSERT(aPersistentKey);
|
||||
MOZ_ASSERT(aAppParam);
|
||||
MOZ_ASSERT(aPrivKey);
|
||||
if (!aSlot || !aWrappingKey || !aPrivKey) {
|
||||
if (!aSlot || !aPersistentKey || !aPrivKey || !aAppParam) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Generate a random salt
|
||||
uint8_t saltParam[kSaltByteLen];
|
||||
SECStatus srv = PK11_GenerateRandomOnSlot(aSlot.get(), saltParam,
|
||||
sizeof(saltParam));
|
||||
if (srv != SECSuccess) {
|
||||
MOZ_LOG(gNSSTokenLog, LogLevel::Warning,
|
||||
("Failed to generate a salt, NSS error #%d", PORT_GetError()));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Prepare the HKDF (https://tools.ietf.org/html/rfc5869)
|
||||
CK_NSS_HKDFParams hkdfParams = { true, saltParam, sizeof(saltParam),
|
||||
true, aAppParam, aAppParamLen };
|
||||
SECItem kdfParams = { siBuffer, (unsigned char*)&hkdfParams,
|
||||
sizeof(hkdfParams) };
|
||||
|
||||
// Derive a wrapping key from aPersistentKey, the salt, and the aAppParam.
|
||||
// CKM_AES_KEY_GEN and CKA_WRAP are key type and usage attributes of the
|
||||
// derived symmetric key and don't matter because we ignore them anyway.
|
||||
UniquePK11SymKey wrapKey(PK11_Derive(aPersistentKey.get(), CKM_NSS_HKDF_SHA256,
|
||||
&kdfParams, CKM_AES_KEY_GEN, CKA_WRAP,
|
||||
kWrappingKeyByteLen));
|
||||
if (!wrapKey.get()) {
|
||||
MOZ_LOG(gNSSTokenLog, LogLevel::Warning,
|
||||
("Failed to derive a wrapping key, NSS error #%d", PORT_GetError()));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -398,46 +435,115 @@ KeyHandleFromPrivateKey(const UniquePK11SlotInfo& aSlot,
|
|||
/* no buffer */ nullptr,
|
||||
kWrappedKeyBufLen));
|
||||
if (!wrappedKey) {
|
||||
MOZ_LOG(gNSSTokenLog, LogLevel::Warning,
|
||||
("Failed to allocate memory, NSS error #%d", PORT_GetError()));
|
||||
MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to allocate memory"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UniqueSECItem param(PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP_PAD,
|
||||
/* default IV */ nullptr ));
|
||||
|
||||
SECStatus srv = PK11_WrapPrivKey(aSlot.get(), aWrappingKey.get(),
|
||||
aPrivKey.get(), CKM_NSS_AES_KEY_WRAP_PAD,
|
||||
param.get(), wrappedKey.get(),
|
||||
/* wincx */ nullptr);
|
||||
srv = PK11_WrapPrivKey(aSlot.get(), wrapKey.get(), aPrivKey.get(),
|
||||
CKM_NSS_AES_KEY_WRAP_PAD, param.get(), wrappedKey.get(),
|
||||
/* wincx */ nullptr);
|
||||
if (srv != SECSuccess) {
|
||||
MOZ_LOG(gNSSTokenLog, LogLevel::Warning,
|
||||
("Failed to wrap U2F key, NSS error #%d", PORT_GetError()));
|
||||
MOZ_LOG(gNSSTokenLog, LogLevel::Warning,
|
||||
("Failed to wrap U2F key, NSS error #%d", PORT_GetError()));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return wrappedKey;
|
||||
// Concatenate the salt and the wrapped Private Key together
|
||||
mozilla::dom::CryptoBuffer keyHandleBuf;
|
||||
if (!keyHandleBuf.SetCapacity(wrappedKey.get()->len + sizeof(saltParam) + 2,
|
||||
mozilla::fallible)) {
|
||||
MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to allocate memory"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// It's OK to ignore the return values here because we're writing into
|
||||
// pre-allocated space
|
||||
keyHandleBuf.AppendElement(SoftTokenHandle::Version1, mozilla::fallible);
|
||||
keyHandleBuf.AppendElement(sizeof(saltParam), mozilla::fallible);
|
||||
keyHandleBuf.AppendElements(saltParam, sizeof(saltParam), mozilla::fallible);
|
||||
keyHandleBuf.AppendSECItem(wrappedKey.get());
|
||||
|
||||
UniqueSECItem keyHandle(SECITEM_AllocItem(/* default arena */ nullptr,
|
||||
/* no buffer */ nullptr,
|
||||
keyHandleBuf.Length()));
|
||||
if (!keyHandle) {
|
||||
MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to allocate memory"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// This can't fail, as it's pre-allocated above, but be careful
|
||||
if (!keyHandleBuf.ToSECItem(/* default arena */ nullptr, keyHandle.get())) {
|
||||
MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to allocate memory"));
|
||||
return nullptr;
|
||||
}
|
||||
return keyHandle;
|
||||
}
|
||||
|
||||
// Convert an opaque key handle aKeyHandle back into a Private Key object, using
|
||||
// aWrappingKey and the AES Key Wrap algorithm.
|
||||
// the long-lived aPersistentKey mixed with aAppParam and the AES Key Wrap
|
||||
// algorithm.
|
||||
static UniqueSECKEYPrivateKey
|
||||
PrivateKeyFromKeyHandle(const UniquePK11SlotInfo& aSlot,
|
||||
const UniquePK11SymKey& aWrappingKey,
|
||||
const UniquePK11SymKey& aPersistentKey,
|
||||
uint8_t* aKeyHandle, uint32_t aKeyHandleLen,
|
||||
uint8_t* aAppParam, uint32_t aAppParamLen,
|
||||
const nsNSSShutDownPreventionLock&)
|
||||
{
|
||||
MOZ_ASSERT(aSlot);
|
||||
MOZ_ASSERT(aWrappingKey);
|
||||
MOZ_ASSERT(aPersistentKey);
|
||||
MOZ_ASSERT(aKeyHandle);
|
||||
if (!aSlot || !aWrappingKey || !aKeyHandle) {
|
||||
MOZ_ASSERT(aAppParam);
|
||||
MOZ_ASSERT(aAppParamLen == SHA256_LENGTH);
|
||||
if (!aSlot || !aPersistentKey || !aKeyHandle || !aAppParam ||
|
||||
aAppParamLen != SHA256_LENGTH) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ScopedAutoSECItem pubKey(kPublicKeyLen);
|
||||
// As we only support one key format ourselves (right now), fail early if
|
||||
// we aren't that length
|
||||
if (aKeyHandleLen != kVersion1KeyHandleLen) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ScopedAutoSECItem keyHandleItem(aKeyHandleLen);
|
||||
memcpy(keyHandleItem.data, aKeyHandle, keyHandleItem.len);
|
||||
if (aKeyHandle[0] != SoftTokenHandle::Version1) {
|
||||
// Unrecognized version
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint8_t saltLen = aKeyHandle[1];
|
||||
uint8_t* saltPtr = aKeyHandle + 2;
|
||||
if (saltLen != kSaltByteLen) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Prepare the HKDF (https://tools.ietf.org/html/rfc5869)
|
||||
CK_NSS_HKDFParams hkdfParams = { true, saltPtr, saltLen,
|
||||
true, aAppParam, aAppParamLen };
|
||||
SECItem kdfParams = { siBuffer, (unsigned char*)&hkdfParams,
|
||||
sizeof(hkdfParams) };
|
||||
|
||||
// Derive a wrapping key from aPersistentKey, the salt, and the aAppParam.
|
||||
// CKM_AES_KEY_GEN and CKA_WRAP are key type and usage attributes of the
|
||||
// derived symmetric key and don't matter because we ignore them anyway.
|
||||
UniquePK11SymKey wrapKey(PK11_Derive(aPersistentKey.get(), CKM_NSS_HKDF_SHA256,
|
||||
&kdfParams, CKM_AES_KEY_GEN, CKA_WRAP,
|
||||
kWrappingKeyByteLen));
|
||||
if (!wrapKey.get()) {
|
||||
MOZ_LOG(gNSSTokenLog, LogLevel::Warning,
|
||||
("Failed to derive a wrapping key, NSS error #%d", PORT_GetError()));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint8_t wrappedLen = aKeyHandleLen - saltLen - 2;
|
||||
uint8_t* wrappedPtr = aKeyHandle + saltLen + 2;
|
||||
|
||||
ScopedAutoSECItem wrappedKeyItem(wrappedLen);
|
||||
memcpy(wrappedKeyItem.data, wrappedPtr, wrappedKeyItem.len);
|
||||
|
||||
ScopedAutoSECItem pubKey(kPublicKeyLen);
|
||||
|
||||
UniqueSECItem param(PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP_PAD,
|
||||
/* default IV */ nullptr ));
|
||||
|
@ -446,8 +552,8 @@ PrivateKeyFromKeyHandle(const UniquePK11SlotInfo& aSlot,
|
|||
int usageCount = 1;
|
||||
|
||||
UniqueSECKEYPrivateKey unwrappedKey(
|
||||
PK11_UnwrapPrivKey(aSlot.get(), aWrappingKey.get(), CKM_NSS_AES_KEY_WRAP_PAD,
|
||||
param.get(), &keyHandleItem,
|
||||
PK11_UnwrapPrivKey(aSlot.get(), wrapKey.get(), CKM_NSS_AES_KEY_WRAP_PAD,
|
||||
param.get(), &wrappedKeyItem,
|
||||
/* no nickname */ nullptr,
|
||||
/* discard pubkey */ &pubKey,
|
||||
/* not permanent */ false,
|
||||
|
@ -477,9 +583,11 @@ nsNSSU2FToken::IsCompatibleVersion(const nsAString& aVersion, bool* aResult)
|
|||
// IsRegistered determines if the provided key handle is usable by this token.
|
||||
NS_IMETHODIMP
|
||||
nsNSSU2FToken::IsRegistered(uint8_t* aKeyHandle, uint32_t aKeyHandleLen,
|
||||
uint8_t* aAppParam, uint32_t aAppParamLen,
|
||||
bool* aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aKeyHandle);
|
||||
NS_ENSURE_ARG_POINTER(aAppParam);
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
|
||||
if (!NS_IsMainThread()) {
|
||||
|
@ -504,6 +612,8 @@ nsNSSU2FToken::IsRegistered(uint8_t* aKeyHandle, uint32_t aKeyHandleLen,
|
|||
UniqueSECKEYPrivateKey privKey = PrivateKeyFromKeyHandle(slot, mWrappingKey,
|
||||
aKeyHandle,
|
||||
aKeyHandleLen,
|
||||
aAppParam,
|
||||
aAppParamLen,
|
||||
locker);
|
||||
*aResult = (privKey.get() != nullptr);
|
||||
return NS_OK;
|
||||
|
@ -583,6 +693,8 @@ nsNSSU2FToken::Register(uint8_t* aApplication,
|
|||
|
||||
// The key handle will be the result of keywrap(privKey, key=mWrappingKey)
|
||||
UniqueSECItem keyHandleItem = KeyHandleFromPrivateKey(slot, mWrappingKey,
|
||||
aApplication,
|
||||
aApplicationLen,
|
||||
privKey, locker);
|
||||
if (!keyHandleItem.get()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -695,6 +807,8 @@ nsNSSU2FToken::Sign(uint8_t* aApplication, uint32_t aApplicationLen,
|
|||
UniqueSECKEYPrivateKey privKey = PrivateKeyFromKeyHandle(slot, mWrappingKey,
|
||||
aKeyHandle,
|
||||
aKeyHandleLen,
|
||||
aApplication,
|
||||
aApplicationLen,
|
||||
locker);
|
||||
if (!privKey.get()) {
|
||||
MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Couldn't get the priv key!"));
|
||||
|
|
Загрузка…
Ссылка в новой задаче