Bug 1838938 - Remove U2FSoftTokenTransport. r=keeler

Depends on D181302

Differential Revision: https://phabricator.services.mozilla.com/D181301
This commit is contained in:
John Schanck 2023-08-09 20:47:55 +00:00
Родитель 5f8b0f5223
Коммит 22d1d1cb02
11 изменённых файлов: 0 добавлений и 1614 удалений

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

@ -1,82 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "CtapResults.h"
namespace mozilla::dom {
NS_IMPL_ISUPPORTS(CtapRegisterResult, nsICtapRegisterResult)
NS_IMETHODIMP
CtapRegisterResult::GetStatus(nsresult* aStatus) {
*aStatus = mStatus;
return NS_OK;
}
NS_IMETHODIMP
CtapRegisterResult::GetAttestationObject(
nsTArray<uint8_t>& aAttestationObject) {
aAttestationObject.Clear();
aAttestationObject.AppendElements(mAttestationObject);
return NS_OK;
}
NS_IMETHODIMP
CtapRegisterResult::GetCredentialId(nsTArray<uint8_t>& aCredentialId) {
aCredentialId.Clear();
aCredentialId.AppendElements(mCredentialId);
return NS_OK;
}
NS_IMPL_ISUPPORTS(CtapSignResult, nsICtapSignResult)
NS_IMETHODIMP
CtapSignResult::GetStatus(nsresult* aStatus) {
*aStatus = mStatus;
return NS_OK;
}
NS_IMETHODIMP
CtapSignResult::GetCredentialId(nsTArray<uint8_t>& aCredentialId) {
aCredentialId.Clear();
aCredentialId.AppendElements(mCredentialId);
return NS_OK;
}
NS_IMETHODIMP
CtapSignResult::GetAuthenticatorData(nsTArray<uint8_t>& aAuthenticatorData) {
aAuthenticatorData.Clear();
aAuthenticatorData.AppendElements(mAuthenticatorData);
return NS_OK;
}
NS_IMETHODIMP
CtapSignResult::GetSignature(nsTArray<uint8_t>& aSignature) {
aSignature.Clear();
aSignature.AppendElements(mSignature);
return NS_OK;
}
NS_IMETHODIMP
CtapSignResult::GetUserHandle(nsTArray<uint8_t>& aUserHandle) {
aUserHandle.Clear();
aUserHandle.AppendElements(mUserHandle);
return NS_OK;
}
NS_IMETHODIMP
CtapSignResult::GetUserName(nsACString& aUserName) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
CtapSignResult::GetRpIdHash(nsTArray<uint8_t>& aRpIdHash) {
aRpIdHash.Clear();
aRpIdHash.AppendElements(mRpIdHash);
return NS_OK;
}
} // namespace mozilla::dom

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

