def msg_authenticate_genkey(app_id: bytes, keyhandle: bytes): from apps.common import seed # unpack the keypath from the first half of keyhandle keybuf = keyhandle[:32] keypath = ustruct.unpack('>8L', keybuf) # check high bit for hardened keys for i in keypath: if not i & 0x80000000: log.warning(__name__, 'invalid key path') return None # derive the signing key nodepath = [_U2F_KEY_PATH] + list(keypath) node = seed.get_root_without_passphrase('nist256p1') node.derive_path(nodepath) # second half of keyhandle is a hmac of app_id and keypath keybase = hmac.Hmac(node.private_key(), app_id, hashlib.sha256) keybase.update(keybuf) keybase = keybase.digest() # verify the hmac if keybase != keyhandle[32:]: log.warning(__name__, 'invalid key handle') return None return node
def msg_register_sign(challenge: bytes, app_id: bytes) -> bytes: from apps.common import seed # derivation path is m/U2F'/r'/r'/r'/r'/r'/r'/r'/r' keypath = [0x80000000 | random.uniform(0xf0000000) for _ in range(0, 8)] nodepath = [_U2F_KEY_PATH] + keypath # prepare signing key from random path, compute decompressed public key node = seed.get_root_without_passphrase('nist256p1') node.derive_path(nodepath) pubkey = nist256p1.publickey(node.private_key(), False) # first half of keyhandle is keypath keybuf = ustruct.pack('>8L', *keypath) # second half of keyhandle is a hmac of app_id and keypath keybase = hmac.Hmac(node.private_key(), app_id, hashlib.sha256) keybase.update(keybuf) keybase = keybase.digest() # hash the request data together with keyhandle and pubkey dig = hashlib.sha256() dig.update(b'\x00') # uint8_t reserved; dig.update(app_id) # uint8_t appId[32]; dig.update(challenge) # uint8_t chal[32]; dig.update(keybuf) # uint8_t keyHandle[64]; dig.update(keybase) dig.update(pubkey) # uint8_t pubKey[65]; dig = dig.digest() # sign the digest and convert to der sig = nist256p1.sign(_U2F_ATT_PRIV_KEY, dig, False) sig = der.encode_seq((sig[1:33], sig[33:])) # pack to a response buf, resp = make_struct( resp_cmd_register( len(keybuf) + len(keybase), len(_U2F_ATT_CERT), len(sig))) resp.registerId = _U2F_REGISTER_ID utils.memcpy(resp.pubKey, 0, pubkey, 0, len(pubkey)) resp.keyHandleLen = len(keybuf) + len(keybase) utils.memcpy(resp.keyHandle, 0, keybuf, 0, len(keybuf)) utils.memcpy(resp.keyHandle, len(keybuf), keybase, 0, len(keybase)) utils.memcpy(resp.cert, 0, _U2F_ATT_CERT, 0, len(_U2F_ATT_CERT)) utils.memcpy(resp.sig, 0, sig, 0, len(sig)) resp.status = _SW_NO_ERROR return buf