mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-16 03:18:09 +00:00
Merge pull request #576 from trezor/andrewkozlik/fido2-device-test
FIDO2 fixes for device tests and knownapps improvements
This commit is contained in:
commit
8524ff9832
common/defs/webauthn
apps
binance.jsonbitbucket.jsonbitfinex.jsonbitwarden.jsondashlane.jsondropbox.jsonduo.jsonfastmail.jsonfedora.jsongandi.jsongithub.jsongitlab.jsongoogle.jsonkeeper.jsonlastpass.jsonlogin.gov.jsonmicrosoft.jsonslushpool.jsonstripe.jsonu2f.bin.coffee.jsonwebauthn.bin.coffee.jsonwebauthn.io.jsonwebauthn.me.jsonyubico-demo.json
gen.pycore/src/apps/webauthn
legacy/firmware
@ -1,5 +1,5 @@
|
||||
{
|
||||
"label": "Binance",
|
||||
"webauthn": "www.binance.com",
|
||||
"webauthn": ["www.binance.com"],
|
||||
"use_sign_count": false
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"label": "Bitbucket",
|
||||
"u2f": "https://bitbucket.org"
|
||||
"u2f": ["12743b921297b77f1135e41fdedd4a846afe82e1f36932a9912f3b0d8dfb7d0e"]
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"label": "Bitfinex",
|
||||
"u2f": "https://www.bitfinex.com"
|
||||
"u2f": ["302fd5b4492a07b9febb30e73269eca501205ccfe0c20bf7b472fa2d31e21e63"]
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"label": "Bitwarden",
|
||||
"u2f": "https://vault.bitwarden.com/app-id.json"
|
||||
"u2f": ["a34d309ffa28c12414b8ba6c07ee1efae1a85e8a04614859a67c0493b6956190"]
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"label": "Dashlane",
|
||||
"u2f": "https://www.dashlane.com"
|
||||
"u2f": ["68201915d74cb42af5b3cc5c95b9553e3e3a83b4d2a93b45fbadaa8469ff8e6e"]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"label": "Dropbox",
|
||||
"u2f": "https://www.dropbox.com/u2f-app-id.json",
|
||||
"webauthn": "www.dropbox.com"
|
||||
"u2f": ["c50f8a7b708e92f82e7a50e2bdc55d8fd91a22fe6b29c0cdf7805530842af581"],
|
||||
"webauthn": ["www.dropbox.com"]
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"label": "Duo",
|
||||
"u2f": "https://api-9dcf9b83.duosecurity.com"
|
||||
"u2f": ["f3e2042f94607da0a9c1f3b95e0d2f2bb2e069c5bb4fa764affa647d847b7ed6"]
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"label": "FastMail",
|
||||
"u2f": "https://www.fastmail.com"
|
||||
"u2f": ["6966abe3674ea2f53079eb710197848c9be6f363992fd029e9898447cb9f0084"]
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"label": "Fedora",
|
||||
"u2f": "https://id.fedoraproject.org/u2f-origins.json"
|
||||
"u2f": ["9d61442f5ce133bd46544fc42f0a6d54c0deb88840cac2b6aefa6514f89349e9"]
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
{
|
||||
"label": "Gandi",
|
||||
"u2f": "https://account.gandi.net/api/u2f/trusted_facets.json"
|
||||
"u2f": ["a4e22dcafea7e90e128950113989fc45978dc9fb87767560516c1c69dfdfd196"],
|
||||
"webauthn": ["gandi.net"]
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"label": "GitHub",
|
||||
"u2f": "https://github.com/u2f/trusted_facets",
|
||||
"webauthn": "github.com",
|
||||
"u2f": ["70617dfed065863af47c15556c91798880828cc407fdf70ae85011569465a075"],
|
||||
"webauthn": ["github.com"],
|
||||
"use_sign_count": true
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"label": "GitLab",
|
||||
"u2f": "https://gitlab.com"
|
||||
"u2f": ["e7be96a51bd0192a72840d2e5909f72ba82a2fe93faa624f03396b30e494c804"]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"label": "Google",
|
||||
"u2f": "https://www.gstatic.com/securitykey/origins.json",
|
||||
"webauthn": "google.com"
|
||||
"u2f": ["a54672b222c4cf95e151ed8d4d3c767a6cc349435943794e884f3d023a8229fd"],
|
||||
"webauthn": ["google.com"]
|
||||
}
|
||||
|
@ -1,4 +1,7 @@
|
||||
{
|
||||
"label": "Keeper",
|
||||
"u2f": "https://keepersecurity.com"
|
||||
"u2f": [
|
||||
"53a15ba42a7c0325b8dbee289634a48f58aea3246645d5ff418f9bb8819885a9",
|
||||
"d65f005ef4dea9320c9973053c95ff6020115d5fec1b7fee41a578e18df9ca8c"
|
||||
]
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"label": "LastPass",
|
||||
"u2f": "https://lastpass.com"
|
||||
"u2f": ["d755c527a86bf78445c282e713dcb86d46ff8b3cafcfb73b2e8cbe6c0884cb24"]
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"label": "login.gov",
|
||||
"webauthn": "secure.login.gov"
|
||||
"webauthn": ["secure.login.gov"]
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"label": "Microsoft",
|
||||
"webauthn": "login.microsoft.com",
|
||||
"webauthn": ["login.microsoft.com"],
|
||||
"use_sign_count": false
|
||||
}
|
||||
|
@ -1,4 +1,7 @@
|
||||
{
|
||||
"label": "Slush Pool",
|
||||
"u2f": "https://slushpool.com/static/security/u2f.json"
|
||||
"u2f": [
|
||||
"08b2a3d41939aa31668493cb36cdcc4f16c4d9b4c8238b73c2f672c033007197",
|
||||
"38804f2eff74f228b74151c201aa82e7e8eefcacfecf23fa146b13a37666314f"
|
||||
]
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"label": "Stripe",
|
||||
"u2f": "https://dashboard.stripe.com"
|
||||
"u2f": ["2ac6ad09a6d0772c44da73a6072f9d240fc6854a70d79c1024ff7c7559593292"]
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"label": "u2f.bin.coffee",
|
||||
"u2f": "https://u2f.bin.coffee"
|
||||
"u2f": ["1b3c16dd2f7c46e2b4c289dc16746bcc60dfcf0fb818e13215526e1408e7f468"]
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"label": "webauthn.bin.coffee",
|
||||
"webauthn": "webauthn.bin.coffee"
|
||||
"webauthn": ["webauthn.bin.coffee"]
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"label": "WebAuthn.io",
|
||||
"webauthn": "webauthn.io"
|
||||
"webauthn": ["webauthn.io"]
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"label": "WebAuthn.me",
|
||||
"webauthn": "webauthn.me"
|
||||
"webauthn": ["webauthn.me"]
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"label": "demo.yubico.com",
|
||||
"webauthn": "demo.yubico.com"
|
||||
"webauthn": ["demo.yubico.com"]
|
||||
}
|
||||
|
@ -16,41 +16,41 @@ def c_bytes(h):
|
||||
|
||||
|
||||
def gen_core(data):
|
||||
print("_knownapps = {")
|
||||
print("# contents generated via script in")
|
||||
print("# trezor-common/defs/webauthn/gen.py")
|
||||
print("# do not edit manually")
|
||||
print()
|
||||
print("knownapps = {")
|
||||
print(" # U2F")
|
||||
for d in data:
|
||||
if "u2f" in d:
|
||||
url, label = d["u2f"], d["label"]
|
||||
print(' "%s": {"label": "%s", "use_sign_count": True},' % (url, label))
|
||||
for appid in d.get("u2f", []):
|
||||
label = d["label"]
|
||||
h = bytes.fromhex(appid)
|
||||
print(" %s: {" % h)
|
||||
print(' "label": "%s",' % label)
|
||||
print(' "use_sign_count": True,')
|
||||
print(" },")
|
||||
print(" # WebAuthn")
|
||||
for d in data:
|
||||
if "webauthn" in d:
|
||||
origin, label, use_sign_count = (
|
||||
d["webauthn"],
|
||||
d["label"],
|
||||
d.get("use_sign_count", None),
|
||||
)
|
||||
if use_sign_count is None:
|
||||
print(' "%s": {"label": "%s"},' % (origin, label))
|
||||
else:
|
||||
print(
|
||||
' "%s": {"label": "%s", "use_sign_count": %s},'
|
||||
% (origin, label, use_sign_count)
|
||||
)
|
||||
for origin in d.get("webauthn", []):
|
||||
h = sha256(origin.encode()).digest()
|
||||
label, use_sign_count = (d["label"], d.get("use_sign_count", None))
|
||||
print(" %s: {" % h)
|
||||
print(' "label": "%s",' % label)
|
||||
if use_sign_count is not None:
|
||||
print(' "use_sign_count": %s,' % use_sign_count)
|
||||
print(" },")
|
||||
print("}")
|
||||
|
||||
|
||||
def gen_mcu(data):
|
||||
for d in data:
|
||||
if "u2f" in d:
|
||||
url, label = d["u2f"], d["label"]
|
||||
h = sha256(url.encode()).digest()
|
||||
print(
|
||||
'\t{\n\t\t// U2F: %s\n\t\t%s,\n\t\t"%s"\n\t},'
|
||||
% (url, c_bytes(h), label)
|
||||
)
|
||||
if "webauthn" in d:
|
||||
origin, label = d["webauthn"], d["label"]
|
||||
for appid in d.get("u2f", []):
|
||||
label = d["label"]
|
||||
h = bytes.fromhex(appid)
|
||||
print('\t{\n\t\t// U2F\n\t\t%s,\n\t\t"%s"\n\t},' % (c_bytes(h), label))
|
||||
for origin in d.get("webauthn", []):
|
||||
label = d["label"]
|
||||
h = sha256(origin.encode()).digest()
|
||||
print(
|
||||
'\t{\n\t\t// WebAuthn: %s\n\t\t%s,\n\t\t"%s"\n\t},'
|
||||
|
@ -25,7 +25,6 @@ if __debug__:
|
||||
if False:
|
||||
from typing import Any, Coroutine, List, Optional
|
||||
|
||||
_HID_RPT_SIZE = const(64)
|
||||
_CID_BROADCAST = const(0xFFFFFFFF) # broadcast channel id
|
||||
|
||||
# types of frame
|
||||
@ -33,6 +32,12 @@ _TYPE_MASK = const(0x80) # frame type mask
|
||||
_TYPE_INIT = const(0x80) # initial frame identifier
|
||||
_TYPE_CONT = const(0x00) # continuation frame identifier
|
||||
|
||||
# U2F HID sizes
|
||||
_HID_RPT_SIZE = const(64)
|
||||
_FRAME_INIT_SIZE = const(57)
|
||||
_FRAME_CONT_SIZE = const(59)
|
||||
_MAX_U2FHID_MSG_PAYLOAD_LEN = const(_FRAME_INIT_SIZE + 128 * _FRAME_CONT_SIZE)
|
||||
|
||||
# types of cmd
|
||||
_CMD_PING = const(0x81) # echo data through local processor only
|
||||
_CMD_MSG = const(0x83) # send U2F message frame
|
||||
@ -108,6 +113,7 @@ _KEEPALIVE_STATUS_UP_NEEDED = const(0x02) # waiting for user presence
|
||||
|
||||
# time intervals and timeouts
|
||||
_KEEPALIVE_INTERVAL_MS = const(80) # interval between keepalive commands
|
||||
_CTAP_HID_TIMEOUT_MS = const(500)
|
||||
_U2F_CONFIRM_TIMEOUT_MS = const(10 * 1000)
|
||||
_FIDO2_CONFIRM_TIMEOUT_MS = const(60 * 1000)
|
||||
|
||||
@ -131,7 +137,9 @@ _ERR_MSG_TIMEOUT = const(0x05) # message has timed out
|
||||
_ERR_CHANNEL_BUSY = const(0x06) # channel busy
|
||||
_ERR_LOCK_REQUIRED = const(0x0A) # command requires channel lock
|
||||
_ERR_INVALID_CID = const(0x0B) # command not allowed on this cid
|
||||
_ERR_CBOR_UNEXPECTED_TYPE = const(0x11) # invalid/unexpected CBOR
|
||||
_ERR_INVALID_CBOR = const(0x12) # error when parsing CBOR
|
||||
_ERR_MISSING_PARAMETER = const(0x14) # missing non-optional parameter
|
||||
_ERR_CREDENTIAL_EXCLUDED = const(0x19) # valid credential found in the exclude list
|
||||
_ERR_UNSUPPORTED_ALGORITHM = const(0x26) # requested COSE algorithm not supported
|
||||
_ERR_OPERATION_DENIED = const(0x27) # user declined or timed out
|
||||
@ -193,9 +201,6 @@ _RESULT_DECLINE = const(2) # User declined.
|
||||
_RESULT_CANCEL = const(3) # Request was cancelled by _CMD_CANCEL.
|
||||
_RESULT_TIMEOUT = const(4) # Request exceeded _FIDO2_CONFIRM_TIMEOUT_MS.
|
||||
|
||||
_FRAME_INIT_SIZE = 57
|
||||
_FRAME_CONT_SIZE = 59
|
||||
|
||||
# Generate the authenticatorKeyAgreementKey used for ECDH in authenticatorClientPIN getKeyAgreement.
|
||||
_KEY_AGREEMENT_PRIVKEY = nist256p1.generate_secret()
|
||||
_KEY_AGREEMENT_PUBKEY = nist256p1.publickey(_KEY_AGREEMENT_PRIVKEY, False)
|
||||
@ -207,6 +212,8 @@ _ALLOW_RESIDENT_CREDENTIALS = True
|
||||
# The attestation type to use in MakeCredential responses. If false, then self attestation will be used.
|
||||
_USE_BASIC_ATTESTATION = False
|
||||
|
||||
_AUTOCONFIRM = False
|
||||
|
||||
|
||||
def frame_init() -> dict:
|
||||
# uint32_t cid; // Channel identifier
|
||||
@ -357,7 +364,7 @@ async def read_cmd(iface: io.HID) -> Optional[Cmd]:
|
||||
read = loop.wait(iface.iface_num() | io.POLL_READ)
|
||||
|
||||
buf = await read
|
||||
|
||||
while True:
|
||||
ifrm = overlay_struct(buf, desc_init)
|
||||
bcnt = ifrm.bcnt
|
||||
data = ifrm.data
|
||||
@ -370,6 +377,18 @@ async def read_cmd(iface: io.HID) -> Optional[Cmd]:
|
||||
log.warning(__name__, "_TYPE_CONT")
|
||||
return None
|
||||
|
||||
if ifrm.cid == 0 or ((ifrm.cid == _CID_BROADCAST) and (ifrm.cmd != _CMD_INIT)):
|
||||
# CID 0 is reserved for future use and _CID_BROADCAST is reserved for channel allocation
|
||||
await send_cmd(cmd_error(ifrm.cid, _ERR_INVALID_CID), iface)
|
||||
return None
|
||||
|
||||
if bcnt > _MAX_U2FHID_MSG_PAYLOAD_LEN:
|
||||
# invalid payload length, abort current msg
|
||||
if __debug__:
|
||||
log.warning(__name__, "_MAX_U2FHID_MSG_PAYLOAD_LEN")
|
||||
await send_cmd(cmd_error(ifrm.cid, _ERR_INVALID_LEN), iface)
|
||||
return None
|
||||
|
||||
if datalen < bcnt:
|
||||
databuf = bytearray(bcnt)
|
||||
utils.memcpy(databuf, 0, data, 0, bcnt)
|
||||
@ -378,18 +397,19 @@ async def read_cmd(iface: io.HID) -> Optional[Cmd]:
|
||||
data = data[:bcnt]
|
||||
|
||||
while datalen < bcnt:
|
||||
buf = await read
|
||||
buf = await loop.race(read, loop.sleep(_CTAP_HID_TIMEOUT_MS * 1000))
|
||||
if not isinstance(buf, (bytes, bytearray)):
|
||||
await send_cmd(cmd_error(ifrm.cid, _ERR_MSG_TIMEOUT), iface)
|
||||
return None
|
||||
|
||||
cfrm = overlay_struct(buf, desc_cont)
|
||||
|
||||
if cfrm.seq == _CMD_INIT:
|
||||
# _CMD_INIT frame, cancels current channel
|
||||
ifrm = overlay_struct(buf, desc_init)
|
||||
data = ifrm.data[: ifrm.bcnt]
|
||||
break
|
||||
|
||||
if cfrm.cid != ifrm.cid:
|
||||
# cont frame for a different channel, reply with BUSY and skip
|
||||
# cont frame for a different channel, reply with BUSY and abort
|
||||
if __debug__:
|
||||
log.warning(__name__, "_ERR_CHANNEL_BUSY")
|
||||
await send_cmd(cmd_error(cfrm.cid, _ERR_CHANNEL_BUSY), iface)
|
||||
@ -405,7 +425,7 @@ async def read_cmd(iface: io.HID) -> Optional[Cmd]:
|
||||
|
||||
datalen += utils.memcpy(data, datalen, cfrm.data, 0, bcnt - datalen)
|
||||
seq += 1
|
||||
|
||||
else:
|
||||
return Cmd(ifrm.cid, ifrm.cmd, data)
|
||||
|
||||
|
||||
@ -533,6 +553,8 @@ async def verify_user(keepalive_callback: KeepaliveCallback) -> bool:
|
||||
|
||||
|
||||
async def confirm(*args: Any, **kwargs: Any) -> bool:
|
||||
if _AUTOCONFIRM:
|
||||
return True
|
||||
dialog = Confirm(*args, **kwargs)
|
||||
if __debug__:
|
||||
return await loop.race(dialog, confirm_signal()) is CONFIRMED
|
||||
@ -540,6 +562,16 @@ async def confirm(*args: Any, **kwargs: Any) -> bool:
|
||||
return await dialog is CONFIRMED
|
||||
|
||||
|
||||
async def confirm_pageable(*args: Any, **kwargs: Any) -> bool:
|
||||
if _AUTOCONFIRM:
|
||||
return True
|
||||
dialog = ConfirmPageable(*args, **kwargs)
|
||||
if __debug__:
|
||||
return await loop.race(dialog, confirm_signal()) is CONFIRMED
|
||||
else:
|
||||
return await dialog is CONFIRMED
|
||||
|
||||
|
||||
class State:
|
||||
def __init__(self, cid: int, iface: io.HID) -> None:
|
||||
self.cid = cid
|
||||
@ -735,6 +767,7 @@ class Fido2ConfirmGetAssertion(Fido2State, ConfirmInfo, Pageable):
|
||||
client_data_hash: bytes,
|
||||
creds: List[Credential],
|
||||
hmac_secret: Optional[dict],
|
||||
resident: bool,
|
||||
user_verification: bool,
|
||||
) -> None:
|
||||
Fido2State.__init__(self, cid, iface)
|
||||
@ -743,6 +776,7 @@ class Fido2ConfirmGetAssertion(Fido2State, ConfirmInfo, Pageable):
|
||||
self._client_data_hash = client_data_hash
|
||||
self._creds = creds
|
||||
self._hmac_secret = hmac_secret
|
||||
self._resident = resident
|
||||
self._user_verification = user_verification
|
||||
self.load_icon(self._creds[0].rp_id_hash)
|
||||
|
||||
@ -760,7 +794,7 @@ class Fido2ConfirmGetAssertion(Fido2State, ConfirmInfo, Pageable):
|
||||
|
||||
async def confirm_dialog(self) -> bool:
|
||||
content = ConfirmContent(self)
|
||||
if await ConfirmPageable(self, content) is not CONFIRMED:
|
||||
if not await confirm_pageable(self, content):
|
||||
return False
|
||||
if self._user_verification:
|
||||
return await verify_user(KeepaliveCallback(self.cid, self.iface))
|
||||
@ -777,6 +811,7 @@ class Fido2ConfirmGetAssertion(Fido2State, ConfirmInfo, Pageable):
|
||||
cred.rp_id_hash,
|
||||
cred,
|
||||
self._hmac_secret,
|
||||
self._resident,
|
||||
True,
|
||||
self._user_verification,
|
||||
)
|
||||
@ -804,7 +839,9 @@ class Fido2ConfirmNoCredentials(Fido2ConfirmGetAssertion):
|
||||
def __init__(self, cid: int, iface: io.HID, rp_id: str) -> None:
|
||||
cred = Fido2Credential()
|
||||
cred.rp_id = rp_id
|
||||
super().__init__(cid, iface, b"", [cred], {}, user_verification=False)
|
||||
super().__init__(
|
||||
cid, iface, b"", [cred], {}, resident=False, user_verification=False
|
||||
)
|
||||
|
||||
async def on_confirm(self) -> None:
|
||||
cmd = cbor_error(self.cid, _ERR_NO_CREDENTIALS)
|
||||
@ -931,7 +968,10 @@ class DialogManager:
|
||||
|
||||
def dispatch_cmd(req: Cmd, dialog_mgr: DialogManager) -> Optional[Cmd]:
|
||||
if req.cmd == _CMD_MSG:
|
||||
try:
|
||||
m = req.to_msg()
|
||||
except IndexError:
|
||||
return cmd_error(req.cid, _ERR_INVALID_LEN)
|
||||
|
||||
if m.cla != 0:
|
||||
if __debug__:
|
||||
@ -974,6 +1014,8 @@ def dispatch_cmd(req: Cmd, dialog_mgr: DialogManager) -> Optional[Cmd]:
|
||||
loop.schedule(ui.alert())
|
||||
return req
|
||||
elif req.cmd == _CMD_CBOR and _ALLOW_FIDO2:
|
||||
if not req.data:
|
||||
return cmd_error(req.cid, _ERR_INVALID_LEN)
|
||||
if req.data[0] == _CBOR_MAKE_CREDENTIAL:
|
||||
if __debug__:
|
||||
log.debug(__name__, "_CBOR_MAKE_CREDENTIAL")
|
||||
@ -1016,9 +1058,7 @@ def dispatch_cmd(req: Cmd, dialog_mgr: DialogManager) -> Optional[Cmd]:
|
||||
|
||||
|
||||
def cmd_init(req: Cmd) -> Cmd:
|
||||
if req.cid == 0:
|
||||
return cmd_error(req.cid, _ERR_INVALID_CID)
|
||||
elif req.cid == _CID_BROADCAST:
|
||||
if req.cid == _CID_BROADCAST:
|
||||
# uint32_t except 0 and 0xffffffff
|
||||
resp_cid = random.uniform(0xFFFFFFFE) + 1
|
||||
else:
|
||||
@ -1211,6 +1251,43 @@ def cbor_error(cid: int, code: int) -> Cmd:
|
||||
return Cmd(cid, _CMD_CBOR, ustruct.pack(">B", code))
|
||||
|
||||
|
||||
def credentials_from_descriptor_list(
|
||||
descriptor_list: List[dict], rp_id_hash: bytes
|
||||
) -> List[Credential]:
|
||||
cred_list = []
|
||||
for credential_descriptor in descriptor_list:
|
||||
credential_type = credential_descriptor["type"]
|
||||
if not isinstance(credential_type, str):
|
||||
raise TypeError
|
||||
if credential_type != "public-key":
|
||||
continue
|
||||
|
||||
credential_id = credential_descriptor["id"]
|
||||
if not isinstance(credential_id, (bytes, bytearray)):
|
||||
raise TypeError
|
||||
cred = Credential.from_bytes(credential_id, rp_id_hash)
|
||||
if cred is not None:
|
||||
cred_list.append(cred)
|
||||
|
||||
return cred_list
|
||||
|
||||
|
||||
def algorithms_from_pub_key_cred_params(pub_key_cred_params: List[dict]) -> List[int]:
|
||||
alg_list = []
|
||||
for pkcp in pub_key_cred_params:
|
||||
pub_key_cred_type = pkcp["type"]
|
||||
if not isinstance(pub_key_cred_type, str):
|
||||
raise TypeError
|
||||
if pub_key_cred_type != "public-key":
|
||||
continue
|
||||
|
||||
pub_key_cred_alg = pkcp["alg"]
|
||||
if not isinstance(pub_key_cred_alg, int):
|
||||
raise TypeError
|
||||
alg_list.append(pub_key_cred_alg)
|
||||
return alg_list
|
||||
|
||||
|
||||
def cbor_make_credential(req: Cmd, dialog_mgr: DialogManager) -> Optional[Cmd]:
|
||||
from apps.webauthn.knownapps import knownapps
|
||||
|
||||
@ -1221,7 +1298,8 @@ def cbor_make_credential(req: Cmd, dialog_mgr: DialogManager) -> Optional[Cmd]:
|
||||
|
||||
try:
|
||||
param = cbor.decode(req.data[1:])
|
||||
rp_id = param[_MAKECRED_CMD_RP]["id"]
|
||||
rp = param[_MAKECRED_CMD_RP]
|
||||
rp_id = rp["id"]
|
||||
rp_id_hash = hashlib.sha256(rp_id).digest()
|
||||
|
||||
# Prepare the new credential.
|
||||
@ -1236,9 +1314,7 @@ def cbor_make_credential(req: Cmd, dialog_mgr: DialogManager) -> Optional[Cmd]:
|
||||
|
||||
# Check if any of the credential descriptors in the exclude list belong to this authenticator.
|
||||
exclude_list = param.get(_MAKECRED_CMD_EXCLUDE_LIST, [])
|
||||
for credential_descriptor in exclude_list:
|
||||
excl_cred = Credential.from_bytes(credential_descriptor["id"], rp_id_hash)
|
||||
if credential_descriptor["type"] == "public-key" and excl_cred is not None:
|
||||
if credentials_from_descriptor_list(exclude_list, rp_id_hash):
|
||||
# This authenticator is already registered.
|
||||
if not dialog_mgr.set_state(
|
||||
Fido2ConfirmExcluded(req.cid, dialog_mgr.iface, cred)
|
||||
@ -1248,9 +1324,8 @@ def cbor_make_credential(req: Cmd, dialog_mgr: DialogManager) -> Optional[Cmd]:
|
||||
|
||||
# Check that the relying party supports ECDSA P-256 with SHA-256. We don't support any other algorithms.
|
||||
pub_key_cred_params = param[_MAKECRED_CMD_PUB_KEY_CRED_PARAMS]
|
||||
if ("public-key", _COSE_ALG_ES256) not in (
|
||||
(pkcp.get("type", None), pkcp.get("alg", None))
|
||||
for pkcp in pub_key_cred_params
|
||||
if _COSE_ALG_ES256 not in algorithms_from_pub_key_cred_params(
|
||||
pub_key_cred_params
|
||||
):
|
||||
return cbor_error(req.cid, _ERR_UNSUPPORTED_ALGORITHM)
|
||||
|
||||
@ -1265,6 +1340,10 @@ def cbor_make_credential(req: Cmd, dialog_mgr: DialogManager) -> Optional[Cmd]:
|
||||
)
|
||||
|
||||
client_data_hash = param[_MAKECRED_CMD_CLIENT_DATA_HASH]
|
||||
except TypeError:
|
||||
return cbor_error(req.cid, _ERR_CBOR_UNEXPECTED_TYPE)
|
||||
except KeyError:
|
||||
return cbor_error(req.cid, _ERR_MISSING_PARAMETER)
|
||||
except Exception:
|
||||
return cbor_error(req.cid, _ERR_INVALID_CBOR)
|
||||
|
||||
@ -1273,13 +1352,18 @@ def cbor_make_credential(req: Cmd, dialog_mgr: DialogManager) -> Optional[Cmd]:
|
||||
# Check data types.
|
||||
if (
|
||||
not cred.check_data_types()
|
||||
or not isinstance(user.get("icon", ""), str)
|
||||
or not isinstance(rp.get("icon", ""), str)
|
||||
or not isinstance(client_data_hash, (bytes, bytearray))
|
||||
or not isinstance(resident_key, bool)
|
||||
or not isinstance(user_verification, bool)
|
||||
):
|
||||
return cbor_error(req.cid, _ERR_INVALID_CBOR)
|
||||
return cbor_error(req.cid, _ERR_CBOR_UNEXPECTED_TYPE)
|
||||
|
||||
# Check options.
|
||||
if "up" in options:
|
||||
return cbor_error(req.cid, _ERR_INVALID_OPTION)
|
||||
|
||||
if resident_key and not _ALLOW_RESIDENT_CREDENTIALS:
|
||||
return cbor_error(req.cid, _ERR_UNSUPPORTED_OPTION)
|
||||
|
||||
@ -1388,22 +1472,21 @@ def cbor_get_assertion(req: Cmd, dialog_mgr: DialogManager) -> Optional[Cmd]:
|
||||
rp_id = param[_GETASSERT_CMD_RP_ID]
|
||||
rp_id_hash = hashlib.sha256(rp_id).digest()
|
||||
|
||||
cred_list = []
|
||||
allow_list = param.get(_GETASSERT_CMD_ALLOW_LIST, [])
|
||||
if allow_list:
|
||||
# Get all credentials from the allow list that belong to this authenticator.
|
||||
for credential_descriptor in allow_list:
|
||||
if credential_descriptor["type"] != "public-key":
|
||||
continue
|
||||
cred = Credential.from_bytes(credential_descriptor["id"], rp_id_hash)
|
||||
if cred is not None:
|
||||
cred_list = credentials_from_descriptor_list(allow_list, rp_id_hash)
|
||||
for cred in cred_list:
|
||||
if cred.rp_id is None:
|
||||
cred.rp_id = rp_id
|
||||
cred_list.append(cred)
|
||||
resident = False
|
||||
else:
|
||||
# Allow list is empty. Get resident credentials.
|
||||
if _ALLOW_RESIDENT_CREDENTIALS:
|
||||
cred_list = get_resident_credentials(rp_id_hash)
|
||||
else:
|
||||
cred_list = []
|
||||
resident = True
|
||||
|
||||
# Sort credentials by time of creation.
|
||||
cred_list.sort()
|
||||
@ -1421,6 +1504,10 @@ def cbor_get_assertion(req: Cmd, dialog_mgr: DialogManager) -> Optional[Cmd]:
|
||||
hmac_secret = param.get(_GETASSERT_CMD_EXTENSIONS, {}).get("hmac-secret", None)
|
||||
|
||||
client_data_hash = param[_GETASSERT_CMD_CLIENT_DATA_HASH]
|
||||
except TypeError:
|
||||
return cbor_error(req.cid, _ERR_CBOR_UNEXPECTED_TYPE)
|
||||
except KeyError:
|
||||
return cbor_error(req.cid, _ERR_MISSING_PARAMETER)
|
||||
except Exception:
|
||||
return cbor_error(req.cid, _ERR_INVALID_CBOR)
|
||||
|
||||
@ -1431,7 +1518,7 @@ def cbor_get_assertion(req: Cmd, dialog_mgr: DialogManager) -> Optional[Cmd]:
|
||||
or not isinstance(user_presence, bool)
|
||||
or not isinstance(user_verification, bool)
|
||||
):
|
||||
return cbor_error(req.cid, _ERR_INVALID_CBOR)
|
||||
return cbor_error(req.cid, _ERR_CBOR_UNEXPECTED_TYPE)
|
||||
|
||||
# Check options.
|
||||
if "rk" in options:
|
||||
@ -1461,6 +1548,7 @@ def cbor_get_assertion(req: Cmd, dialog_mgr: DialogManager) -> Optional[Cmd]:
|
||||
rp_id_hash,
|
||||
cred_list[0],
|
||||
hmac_secret,
|
||||
resident,
|
||||
user_presence,
|
||||
user_verification,
|
||||
)
|
||||
@ -1476,6 +1564,7 @@ def cbor_get_assertion(req: Cmd, dialog_mgr: DialogManager) -> Optional[Cmd]:
|
||||
client_data_hash,
|
||||
cred_list,
|
||||
hmac_secret,
|
||||
resident,
|
||||
user_verification,
|
||||
)
|
||||
)
|
||||
@ -1536,6 +1625,7 @@ def cbor_get_assertion_sign(
|
||||
rp_id_hash: bytes,
|
||||
cred: Credential,
|
||||
hmac_secret: Optional[dict],
|
||||
resident: bool,
|
||||
user_presence: bool,
|
||||
user_verification: bool,
|
||||
) -> bytes:
|
||||
@ -1585,7 +1675,7 @@ def cbor_get_assertion_sign(
|
||||
_GETASSERT_RESP_SIGNATURE: sig,
|
||||
}
|
||||
|
||||
if user_presence and cred.user_id is not None:
|
||||
if resident and user_presence and cred.user_id is not None:
|
||||
response[_GETASSERT_RESP_USER] = {"id": cred.user_id}
|
||||
|
||||
return cbor.encode(response)
|
||||
|
@ -1,60 +1,120 @@
|
||||
from trezor.crypto.hashlib import sha256
|
||||
|
||||
# contents generated via script in
|
||||
# trezor-common/defs/webauthn/gen.py
|
||||
# do not edit manually
|
||||
|
||||
_knownapps = {
|
||||
knownapps = {
|
||||
# U2F
|
||||
"https://bitbucket.org": {"label": "Bitbucket", "use_sign_count": True},
|
||||
"https://www.bitfinex.com": {"label": "Bitfinex", "use_sign_count": True},
|
||||
"https://vault.bitwarden.com/app-id.json": {
|
||||
b"\x12t;\x92\x12\x97\xb7\x7f\x115\xe4\x1f\xde\xddJ\x84j\xfe\x82\xe1\xf3i2\xa9\x91/;\r\x8d\xfb}\x0e": {
|
||||
"label": "Bitbucket",
|
||||
"use_sign_count": True,
|
||||
},
|
||||
b"0/\xd5\xb4I*\x07\xb9\xfe\xbb0\xe72i\xec\xa5\x01 \\\xcf\xe0\xc2\x0b\xf7\xb4r\xfa-1\xe2\x1ec": {
|
||||
"label": "Bitfinex",
|
||||
"use_sign_count": True,
|
||||
},
|
||||
b"\xa3M0\x9f\xfa(\xc1$\x14\xb8\xbal\x07\xee\x1e\xfa\xe1\xa8^\x8a\x04aHY\xa6|\x04\x93\xb6\x95a\x90": {
|
||||
"label": "Bitwarden",
|
||||
"use_sign_count": True,
|
||||
},
|
||||
"https://www.dashlane.com": {"label": "Dashlane", "use_sign_count": True},
|
||||
"https://www.dropbox.com/u2f-app-id.json": {
|
||||
b"h \x19\x15\xd7L\xb4*\xf5\xb3\xcc\\\x95\xb9U>>:\x83\xb4\xd2\xa9;E\xfb\xad\xaa\x84i\xff\x8en": {
|
||||
"label": "Dashlane",
|
||||
"use_sign_count": True,
|
||||
},
|
||||
b'\xc5\x0f\x8a{p\x8e\x92\xf8.zP\xe2\xbd\xc5]\x8f\xd9\x1a"\xfek)\xc0\xcd\xf7\x80U0\x84*\xf5\x81': {
|
||||
"label": "Dropbox",
|
||||
"use_sign_count": True,
|
||||
},
|
||||
"https://api-9dcf9b83.duosecurity.com": {"label": "Duo", "use_sign_count": True},
|
||||
"https://www.fastmail.com": {"label": "FastMail", "use_sign_count": True},
|
||||
"https://id.fedoraproject.org/u2f-origins.json": {
|
||||
b"\xf3\xe2\x04/\x94`}\xa0\xa9\xc1\xf3\xb9^\r/+\xb2\xe0i\xc5\xbbO\xa7d\xaf\xfad}\x84{~\xd6": {
|
||||
"label": "Duo",
|
||||
"use_sign_count": True,
|
||||
},
|
||||
b"if\xab\xe3gN\xa2\xf50y\xebq\x01\x97\x84\x8c\x9b\xe6\xf3c\x99/\xd0)\xe9\x89\x84G\xcb\x9f\x00\x84": {
|
||||
"label": "FastMail",
|
||||
"use_sign_count": True,
|
||||
},
|
||||
b"\x9daD/\\\xe13\xbdFTO\xc4/\nmT\xc0\xde\xb8\x88@\xca\xc2\xb6\xae\xfae\x14\xf8\x93I\xe9": {
|
||||
"label": "Fedora",
|
||||
"use_sign_count": True,
|
||||
},
|
||||
"https://account.gandi.net/api/u2f/trusted_facets.json": {
|
||||
b"\xa4\xe2-\xca\xfe\xa7\xe9\x0e\x12\x89P\x119\x89\xfcE\x97\x8d\xc9\xfb\x87vu`Ql\x1ci\xdf\xdf\xd1\x96": {
|
||||
"label": "Gandi",
|
||||
"use_sign_count": True,
|
||||
},
|
||||
"https://github.com/u2f/trusted_facets": {
|
||||
b"pa}\xfe\xd0e\x86:\xf4|\x15Ul\x91y\x88\x80\x82\x8c\xc4\x07\xfd\xf7\n\xe8P\x11V\x94e\xa0u": {
|
||||
"label": "GitHub",
|
||||
"use_sign_count": True,
|
||||
},
|
||||
"https://gitlab.com": {"label": "GitLab", "use_sign_count": True},
|
||||
"https://www.gstatic.com/securitykey/origins.json": {
|
||||
b"\xe7\xbe\x96\xa5\x1b\xd0\x19*r\x84\r.Y\t\xf7+\xa8*/\xe9?\xaabO\x039k0\xe4\x94\xc8\x04": {
|
||||
"label": "GitLab",
|
||||
"use_sign_count": True,
|
||||
},
|
||||
b'\xa5Fr\xb2"\xc4\xcf\x95\xe1Q\xed\x8dM<vzl\xc3ICYCyN\x88O=\x02:\x82)\xfd': {
|
||||
"label": "Google",
|
||||
"use_sign_count": True,
|
||||
},
|
||||
"https://keepersecurity.com": {"label": "Keeper", "use_sign_count": True},
|
||||
"https://lastpass.com": {"label": "LastPass", "use_sign_count": True},
|
||||
"https://slushpool.com/static/security/u2f.json": {
|
||||
b"S\xa1[\xa4*|\x03%\xb8\xdb\xee(\x964\xa4\x8fX\xae\xa3$fE\xd5\xffA\x8f\x9b\xb8\x81\x98\x85\xa9": {
|
||||
"label": "Keeper",
|
||||
"use_sign_count": True,
|
||||
},
|
||||
b"\xd6_\x00^\xf4\xde\xa92\x0c\x99s\x05<\x95\xff` \x11]_\xec\x1b\x7f\xeeA\xa5x\xe1\x8d\xf9\xca\x8c": {
|
||||
"label": "Keeper",
|
||||
"use_sign_count": True,
|
||||
},
|
||||
b"\xd7U\xc5'\xa8k\xf7\x84E\xc2\x82\xe7\x13\xdc\xb8mF\xff\x8b<\xaf\xcf\xb7;.\x8c\xbel\x08\x84\xcb$": {
|
||||
"label": "LastPass",
|
||||
"use_sign_count": True,
|
||||
},
|
||||
b"\x08\xb2\xa3\xd4\x199\xaa1f\x84\x93\xcb6\xcd\xccO\x16\xc4\xd9\xb4\xc8#\x8bs\xc2\xf6r\xc03\x00q\x97": {
|
||||
"label": "Slush Pool",
|
||||
"use_sign_count": True,
|
||||
},
|
||||
"https://dashboard.stripe.com": {"label": "Stripe", "use_sign_count": True},
|
||||
"https://u2f.bin.coffee": {"label": "u2f.bin.coffee", "use_sign_count": True},
|
||||
b"8\x80O.\xfft\xf2(\xb7AQ\xc2\x01\xaa\x82\xe7\xe8\xee\xfc\xac\xfe\xcf#\xfa\x14k\x13\xa3vf1O": {
|
||||
"label": "Slush Pool",
|
||||
"use_sign_count": True,
|
||||
},
|
||||
b"*\xc6\xad\t\xa6\xd0w,D\xdas\xa6\x07/\x9d$\x0f\xc6\x85Jp\xd7\x9c\x10$\xff|uYY2\x92": {
|
||||
"label": "Stripe",
|
||||
"use_sign_count": True,
|
||||
},
|
||||
b"\x1b<\x16\xdd/|F\xe2\xb4\xc2\x89\xdc\x16tk\xcc`\xdf\xcf\x0f\xb8\x18\xe12\x15Rn\x14\x08\xe7\xf4h": {
|
||||
"label": "u2f.bin.coffee",
|
||||
"use_sign_count": True,
|
||||
},
|
||||
# WebAuthn
|
||||
"www.binance.com": {"label": "Binance", "use_sign_count": False},
|
||||
"www.dropbox.com": {"label": "Dropbox"},
|
||||
"github.com": {"label": "GitHub", "use_sign_count": True},
|
||||
"google.com": {"label": "Google"},
|
||||
"secure.login.gov": {"label": "login.gov"},
|
||||
"login.microsoft.com": {"label": "Microsoft", "use_sign_count": False},
|
||||
"webauthn.bin.coffee": {"label": "webauthn.bin.coffee"},
|
||||
"webauthn.io": {"label": "WebAuthn.io"},
|
||||
"webauthn.me": {"label": "WebAuthn.me"},
|
||||
"demo.yubico.com": {"label": "demo.yubico.com"},
|
||||
b"\xc3@\x8c\x04G\x88\xae\xa5\xb3\xdf0\x89R\xfd\x8c\xa3\xc7\x0e!\xfe\xf4\xf6\xc1\xc27L\xaa\x1d\xf9\xb2\x8d\xdd": {
|
||||
"label": "Binance",
|
||||
"use_sign_count": False,
|
||||
},
|
||||
b"\x82\xf4\xa8\xc9_\xec\x94\xb2k\xaf\x9e7%\x0e\x95c\xd9\xa3f\xc7\xbe&\x1c\xa4\xdd\x01\x01\xf4\xd5\xef\xcb\x83": {
|
||||
"label": "Dropbox"
|
||||
},
|
||||
b"T\xcee\x1e\xd7\x15\xb4\xaa\xa7U\xee\xce\xbdN\xa0\x95\x08\x15\xb34\xbd\x07\xd1\t\x89>\x960\x18\xcd\xdb\xd9": {
|
||||
"label": "Gandi"
|
||||
},
|
||||
b":\xeb\x00$`8\x1co%\x8e\x83\x95\xd3\x02oW\x1f\r\x9avH\x8d\xcd\x83v9\xb1:\xed1e`": {
|
||||
"label": "GitHub",
|
||||
"use_sign_count": True,
|
||||
},
|
||||
b"\xd4\xc9\xd9\x02s&'\x1a\x89\xceQ\xfc\xaf2\x8e\xd6s\xf1{\xe34i\xff\x97\x9e\x8a\xb8\xddP\x1efO": {
|
||||
"label": "Google"
|
||||
},
|
||||
b"\xf8?\xc3\xa1\xb2\x89\xa0\xde\xc5\xc1\xc8\xaa\x07\xe9\xb5\xdd\x9c\xbbv\xf6\xb2\xf5``\x17frh\xe5\xb9\xc4^": {
|
||||
"label": "login.gov"
|
||||
},
|
||||
b"5l\x9e\xd4\xa0\x93!\xb9i_\x1e\xaf\x91\x82\x03\xf1\xb5_h\x9d\xa6\x1f\xbc\x96\x18L\x15}\xdah\x0c\x81": {
|
||||
"label": "Microsoft",
|
||||
"use_sign_count": False,
|
||||
},
|
||||
b"\xa6B\xd2\x1b|mU\xe1\xce#\xc59\x98(\xd2\xc7I\xbfjn\xf2\xfe\x03\xcc\x9e\x10\xcd\xf4\xedS\x08\x8b": {
|
||||
"label": "webauthn.bin.coffee"
|
||||
},
|
||||
b"t\xa6\xea\x92\x13\xc9\x9c/t\xb2$\x92\xb3 \xcf@&*\x94\xc1\xa9P\xa09\x7f)%\x0b`\x84\x1e\xf0": {
|
||||
"label": "WebAuthn.io"
|
||||
},
|
||||
b"\xf9[\xc78(\xee!\x0f\x9f\xd3\xbb\xe7-\x97\x90\x80\x13\xb0\xa3u\x9e\x9a\xea=\n\xe3\x18vl\xd2\xe1\xad": {
|
||||
"label": "WebAuthn.me"
|
||||
},
|
||||
b"\xc4l\xef\x82\xad\x1bTdwY\x1d\x00\x8b\x08u\x9e\xc3\xe6\xd2\xec\xb4\xf3\x94t\xbf\xeaii\x92]\x03\xb7": {
|
||||
"label": "demo.yubico.com"
|
||||
},
|
||||
}
|
||||
|
||||
knownapps = {sha256(k.encode()).digest(): v for (k, v) in _knownapps.items()}
|
||||
|
@ -40,27 +40,27 @@ static const U2FWellKnown u2f_well_known[] = {
|
||||
"Binance"
|
||||
},
|
||||
{
|
||||
// U2F: https://bitbucket.org
|
||||
// U2F
|
||||
{ 0x12, 0x74, 0x3b, 0x92, 0x12, 0x97, 0xb7, 0x7f, 0x11, 0x35, 0xe4, 0x1f, 0xde, 0xdd, 0x4a, 0x84, 0x6a, 0xfe, 0x82, 0xe1, 0xf3, 0x69, 0x32, 0xa9, 0x91, 0x2f, 0x3b, 0x0d, 0x8d, 0xfb, 0x7d, 0x0e },
|
||||
"Bitbucket"
|
||||
},
|
||||
{
|
||||
// U2F: https://www.bitfinex.com
|
||||
// U2F
|
||||
{ 0x30, 0x2f, 0xd5, 0xb4, 0x49, 0x2a, 0x07, 0xb9, 0xfe, 0xbb, 0x30, 0xe7, 0x32, 0x69, 0xec, 0xa5, 0x01, 0x20, 0x5c, 0xcf, 0xe0, 0xc2, 0x0b, 0xf7, 0xb4, 0x72, 0xfa, 0x2d, 0x31, 0xe2, 0x1e, 0x63 },
|
||||
"Bitfinex"
|
||||
},
|
||||
{
|
||||
// U2F: https://vault.bitwarden.com/app-id.json
|
||||
// U2F
|
||||
{ 0xa3, 0x4d, 0x30, 0x9f, 0xfa, 0x28, 0xc1, 0x24, 0x14, 0xb8, 0xba, 0x6c, 0x07, 0xee, 0x1e, 0xfa, 0xe1, 0xa8, 0x5e, 0x8a, 0x04, 0x61, 0x48, 0x59, 0xa6, 0x7c, 0x04, 0x93, 0xb6, 0x95, 0x61, 0x90 },
|
||||
"Bitwarden"
|
||||
},
|
||||
{
|
||||
// U2F: https://www.dashlane.com
|
||||
// U2F
|
||||
{ 0x68, 0x20, 0x19, 0x15, 0xd7, 0x4c, 0xb4, 0x2a, 0xf5, 0xb3, 0xcc, 0x5c, 0x95, 0xb9, 0x55, 0x3e, 0x3e, 0x3a, 0x83, 0xb4, 0xd2, 0xa9, 0x3b, 0x45, 0xfb, 0xad, 0xaa, 0x84, 0x69, 0xff, 0x8e, 0x6e },
|
||||
"Dashlane"
|
||||
},
|
||||
{
|
||||
// U2F: https://www.dropbox.com/u2f-app-id.json
|
||||
// U2F
|
||||
{ 0xc5, 0x0f, 0x8a, 0x7b, 0x70, 0x8e, 0x92, 0xf8, 0x2e, 0x7a, 0x50, 0xe2, 0xbd, 0xc5, 0x5d, 0x8f, 0xd9, 0x1a, 0x22, 0xfe, 0x6b, 0x29, 0xc0, 0xcd, 0xf7, 0x80, 0x55, 0x30, 0x84, 0x2a, 0xf5, 0x81 },
|
||||
"Dropbox"
|
||||
},
|
||||
@ -70,47 +70,67 @@ static const U2FWellKnown u2f_well_known[] = {
|
||||
"Dropbox"
|
||||
},
|
||||
{
|
||||
// U2F: https://api-9dcf9b83.duosecurity.com
|
||||
// U2F
|
||||
{ 0xf3, 0xe2, 0x04, 0x2f, 0x94, 0x60, 0x7d, 0xa0, 0xa9, 0xc1, 0xf3, 0xb9, 0x5e, 0x0d, 0x2f, 0x2b, 0xb2, 0xe0, 0x69, 0xc5, 0xbb, 0x4f, 0xa7, 0x64, 0xaf, 0xfa, 0x64, 0x7d, 0x84, 0x7b, 0x7e, 0xd6 },
|
||||
"Duo"
|
||||
},
|
||||
{
|
||||
// U2F: https://www.fastmail.com
|
||||
// U2F
|
||||
{ 0x69, 0x66, 0xab, 0xe3, 0x67, 0x4e, 0xa2, 0xf5, 0x30, 0x79, 0xeb, 0x71, 0x01, 0x97, 0x84, 0x8c, 0x9b, 0xe6, 0xf3, 0x63, 0x99, 0x2f, 0xd0, 0x29, 0xe9, 0x89, 0x84, 0x47, 0xcb, 0x9f, 0x00, 0x84 },
|
||||
"FastMail"
|
||||
},
|
||||
{
|
||||
// U2F: https://id.fedoraproject.org/u2f-origins.json
|
||||
// U2F
|
||||
{ 0x9d, 0x61, 0x44, 0x2f, 0x5c, 0xe1, 0x33, 0xbd, 0x46, 0x54, 0x4f, 0xc4, 0x2f, 0x0a, 0x6d, 0x54, 0xc0, 0xde, 0xb8, 0x88, 0x40, 0xca, 0xc2, 0xb6, 0xae, 0xfa, 0x65, 0x14, 0xf8, 0x93, 0x49, 0xe9 },
|
||||
"Fedora"
|
||||
},
|
||||
{
|
||||
// U2F: https://account.gandi.net/api/u2f/trusted_facets.json
|
||||
// U2F
|
||||
{ 0xa4, 0xe2, 0x2d, 0xca, 0xfe, 0xa7, 0xe9, 0x0e, 0x12, 0x89, 0x50, 0x11, 0x39, 0x89, 0xfc, 0x45, 0x97, 0x8d, 0xc9, 0xfb, 0x87, 0x76, 0x75, 0x60, 0x51, 0x6c, 0x1c, 0x69, 0xdf, 0xdf, 0xd1, 0x96 },
|
||||
"Gandi"
|
||||
},
|
||||
{
|
||||
// U2F: https://github.com/u2f/trusted_facets
|
||||
// WebAuthn: gandi.net
|
||||
{ 0x54, 0xce, 0x65, 0x1e, 0xd7, 0x15, 0xb4, 0xaa, 0xa7, 0x55, 0xee, 0xce, 0xbd, 0x4e, 0xa0, 0x95, 0x08, 0x15, 0xb3, 0x34, 0xbd, 0x07, 0xd1, 0x09, 0x89, 0x3e, 0x96, 0x30, 0x18, 0xcd, 0xdb, 0xd9 },
|
||||
"Gandi"
|
||||
},
|
||||
{
|
||||
// U2F
|
||||
{ 0x70, 0x61, 0x7d, 0xfe, 0xd0, 0x65, 0x86, 0x3a, 0xf4, 0x7c, 0x15, 0x55, 0x6c, 0x91, 0x79, 0x88, 0x80, 0x82, 0x8c, 0xc4, 0x07, 0xfd, 0xf7, 0x0a, 0xe8, 0x50, 0x11, 0x56, 0x94, 0x65, 0xa0, 0x75 },
|
||||
"GitHub"
|
||||
},
|
||||
{
|
||||
// U2F: https://gitlab.com
|
||||
// WebAuthn: github.com
|
||||
{ 0x3a, 0xeb, 0x00, 0x24, 0x60, 0x38, 0x1c, 0x6f, 0x25, 0x8e, 0x83, 0x95, 0xd3, 0x02, 0x6f, 0x57, 0x1f, 0x0d, 0x9a, 0x76, 0x48, 0x8d, 0xcd, 0x83, 0x76, 0x39, 0xb1, 0x3a, 0xed, 0x31, 0x65, 0x60 },
|
||||
"GitHub"
|
||||
},
|
||||
{
|
||||
// U2F
|
||||
{ 0xe7, 0xbe, 0x96, 0xa5, 0x1b, 0xd0, 0x19, 0x2a, 0x72, 0x84, 0x0d, 0x2e, 0x59, 0x09, 0xf7, 0x2b, 0xa8, 0x2a, 0x2f, 0xe9, 0x3f, 0xaa, 0x62, 0x4f, 0x03, 0x39, 0x6b, 0x30, 0xe4, 0x94, 0xc8, 0x04 },
|
||||
"GitLab"
|
||||
},
|
||||
{
|
||||
// U2F: https://www.gstatic.com/securitykey/origins.json
|
||||
// U2F
|
||||
{ 0xa5, 0x46, 0x72, 0xb2, 0x22, 0xc4, 0xcf, 0x95, 0xe1, 0x51, 0xed, 0x8d, 0x4d, 0x3c, 0x76, 0x7a, 0x6c, 0xc3, 0x49, 0x43, 0x59, 0x43, 0x79, 0x4e, 0x88, 0x4f, 0x3d, 0x02, 0x3a, 0x82, 0x29, 0xfd },
|
||||
"Google"
|
||||
},
|
||||
{
|
||||
// U2F: https://keepersecurity.com
|
||||
// WebAuthn: google.com
|
||||
{ 0xd4, 0xc9, 0xd9, 0x02, 0x73, 0x26, 0x27, 0x1a, 0x89, 0xce, 0x51, 0xfc, 0xaf, 0x32, 0x8e, 0xd6, 0x73, 0xf1, 0x7b, 0xe3, 0x34, 0x69, 0xff, 0x97, 0x9e, 0x8a, 0xb8, 0xdd, 0x50, 0x1e, 0x66, 0x4f },
|
||||
"Google"
|
||||
},
|
||||
{
|
||||
// U2F
|
||||
{ 0x53, 0xa1, 0x5b, 0xa4, 0x2a, 0x7c, 0x03, 0x25, 0xb8, 0xdb, 0xee, 0x28, 0x96, 0x34, 0xa4, 0x8f, 0x58, 0xae, 0xa3, 0x24, 0x66, 0x45, 0xd5, 0xff, 0x41, 0x8f, 0x9b, 0xb8, 0x81, 0x98, 0x85, 0xa9 },
|
||||
"Keeper"
|
||||
},
|
||||
{
|
||||
// U2F: https://lastpass.com
|
||||
// U2F
|
||||
{ 0xd6, 0x5f, 0x00, 0x5e, 0xf4, 0xde, 0xa9, 0x32, 0x0c, 0x99, 0x73, 0x05, 0x3c, 0x95, 0xff, 0x60, 0x20, 0x11, 0x5d, 0x5f, 0xec, 0x1b, 0x7f, 0xee, 0x41, 0xa5, 0x78, 0xe1, 0x8d, 0xf9, 0xca, 0x8c },
|
||||
"Keeper"
|
||||
},
|
||||
{
|
||||
// U2F
|
||||
{ 0xd7, 0x55, 0xc5, 0x27, 0xa8, 0x6b, 0xf7, 0x84, 0x45, 0xc2, 0x82, 0xe7, 0x13, 0xdc, 0xb8, 0x6d, 0x46, 0xff, 0x8b, 0x3c, 0xaf, 0xcf, 0xb7, 0x3b, 0x2e, 0x8c, 0xbe, 0x6c, 0x08, 0x84, 0xcb, 0x24 },
|
||||
"LastPass"
|
||||
},
|
||||
@ -120,17 +140,27 @@ static const U2FWellKnown u2f_well_known[] = {
|
||||
"login.gov"
|
||||
},
|
||||
{
|
||||
// U2F: https://slushpool.com/static/security/u2f.json
|
||||
// WebAuthn: login.microsoft.com
|
||||
{ 0x35, 0x6c, 0x9e, 0xd4, 0xa0, 0x93, 0x21, 0xb9, 0x69, 0x5f, 0x1e, 0xaf, 0x91, 0x82, 0x03, 0xf1, 0xb5, 0x5f, 0x68, 0x9d, 0xa6, 0x1f, 0xbc, 0x96, 0x18, 0x4c, 0x15, 0x7d, 0xda, 0x68, 0x0c, 0x81 },
|
||||
"Microsoft"
|
||||
},
|
||||
{
|
||||
// U2F
|
||||
{ 0x08, 0xb2, 0xa3, 0xd4, 0x19, 0x39, 0xaa, 0x31, 0x66, 0x84, 0x93, 0xcb, 0x36, 0xcd, 0xcc, 0x4f, 0x16, 0xc4, 0xd9, 0xb4, 0xc8, 0x23, 0x8b, 0x73, 0xc2, 0xf6, 0x72, 0xc0, 0x33, 0x00, 0x71, 0x97 },
|
||||
"Slush Pool"
|
||||
},
|
||||
{
|
||||
// U2F: https://dashboard.stripe.com
|
||||
// U2F
|
||||
{ 0x38, 0x80, 0x4f, 0x2e, 0xff, 0x74, 0xf2, 0x28, 0xb7, 0x41, 0x51, 0xc2, 0x01, 0xaa, 0x82, 0xe7, 0xe8, 0xee, 0xfc, 0xac, 0xfe, 0xcf, 0x23, 0xfa, 0x14, 0x6b, 0x13, 0xa3, 0x76, 0x66, 0x31, 0x4f },
|
||||
"Slush Pool"
|
||||
},
|
||||
{
|
||||
// U2F
|
||||
{ 0x2a, 0xc6, 0xad, 0x09, 0xa6, 0xd0, 0x77, 0x2c, 0x44, 0xda, 0x73, 0xa6, 0x07, 0x2f, 0x9d, 0x24, 0x0f, 0xc6, 0x85, 0x4a, 0x70, 0xd7, 0x9c, 0x10, 0x24, 0xff, 0x7c, 0x75, 0x59, 0x59, 0x32, 0x92 },
|
||||
"Stripe"
|
||||
},
|
||||
{
|
||||
// U2F: https://u2f.bin.coffee
|
||||
// U2F
|
||||
{ 0x1b, 0x3c, 0x16, 0xdd, 0x2f, 0x7c, 0x46, 0xe2, 0xb4, 0xc2, 0x89, 0xdc, 0x16, 0x74, 0x6b, 0xcc, 0x60, 0xdf, 0xcf, 0x0f, 0xb8, 0x18, 0xe1, 0x32, 0x15, 0x52, 0x6e, 0x14, 0x08, 0xe7, 0xf4, 0x68 },
|
||||
"u2f.bin.coffee"
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user