@ -1,65 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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 CtapResults_h
#define CtapResults_h
#include "mozilla/dom/WebAuthnTransactionChild.h"
#include "nsIWebAuthnController.h"
namespace mozilla::dom {
class CtapRegisterResult final : public nsICtapRegisterResult {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICTAPREGISTERRESULT
explicit CtapRegisterResult(nsresult aStatus,
nsTArray<uint8_t>&& aAttestationObject,
nsTArray<uint8_t>&& aCredentialId)
: mStatus(aStatus),
mAttestationObject(std::move(aAttestationObject)),
mCredentialId(std::move(aCredentialId)) {}
private:
~CtapRegisterResult() = default;
nsresult mStatus;
nsTArray<uint8_t> mAttestationObject;
nsTArray<uint8_t> mCredentialId;
};
class CtapSignResult final : public nsICtapSignResult {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICTAPSIGNRESULT
explicit CtapSignResult(nsresult aStatus, nsTArray<uint8_t>&& aCredentialId,
nsTArray<uint8_t>&& aSignature,
nsTArray<uint8_t>&& aAuthenticatorData,
nsTArray<uint8_t>&& aUserHandle,
nsTArray<uint8_t>&& aRpIdHash)
: mStatus(aStatus),
mCredentialId(std::move(aCredentialId)),
mSignature(std::move(aSignature)),
mAuthenticatorData(std::move(aAuthenticatorData)),
mUserHandle(std::move(aUserHandle)),
mRpIdHash(std::move(aRpIdHash)) {}
private:
~CtapSignResult() = default;
nsresult mStatus;
nsTArray<uint8_t> mCredentialId;
nsTArray<uint8_t> mSignature;
nsTArray<uint8_t> mAuthenticatorData;
nsTArray<uint8_t> mUserHandle;
nsTArray<uint8_t> mRpIdHash;
};
} // namespace mozilla::dom
#endif // CtapResult_h

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -1,53 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 mozilla_dom_U2FSoftTokenTransport_h
#define mozilla_dom_U2FSoftTokenTransport_h
#include "nsIWebAuthnController.h"
#include "ScopedNSSTypes.h"
/*
* U2FSoftTokenManager is a software implementation of a secure token manager
* for the U2F and WebAuthn APIs.
*/
namespace mozilla::dom {
class U2FSoftTokenTransport final : public nsIWebAuthnTransport {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBAUTHNTRANSPORT
explicit U2FSoftTokenTransport(uint32_t aCounter);
private:
~U2FSoftTokenTransport() = default;
nsresult Init();
nsresult IsRegistered(const nsTArray<uint8_t>& aKeyHandle,
const nsTArray<uint8_t>& aAppParam, bool& aResult);
bool FindRegisteredKeyHandle(
const nsTArray<nsTArray<uint8_t>>& aAppIds,
const nsTArray<nsTArray<uint8_t>>& aCredentialIds,
/*out*/ nsTArray<uint8_t>& aKeyHandle,
/*out*/ nsTArray<uint8_t>& aAppId);
bool mInitialized;
mozilla::UniquePK11SymKey mWrappingKey;
static const nsCString mSecretNickname;
nsresult GetOrCreateWrappingKey(const mozilla::UniquePK11SlotInfo& aSlot);
uint32_t mCounter;
nsCOMPtr<nsIWebAuthnController> mController;
};
} // namespace mozilla::dom
#endif // mozilla_dom_U2FSoftTokenTransport_h

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

@ -10,89 +10,6 @@
namespace mozilla::dom {
nsresult CBOREncodePublicKeyObj(const CryptoBuffer& aPubKeyBuf,
/* out */ CryptoBuffer& aPubKeyObj) {
mozilla::dom::CryptoBuffer xBuf, yBuf;
nsresult rv = U2FDecomposeECKey(aPubKeyBuf, xBuf, yBuf);
if (NS_FAILED(rv)) {
return rv;
}
// COSE_Key object. See https://tools.ietf.org/html/rfc8152#section-7
cbor::output_dynamic cborPubKeyOut;
cbor::encoder encoder(cborPubKeyOut);
encoder.write_map(5);
{
encoder.write_int(1); // kty
encoder.write_int(2); // EC2
encoder.write_int(3); // alg
encoder.write_int(-7); // ES256
// See https://tools.ietf.org/html/rfc8152#section-13.1
encoder.write_int(-1); // crv
encoder.write_int(1); // P-256
encoder.write_int(-2); // x
encoder.write_bytes(xBuf.Elements(), xBuf.Length());
encoder.write_int(-3); // y
encoder.write_bytes(yBuf.Elements(), yBuf.Length());
}
if (!aPubKeyObj.Assign(cborPubKeyOut.data(), cborPubKeyOut.size())) {
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
nsresult CBOREncodeFidoU2FAttestationObj(
const CryptoBuffer& aAuthDataBuf, const CryptoBuffer& aAttestationCertBuf,
const CryptoBuffer& aSignatureBuf,
/* out */ CryptoBuffer& aAttestationObj) {
/*
Attestation Object, encoded in CBOR (description is CDDL)
attObj = {
authData: bytes,
$$attStmtType
}
$$attStmtType //= (
fmt: "fido-u2f",
attStmt: u2fStmtFormat
)
u2fStmtFormat = {
x5c: [ attestnCert: bytes, * (caCert: bytes) ],
sig: bytes
}
*/
cbor::output_dynamic cborAttOut;
cbor::encoder encoder(cborAttOut);
encoder.write_map(3);
{
encoder.write_string("fmt");
encoder.write_string("fido-u2f");
encoder.write_string("attStmt");
encoder.write_map(2);
{
encoder.write_string("sig");
encoder.write_bytes(aSignatureBuf.Elements(), aSignatureBuf.Length());
encoder.write_string("x5c");
// U2F wire protocol can only deliver 1 certificate, so it's never a chain
encoder.write_array(1);
encoder.write_bytes(aAttestationCertBuf.Elements(),
aAttestationCertBuf.Length());
}
encoder.write_string("authData");
encoder.write_bytes(aAuthDataBuf.Elements(), aAuthDataBuf.Length());
}
if (!aAttestationObj.Assign(cborAttOut.data(), cborAttOut.size())) {
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
nsresult CBOREncodeNoneAttestationObj(const CryptoBuffer& aAuthDataBuf,
/* out */ CryptoBuffer& aAttestationObj) {
/*

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

@ -15,14 +15,6 @@
namespace mozilla::dom {
nsresult CBOREncodePublicKeyObj(const CryptoBuffer& aPubKeyBuf,
/* out */ CryptoBuffer& aPubKeyObj);
nsresult CBOREncodeFidoU2FAttestationObj(
const CryptoBuffer& aAuthDataBuf, const CryptoBuffer& aAttestationCertBuf,
const CryptoBuffer& aSignatureBuf,
/* out */ CryptoBuffer& aAttestationObj);
nsresult CBOREncodeNoneAttestationObj(const CryptoBuffer& aAuthDataBuf,
/* out */ CryptoBuffer& aAttestationObj);

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

@ -23,8 +23,6 @@
#include "AuthrsTransport.h"
#include "CtapArgs.h"
#include "CtapResults.h"
#include "U2FSoftTokenTransport.h"
#include "WebAuthnEnumStrings.h"
#ifdef MOZ_WIDGET_ANDROID

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

@ -22,9 +22,6 @@ constexpr auto kGoogleAccountsAppId1 =
constexpr auto kGoogleAccountsAppId2 =
u"https://www.gstatic.com/securitykey/a/google.com/origins.json"_ns;
const uint8_t FLAG_TUP = 0x01; // Test of User Presence required
const uint8_t FLAG_AT = 0x40; // Authenticator Data is provided
bool EvaluateAppID(nsPIDOMWindowInner* aParent, const nsString& aOrigin,
/* in/out */ nsString& aAppId) {
// Facet is the specification's way of referring to the web origin.
@ -134,253 +131,6 @@ nsresult ReadToCryptoBuffer(pkix::Reader& aSrc, /* out */ CryptoBuffer& aDest,
return NS_OK;
}
// Format:
// 32 bytes: SHA256 of the RP ID
// 1 byte: flags (TUP & AT)
// 4 bytes: sign counter
// variable: attestation data struct
// variable: CBOR-format extension auth data (optional, not flagged)
nsresult AssembleAuthenticatorData(const CryptoBuffer& rpIdHashBuf,
const uint8_t flags,
const CryptoBuffer& counterBuf,
const CryptoBuffer& attestationDataBuf,
/* out */ CryptoBuffer& authDataBuf) {
if (NS_WARN_IF(!authDataBuf.SetCapacity(
32 + 1 + 4 + attestationDataBuf.Length(), mozilla::fallible))) {
return NS_ERROR_OUT_OF_MEMORY;
}
if (rpIdHashBuf.Length() != 32 || counterBuf.Length() != 4) {
return NS_ERROR_INVALID_ARG;
}
(void)authDataBuf.AppendElements(rpIdHashBuf, mozilla::fallible);
(void)authDataBuf.AppendElement(flags, mozilla::fallible);
(void)authDataBuf.AppendElements(counterBuf, mozilla::fallible);
(void)authDataBuf.AppendElements(attestationDataBuf, mozilla::fallible);
return NS_OK;
}
// attestation data struct format:
// - 16 bytes: AAGUID
// - 2 bytes: Length of Credential ID
// - L bytes: Credential ID
// - variable: CBOR-format public key
nsresult AssembleAttestationData(const CryptoBuffer& aaguidBuf,
const CryptoBuffer& keyHandleBuf,
const CryptoBuffer& pubKeyObj,
/* out */ CryptoBuffer& attestationDataBuf) {
if (NS_WARN_IF(!attestationDataBuf.SetCapacity(
aaguidBuf.Length() + 2 + keyHandleBuf.Length() + pubKeyObj.Length(),
mozilla::fallible))) {
return NS_ERROR_OUT_OF_MEMORY;
}
if (keyHandleBuf.Length() > 0xFFFF) {
return NS_ERROR_INVALID_ARG;
}
(void)attestationDataBuf.AppendElements(aaguidBuf, mozilla::fallible);
(void)attestationDataBuf.AppendElement((keyHandleBuf.Length() >> 8) & 0xFF,
mozilla::fallible);
(void)attestationDataBuf.AppendElement((keyHandleBuf.Length() >> 0) & 0xFF,
mozilla::fallible);
(void)attestationDataBuf.AppendElements(keyHandleBuf, mozilla::fallible);
(void)attestationDataBuf.AppendElements(pubKeyObj, mozilla::fallible);
return NS_OK;
}
nsresult AssembleAttestationObject(const CryptoBuffer& aRpIdHash,
const CryptoBuffer& aPubKeyBuf,
const CryptoBuffer& aKeyHandleBuf,
const CryptoBuffer& aAttestationCertBuf,
const CryptoBuffer& aSignatureBuf,
bool aForceNoneAttestation,
/* out */ CryptoBuffer& aAttestationObjBuf) {
// Construct the public key object
CryptoBuffer pubKeyObj;
nsresult rv = CBOREncodePublicKeyObj(aPubKeyBuf, pubKeyObj);
if (NS_FAILED(rv)) {
return rv;
}
mozilla::dom::CryptoBuffer aaguidBuf;
if (NS_WARN_IF(!aaguidBuf.SetCapacity(16, mozilla::fallible))) {
return NS_ERROR_OUT_OF_MEMORY;
}
// FIDO U2F devices have no AAGUIDs, so they'll be all zeros until we add
// support for CTAP2 devices.
for (int i = 0; i < 16; i++) {
// SetCapacity was just called, these cannot fail.
(void)aaguidBuf.AppendElement(0x00, mozilla::fallible);
}
// During create credential, counter is always 0 for U2F
// See https://github.com/w3c/webauthn/issues/507
mozilla::dom::CryptoBuffer counterBuf;
if (NS_WARN_IF(!counterBuf.SetCapacity(4, mozilla::fallible))) {
return NS_ERROR_OUT_OF_MEMORY;
}
// SetCapacity was just called, these cannot fail.
(void)counterBuf.AppendElement(0x00, mozilla::fallible);
(void)counterBuf.AppendElement(0x00, mozilla::fallible);
(void)counterBuf.AppendElement(0x00, mozilla::fallible);
(void)counterBuf.AppendElement(0x00, mozilla::fallible);
// Construct the Attestation Data, which slots into the end of the
// Authentication Data buffer.
CryptoBuffer attDataBuf;
rv = AssembleAttestationData(aaguidBuf, aKeyHandleBuf, pubKeyObj, attDataBuf);
if (NS_FAILED(rv)) {
return rv;
}
CryptoBuffer authDataBuf;
// attDataBuf always contains data, so per [1] we have to set the AT flag.
// [1] https://w3c.github.io/webauthn/#sec-authenticator-data
const uint8_t flags = FLAG_TUP | FLAG_AT;
rv = AssembleAuthenticatorData(aRpIdHash, flags, counterBuf, attDataBuf,
authDataBuf);
if (NS_FAILED(rv)) {
return rv;
}
// Direct attestation might have been requested by the RP.
// The user might override this and request anonymization anyway.
if (aForceNoneAttestation) {
rv = CBOREncodeNoneAttestationObj(authDataBuf, aAttestationObjBuf);
} else {
rv = CBOREncodeFidoU2FAttestationObj(authDataBuf, aAttestationCertBuf,
aSignatureBuf, aAttestationObjBuf);
}
return rv;
}
nsresult U2FDecomposeSignResponse(const CryptoBuffer& aResponse,
/* out */ uint8_t& aFlags,
/* out */ CryptoBuffer& aCounterBuf,
/* out */ CryptoBuffer& aSignatureBuf) {
if (aResponse.Length() < 5) {
return NS_ERROR_INVALID_ARG;
}
Span<const uint8_t> rspView = Span(aResponse);
aFlags = rspView[0];
if (NS_WARN_IF(!aCounterBuf.AppendElements(rspView.FromTo(1, 5),
mozilla::fallible))) {
return NS_ERROR_OUT_OF_MEMORY;
}
if (NS_WARN_IF(
!aSignatureBuf.AppendElements(rspView.From(5), mozilla::fallible))) {
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
nsresult U2FDecomposeRegistrationResponse(
const CryptoBuffer& aResponse,
/* out */ CryptoBuffer& aPubKeyBuf,
/* out */ CryptoBuffer& aKeyHandleBuf,
/* out */ CryptoBuffer& aAttestationCertBuf,
/* out */ CryptoBuffer& aSignatureBuf) {
// U2F v1.1 Format via
// http://fidoalliance.org/specs/fido-u2f-v1.1-id-20160915/fido-u2f-raw-message-formats-v1.1-id-20160915.html
//
// Bytes Value
// 1 0x05
// 65 public key
// 1 key handle length
// * key handle
// ASN.1 attestation certificate
// * attestation signature
pkix::Input u2fResponse;
u2fResponse.Init(aResponse.Elements(), aResponse.Length());
pkix::Reader input(u2fResponse);
uint8_t b;
if (input.Read(b) != pkix::Success) {
return NS_ERROR_DOM_UNKNOWN_ERR;
}
if (b != 0x05) {
return NS_ERROR_DOM_UNKNOWN_ERR;
}
nsresult rv = ReadToCryptoBuffer(input, aPubKeyBuf, 65);
if (NS_FAILED(rv)) {
return rv;
}
uint8_t handleLen;
if (input.Read(handleLen) != pkix::Success) {
return NS_ERROR_DOM_UNKNOWN_ERR;
}
rv = ReadToCryptoBuffer(input, aKeyHandleBuf, handleLen);
if (NS_FAILED(rv)) {
return rv;
}
// We have to parse the ASN.1 SEQUENCE on the outside to determine the cert's
// length.
pkix::Input cert;
if (pkix::der::ExpectTagAndGetTLV(input, pkix::der::SEQUENCE, cert) !=
pkix::Success) {
return NS_ERROR_DOM_UNKNOWN_ERR;
}
pkix::Reader certInput(cert);
rv = ReadToCryptoBuffer(certInput, aAttestationCertBuf, cert.GetLength());
if (NS_FAILED(rv)) {
return rv;
}
// The remainder of u2fResponse is the signature
pkix::Input u2fSig;
input.SkipToEnd(u2fSig);
pkix::Reader sigInput(u2fSig);
rv = ReadToCryptoBuffer(sigInput, aSignatureBuf, u2fSig.GetLength());
if (NS_FAILED(rv)) {
return rv;
}
MOZ_ASSERT(input.AtEnd());
return NS_OK;
}
nsresult U2FDecomposeECKey(const CryptoBuffer& aPubKeyBuf,
/* out */ CryptoBuffer& aXcoord,
/* out */ CryptoBuffer& aYcoord) {
pkix::Input pubKey;
pubKey.Init(aPubKeyBuf.Elements(), aPubKeyBuf.Length());
pkix::Reader input(pubKey);
uint8_t b;
if (input.Read(b) != pkix::Success) {
return NS_ERROR_DOM_UNKNOWN_ERR;
}
if (b != 0x04) {
return NS_ERROR_DOM_UNKNOWN_ERR;
}
nsresult rv = ReadToCryptoBuffer(input, aXcoord, 32);
if (NS_FAILED(rv)) {
return rv;
}
rv = ReadToCryptoBuffer(input, aYcoord, 32);
if (NS_FAILED(rv)) {
return rv;
}
MOZ_ASSERT(input.AtEnd());
return NS_OK;
}
static nsresult HashCString(nsICryptoHash* aHashService, const nsACString& aIn,
/* out */ CryptoBuffer& aOut) {
MOZ_ASSERT(aHashService);

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

@ -18,41 +18,9 @@
namespace mozilla::dom {
enum class U2FOperation { Register, Sign };
bool EvaluateAppID(nsPIDOMWindowInner* aParent, const nsString& aOrigin,
/* in/out */ nsString& aAppId);
nsresult AssembleAuthenticatorData(const CryptoBuffer& rpIdHashBuf,
const uint8_t flags,
const CryptoBuffer& counterBuf,
const CryptoBuffer& attestationDataBuf,
/* out */ CryptoBuffer& authDataBuf);
nsresult AssembleAttestationObject(const CryptoBuffer& aRpIdHash,
const CryptoBuffer& aPubKeyBuf,
const CryptoBuffer& aKeyHandleBuf,
const CryptoBuffer& aAttestationCertBuf,
const CryptoBuffer& aSignatureBuf,
bool aForceNoneAttestation,
/* out */ CryptoBuffer& aAttestationObjBuf);
nsresult U2FDecomposeSignResponse(const CryptoBuffer& aResponse,
/* out */ uint8_t& aFlags,
/* out */ CryptoBuffer& aCounterBuf,
/* out */ CryptoBuffer& aSignatureBuf);
nsresult U2FDecomposeRegistrationResponse(
const CryptoBuffer& aResponse,
/* out */ CryptoBuffer& aPubKeyBuf,
/* out */ CryptoBuffer& aKeyHandleBuf,
/* out */ CryptoBuffer& aAttestationCertBuf,
/* out */ CryptoBuffer& aSignatureBuf);
nsresult U2FDecomposeECKey(const CryptoBuffer& aPubKeyBuf,
/* out */ CryptoBuffer& aXcoord,
/* out */ CryptoBuffer& aYcoord);
nsresult HashCString(const nsACString& aIn, /* out */ CryptoBuffer& aOut);
nsresult BuildTransactionHashes(const nsCString& aRpId,

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

@ -38,9 +38,7 @@ UNIFIED_SOURCES += [
"cbor-cpp/src/encoder.cpp",
"cbor-cpp/src/output_dynamic.cpp",
"CtapArgs.cpp",
"CtapResults.cpp",
"PublicKeyCredential.cpp",
"U2FSoftTokenTransport.cpp",
"U2FTokenManager.cpp",
"WebAuthnCBORUtil.cpp",
"WebAuthnController.cpp",

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

@ -13854,12 +13854,6 @@
value: false
mirror: always
# Global counter for U2F soft token operations
- name: security.webauth.softtoken_counter
type: RelaxedAtomicUint32
value: 0
mirror: always
# Block Worker/SharedWorker scripts with wrong MIME type.
- name: security.block_Worker_with_wrong_mime
type: bool