blob: fdef660eb325bbe20f9d325ddeb0a00d21c53ec4 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/webauth/authenticator_impl.h"
#include <string>
#include "base/base64url.h"
#include "base/run_loop.h"
#include "base/test/gtest_util.h"
#include "content/browser/webauth/attestation_data.h"
#include "content/browser/webauth/attestation_object.h"
#include "content/browser/webauth/authenticator_data.h"
#include "content/browser/webauth/authenticator_utils.h"
#include "content/browser/webauth/cbor/cbor_writer.h"
#include "content/browser/webauth/collected_client_data.h"
#include "content/browser/webauth/ec_public_key.h"
#include "content/browser/webauth/fido_attestation_statement.h"
#include "content/browser/webauth/register_response_data.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/navigation_simulator.h"
#include "content/public/test/test_renderer_host.h"
#include "content/test/test_render_frame_host.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
using ::testing::_;
using webauth::mojom::AuthenticatorPtr;
using webauth::mojom::AuthenticatorStatus;
using webauth::mojom::MakeCredentialOptions;
using webauth::mojom::MakeCredentialOptionsPtr;
using webauth::mojom::PublicKeyCredentialEntity;
using webauth::mojom::PublicKeyCredentialEntityPtr;
using webauth::mojom::PublicKeyCredentialInfoPtr;
using webauth::mojom::PublicKeyCredentialParameters;
using webauth::mojom::PublicKeyCredentialParametersPtr;
namespace {
constexpr char kTestOrigin1[] = "https://google.com";
// Test data. CBOR test data can be built using the given diagnostic strings
// and the utility at "http://cbor.me/".
constexpr int32_t kCoseEs256 = -7;
constexpr char kTestRelyingPartyId[] = "google.com";
constexpr uint8_t kTestChallengeBytes[] = {
0x68, 0x71, 0x34, 0x96, 0x82, 0x22, 0xEC, 0x17, 0x20, 0x2E, 0x42,
0x50, 0x5F, 0x8E, 0xD2, 0xB1, 0x6A, 0xE2, 0x2F, 0x16, 0xBB, 0x05,
0xB8, 0x8C, 0x25, 0xDB, 0x9E, 0x60, 0x26, 0x45, 0xF1, 0x41};
constexpr char kTestClientDataJsonString[] =
"{\"challenge\":\"aHE0loIi7BcgLkJQX47SsWriLxa7BbiMJdueYCZF8UE\",\"hashAlg\""
":\"SHA-256\",\"origin\":\"google.com\",\"tokenBinding\":\"unused\"}";
constexpr uint8_t kTestCredentialRawIdBytes[] = {
0x89, 0xAF, 0xB5, 0x24, 0x91, 0x1C, 0x40, 0x2B, 0x7F, 0x74, 0x59,
0xC9, 0xF2, 0x21, 0xAF, 0xE6, 0xE5, 0x56, 0x65, 0x85, 0x04, 0xE8,
0x5B, 0x49, 0x4D, 0x07, 0x55, 0x55, 0xF4, 0x6A, 0xBC, 0x44, 0x7B,
0x15, 0xFC, 0x62, 0x61, 0x90, 0xA5, 0xFE, 0xEB, 0xE5, 0x9F, 0x5E,
0xDC, 0x75, 0x32, 0x98, 0x6F, 0x44, 0x69, 0xD7, 0xF6, 0x13, 0xEB,
0xAA, 0xEA, 0x33, 0xFB, 0xD5, 0x8E, 0xBF, 0xC6, 0x09};
// CBOR-encoded EC public key.
// Diagnostic notation:
// {"x": h'F868CE3869605224CE1059C0047EF01B830F2AD93BE27A3211F44E894560E695',
// "y": h'4E11538CABA2DF1CC1A6F250ED9F0C8B28B39DA44539DFABD46B589CD0E202E5',
// "alg": "ES256"}
constexpr uint8_t kTestECPublicKeyCBOR[] = {
// clang-format off
0xA3, // map(3)
0x61, // text(1)
0x78, // "x"
0x58, 0x20, // bytes(32)
0xF8, 0x68, 0xCE, 0x38, 0x69, 0x60, 0x52, 0x24, 0xCE, 0x10, 0x59, 0xC0,
0x04, 0x7E, 0xF0, 0x1B, 0x83, 0x0F, 0x2A, 0xD9, 0x3B, 0xE2, 0x7A, 0x32,
0x11, 0xF4, 0x4E, 0x89, 0x45, 0x60, 0xE6, 0x95,
0x61, // text(1)
0x79, // "y"
0x58, 0x20, // bytes(32)
0x4E, 0x11, 0x53, 0x8C, 0xAB, 0xA2, 0xDF, 0x1C, 0xC1, 0xA6, 0xF2, 0x50,
0xED, 0x9F, 0x0C, 0x8B, 0x28, 0xB3, 0x9D, 0xA4, 0x45, 0x39, 0xDF, 0xAB,
0xD4, 0x6B, 0x58, 0x9C, 0xD0, 0xE2, 0x02, 0xE5,
0x63, // text(3)
0x61, 0x6C, 0x67, // "alg"
0x65, // text(5)
0x45, 0x53, 0x32, 0x35, 0x36, // "ES256"
// clang-format on
};
// U2F response blob produced by a U2F registration request. This example
// data uses testClientDataJson and 'created' a key with testCredentialRawId
// as its key handle and with the above x- and y- coordinates.
constexpr uint8_t kTestU2fRegisterResponse[] = {
0x05, 0x04, 0xF8, 0x68, 0xCE, 0x38, 0x69, 0x60, 0x52, 0x24, 0xCE, 0x10,
0x59, 0xC0, 0x04, 0x7E, 0xF0, 0x1B, 0x83, 0x0F, 0x2A, 0xD9, 0x3B, 0xE2,
0x7A, 0x32, 0x11, 0xF4, 0x4E, 0x89, 0x45, 0x60, 0xE6, 0x95, 0x4E, 0x11,
0x53, 0x8C, 0xAB, 0xA2, 0xDF, 0x1C, 0xC1, 0xA6, 0xF2, 0x50, 0xED, 0x9F,
0x0C, 0x8B, 0x28, 0xB3, 0x9D, 0xA4, 0x45, 0x39, 0xDF, 0xAB, 0xD4, 0x6B,
0x58, 0x9C, 0xD0, 0xE2, 0x02, 0xE5, 0x40, 0x89, 0xAF, 0xB5, 0x24, 0x91,
0x1C, 0x40, 0x2B, 0x7F, 0x74, 0x59, 0xC9, 0xF2, 0x21, 0xAF, 0xE6, 0xE5,
0x56, 0x65, 0x85, 0x04, 0xE8, 0x5B, 0x49, 0x4D, 0x07, 0x55, 0x55, 0xF4,
0x6A, 0xBC, 0x44, 0x7B, 0x15, 0xFC, 0x62, 0x61, 0x90, 0xA5, 0xFE, 0xEB,
0xE5, 0x9F, 0x5E, 0xDC, 0x75, 0x32, 0x98, 0x6F, 0x44, 0x69, 0xD7, 0xF6,
0x13, 0xEB, 0xAA, 0xEA, 0x33, 0xFB, 0xD5, 0x8E, 0xBF, 0xC6, 0x09, 0x30,
0x82, 0x02, 0x4A, 0x30, 0x82, 0x01, 0x32, 0xA0, 0x03, 0x02, 0x01, 0x02,
0x02, 0x04, 0x04, 0x6C, 0x88, 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86,
0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x30, 0x2E, 0x31,
0x2C, 0x30, 0x2A, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x23, 0x59, 0x75,
0x62, 0x69, 0x63, 0x6F, 0x20, 0x55, 0x32, 0x46, 0x20, 0x52, 0x6F, 0x6F,
0x74, 0x20, 0x43, 0x41, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6C, 0x20,
0x34, 0x35, 0x37, 0x32, 0x30, 0x30, 0x36, 0x33, 0x31, 0x30, 0x20, 0x17,
0x0D, 0x31, 0x34, 0x30, 0x38, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x5A, 0x18, 0x0F, 0x32, 0x30, 0x35, 0x30, 0x30, 0x39, 0x30, 0x34,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A, 0x30, 0x2C, 0x31, 0x2A, 0x30,
0x28, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x21, 0x59, 0x75, 0x62, 0x69,
0x63, 0x6F, 0x20, 0x55, 0x32, 0x46, 0x20, 0x45, 0x45, 0x20, 0x53, 0x65,
0x72, 0x69, 0x61, 0x6C, 0x20, 0x32, 0x34, 0x39, 0x31, 0x38, 0x32, 0x33,
0x32, 0x34, 0x37, 0x37, 0x30, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A,
0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE,
0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x3C, 0xCA, 0xB9, 0x2C,
0xCB, 0x97, 0x28, 0x7E, 0xE8, 0xE6, 0x39, 0x43, 0x7E, 0x21, 0xFC, 0xD6,
0xB6, 0xF1, 0x65, 0xB2, 0xD5, 0xA3, 0xF3, 0xDB, 0x13, 0x1D, 0x31, 0xC1,
0x6B, 0x74, 0x2B, 0xB4, 0x76, 0xD8, 0xD1, 0xE9, 0x90, 0x80, 0xEB, 0x54,
0x6C, 0x9B, 0xBD, 0xF5, 0x56, 0xE6, 0x21, 0x0F, 0xD4, 0x27, 0x85, 0x89,
0x9E, 0x78, 0xCC, 0x58, 0x9E, 0xBE, 0x31, 0x0F, 0x6C, 0xDB, 0x9F, 0xF4,
0xA3, 0x3B, 0x30, 0x39, 0x30, 0x22, 0x06, 0x09, 0x2B, 0x06, 0x01, 0x04,
0x01, 0x82, 0xC4, 0x0A, 0x02, 0x04, 0x15, 0x31, 0x2E, 0x33, 0x2E, 0x36,
0x2E, 0x31, 0x2E, 0x34, 0x2E, 0x31, 0x2E, 0x34, 0x31, 0x34, 0x38, 0x32,
0x2E, 0x31, 0x2E, 0x32, 0x30, 0x13, 0x06, 0x0B, 0x2B, 0x06, 0x01, 0x04,
0x01, 0x82, 0xE5, 0x1C, 0x02, 0x01, 0x01, 0x04, 0x04, 0x03, 0x02, 0x04,
0x30, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01,
0x01, 0x0B, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x9F, 0x9B, 0x05,
0x22, 0x48, 0xBC, 0x4C, 0xF4, 0x2C, 0xC5, 0x99, 0x1F, 0xCA, 0xAB, 0xAC,
0x9B, 0x65, 0x1B, 0xBE, 0x5B, 0xDC, 0xDC, 0x8E, 0xF0, 0xAD, 0x2C, 0x1C,
0x1F, 0xFB, 0x36, 0xD1, 0x87, 0x15, 0xD4, 0x2E, 0x78, 0xB2, 0x49, 0x22,
0x4F, 0x92, 0xC7, 0xE6, 0xE7, 0xA0, 0x5C, 0x49, 0xF0, 0xE7, 0xE4, 0xC8,
0x81, 0xBF, 0x2E, 0x94, 0xF4, 0x5E, 0x4A, 0x21, 0x83, 0x3D, 0x74, 0x56,
0x85, 0x1D, 0x0F, 0x6C, 0x14, 0x5A, 0x29, 0x54, 0x0C, 0x87, 0x4F, 0x30,
0x92, 0xC9, 0x34, 0xB4, 0x3D, 0x22, 0x2B, 0x89, 0x62, 0xC0, 0xF4, 0x10,
0xCE, 0xF1, 0xDB, 0x75, 0x89, 0x2A, 0xF1, 0x16, 0xB4, 0x4A, 0x96, 0xF5,
0xD3, 0x5A, 0xDE, 0xA3, 0x82, 0x2F, 0xC7, 0x14, 0x6F, 0x60, 0x04, 0x38,
0x5B, 0xCB, 0x69, 0xB6, 0x5C, 0x99, 0xE7, 0xEB, 0x69, 0x19, 0x78, 0x67,
0x03, 0xC0, 0xD8, 0xCD, 0x41, 0xE8, 0xF7, 0x5C, 0xCA, 0x44, 0xAA, 0x8A,
0xB7, 0x25, 0xAD, 0x8E, 0x79, 0x9F, 0xF3, 0xA8, 0x69, 0x6A, 0x6F, 0x1B,
0x26, 0x56, 0xE6, 0x31, 0xB1, 0xE4, 0x01, 0x83, 0xC0, 0x8F, 0xDA, 0x53,
0xFA, 0x4A, 0x8F, 0x85, 0xA0, 0x56, 0x93, 0x94, 0x4A, 0xE1, 0x79, 0xA1,
0x33, 0x9D, 0x00, 0x2D, 0x15, 0xCA, 0xBD, 0x81, 0x00, 0x90, 0xEC, 0x72,
0x2E, 0xF5, 0xDE, 0xF9, 0x96, 0x5A, 0x37, 0x1D, 0x41, 0x5D, 0x62, 0x4B,
0x68, 0xA2, 0x70, 0x7C, 0xAD, 0x97, 0xBC, 0xDD, 0x17, 0x85, 0xAF, 0x97,
0xE2, 0x58, 0xF3, 0x3D, 0xF5, 0x6A, 0x03, 0x1A, 0xA0, 0x35, 0x6D, 0x8E,
0x8D, 0x5E, 0xBC, 0xAD, 0xC7, 0x4E, 0x07, 0x16, 0x36, 0xC6, 0xB1, 0x10,
0xAC, 0xE5, 0xCC, 0x9B, 0x90, 0xDF, 0xEA, 0xCA, 0xE6, 0x40, 0xFF, 0x1B,
0xB0, 0xF1, 0xFE, 0x5D, 0xB4, 0xEF, 0xF7, 0xA9, 0x5F, 0x06, 0x07, 0x33,
0xF5, 0x30, 0x44, 0x02, 0x20, 0x08, 0xC3, 0xF8, 0xDB, 0x6E, 0x29, 0xFD,
0x8B, 0x14, 0xD9, 0xDE, 0x1B, 0xD9, 0x8E, 0x84, 0x07, 0x2C, 0xB8, 0x13,
0x38, 0x59, 0x89, 0xAA, 0x2C, 0xA2, 0x89, 0x39, 0x5E, 0x00, 0x09, 0xB8,
0xB7, 0x02, 0x20, 0x26, 0x07, 0xB4, 0xF9, 0xAD, 0x05, 0xDE, 0x26, 0xF5,
0x6F, 0x48, 0xB8, 0x25, 0x69, 0xEA, 0xD8, 0x23, 0x1A, 0x5A, 0x6C, 0x3A,
0x14, 0x48, 0xDE, 0xAA, 0xAF, 0x15, 0xC0, 0xEF, 0x29, 0x63, 0x1A};
// The attestation data, excluding the CBOR public key bytes. Append with
// kTestECPublicKeyCBOR to get the complete attestation data.
constexpr uint8_t kTestAttestationDataPrefix[] = {
// clang-format off
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, // 16-byte aaguid
0x00, 0x40, // 2-byte length
0x89, 0xAF, 0xB5, 0x24, 0x91, 0x1C, 0x40, 0x2B, 0x7F, 0x74, 0x59, 0xC9,
0xF2, 0x21, 0xAF, 0xE6, 0xE5, 0x56, 0x65, 0x85, 0x04, 0xE8, 0x5B, 0x49,
0x4D, 0x07, 0x55, 0x55, 0xF4, 0x6A, 0xBC, 0x44, 0x7B, 0x15, 0xFC, 0x62,
0x61, 0x90, 0xA5, 0xFE, 0xEB, 0xE5, 0x9F, 0x5E, 0xDC, 0x75, 0x32, 0x98,
0x6F, 0x44, 0x69, 0xD7, 0xF6, 0x13, 0xEB, 0xAA, 0xEA, 0x33, 0xFB, 0xD5,
0x8E, 0xBF, 0xC6, 0x09 //64-byte key handle
// clang-format on
};
// The authenticator data, excluding the attestation data bytes. Append with
// attestation data to get the complete authenticator data.
constexpr uint8_t kTestAuthenticatorDataPrefix[] = {
// clang-format off
// sha256 hash of kTestRelyingPartyId
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,
0x41, // flags (TUP and AT bits set)
0x00, 0x00, 0x00, 0x00 //counter
// clang-format on
};
// The attestation statement, a CBOR-encoded byte array.
// Diagnostic notation:
// {"sig":
// h'3044022008C3F8DB6E29FD8B14D9DE1BD98E84072CB813385989AA2CA289395E0009B8B70 \
// 2202607B4F9AD05DE26F56F48B82569EAD8231A5A6C3A1448DEAAAF15C0EF29631A',
// "x5c": [h'3082024A30820132A0030201020204046C8822300D06092A864886F70D01010B0 \
// 500302E312C302A0603550403132359756269636F2055324620526F6F742043412053657269 \
// 616C203435373230303633313020170D3134303830313030303030305A180F3230353030393 \
// 0343030303030305A302C312A302806035504030C2159756269636F20553246204545205365 \
// 7269616C203234393138323332343737303059301306072A8648CE3D020106082A8648CE3D0 \
// 30107034200043CCAB92CCB97287EE8E639437E21FCD6B6F165B2D5A3F3DB131D31C16B742B \
// B476D8D1E99080EB546C9BBDF556E6210FD42785899E78CC589EBE310F6CDB9FF4A33B30393 \
// 02206092B0601040182C40A020415312E332E362E312E342E312E34313438322E312E323013 \
// 060B2B0601040182E51C020101040403020430300D06092A864886F70D01010B05000382010 \
// 1009F9B052248BC4CF42CC5991FCAABAC9B651BBE5BDCDC8EF0AD2C1C1FFB36D18715D42E78 \
// B249224F92C7E6E7A05C49F0E7E4C881BF2E94F45E4A21833D7456851D0F6C145A29540C874 \
// F3092C934B43D222B8962C0F410CEF1DB75892AF116B44A96F5D35ADEA3822FC7146F600438 \
// 5BCB69B65C99E7EB6919786703C0D8CD41E8F75CCA44AA8AB725AD8E799FF3A8696A6F1B265 \
// 6E631B1E40183C08FDA53FA4A8F85A05693944AE179A1339D002D15CABD810090EC722EF5DE \
// F9965A371D415D624B68A2707CAD97BCDD1785AF97E258F33DF56A031AA0356D8E8D5EBCADC \
// 74E071636C6B110ACE5CC9B90DFEACAE640FF1BB0F1FE5DB4EFF7A95F060733F5']}
constexpr uint8_t kU2fAttestationStatementCBOR[] = {
// clang-format off
0xA2, // map(2)
0x63, // text(3)
0x73, 0x69, 0x67, // "sig"
0x58, 0x46, // bytes(70)
0x30, 0x44, 0x02, 0x20, 0x08, 0xC3, 0xF8, 0xDB, 0x6E, 0x29, 0xFD, 0x8B,
0x14, 0xD9, 0xDE, 0x1B, 0xD9, 0x8E, 0x84, 0x07, 0x2C, 0xB8, 0x13, 0x38,
0x59, 0x89, 0xAA, 0x2C, 0xA2, 0x89, 0x39, 0x5E, 0x00, 0x09, 0xB8, 0xB7,
0x02, 0x20, 0x26, 0x07, 0xB4, 0xF9, 0xAD, 0x05, 0xDE, 0x26, 0xF5, 0x6F,
0x48, 0xB8, 0x25, 0x69, 0xEA, 0xD8, 0x23, 0x1A, 0x5A, 0x6C, 0x3A, 0x14,
0x48, 0xDE, 0xAA, 0xAF, 0x15, 0xC0, 0xEF, 0x29, 0x63, 0x1A,
0x63, // text(3)
0x78, 0x35, 0x63, // "x5c"
0x81, // array(1)
0x59, 0x02, 0x4E, // bytes(590)
0x30, 0x82, 0x02, 0x4A, 0x30, 0x82, 0x01, 0x32, 0xA0, 0x03, 0x02,
0x01, 0x02, 0x02, 0x04, 0x04, 0x6C, 0x88, 0x22, 0x30, 0x0D, 0x06,
0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05,
0x00, 0x30, 0x2E, 0x31, 0x2C, 0x30, 0x2A, 0x06, 0x03, 0x55, 0x04,
0x03, 0x13, 0x23, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6F, 0x20, 0x55,
0x32, 0x46, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x43, 0x41, 0x20,
0x53, 0x65, 0x72, 0x69, 0x61, 0x6C, 0x20, 0x34, 0x35, 0x37, 0x32,
0x30, 0x30, 0x36, 0x33, 0x31, 0x30, 0x20, 0x17, 0x0D, 0x31, 0x34,
0x30, 0x38, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A,
0x18, 0x0F, 0x32, 0x30, 0x35, 0x30, 0x30, 0x39, 0x30, 0x34, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x5A, 0x30, 0x2C, 0x31, 0x2A, 0x30,
0x28, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x21, 0x59, 0x75, 0x62,
0x69, 0x63, 0x6F, 0x20, 0x55, 0x32, 0x46, 0x20, 0x45, 0x45, 0x20,
0x53, 0x65, 0x72, 0x69, 0x61, 0x6C, 0x20, 0x32, 0x34, 0x39, 0x31,
0x38, 0x32, 0x33, 0x32, 0x34, 0x37, 0x37, 0x30, 0x30, 0x59, 0x30,
0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06,
0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42,
0x00, 0x04, 0x3C, 0xCA, 0xB9, 0x2C, 0xCB, 0x97, 0x28, 0x7E, 0xE8,
0xE6, 0x39, 0x43, 0x7E, 0x21, 0xFC, 0xD6, 0xB6, 0xF1, 0x65, 0xB2,
0xD5, 0xA3, 0xF3, 0xDB, 0x13, 0x1D, 0x31, 0xC1, 0x6B, 0x74, 0x2B,
0xB4, 0x76, 0xD8, 0xD1, 0xE9, 0x90, 0x80, 0xEB, 0x54, 0x6C, 0x9B,
0xBD, 0xF5, 0x56, 0xE6, 0x21, 0x0F, 0xD4, 0x27, 0x85, 0x89, 0x9E,
0x78, 0xCC, 0x58, 0x9E, 0xBE, 0x31, 0x0F, 0x6C, 0xDB, 0x9F, 0xF4,
0xA3, 0x3B, 0x30, 0x39, 0x30, 0x22, 0x06, 0x09, 0x2B, 0x06, 0x01,
0x04, 0x01, 0x82, 0xC4, 0x0A, 0x02, 0x04, 0x15, 0x31, 0x2E, 0x33,
0x2E, 0x36, 0x2E, 0x31, 0x2E, 0x34, 0x2E, 0x31, 0x2E, 0x34, 0x31,
0x34, 0x38, 0x32, 0x2E, 0x31, 0x2E, 0x32, 0x30, 0x13, 0x06, 0x0B,
0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xE5, 0x1C, 0x02, 0x01, 0x01,
0x04, 0x04, 0x03, 0x02, 0x04, 0x30, 0x30, 0x0D, 0x06, 0x09, 0x2A,
0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x03,
0x82, 0x01, 0x01, 0x00, 0x9F, 0x9B, 0x05, 0x22, 0x48, 0xBC, 0x4C,
0xF4, 0x2C, 0xC5, 0x99, 0x1F, 0xCA, 0xAB, 0xAC, 0x9B, 0x65, 0x1B,
0xBE, 0x5B, 0xDC, 0xDC, 0x8E, 0xF0, 0xAD, 0x2C, 0x1C, 0x1F, 0xFB,
0x36, 0xD1, 0x87, 0x15, 0xD4, 0x2E, 0x78, 0xB2, 0x49, 0x22, 0x4F,
0x92, 0xC7, 0xE6, 0xE7, 0xA0, 0x5C, 0x49, 0xF0, 0xE7, 0xE4, 0xC8,
0x81, 0xBF, 0x2E, 0x94, 0xF4, 0x5E, 0x4A, 0x21, 0x83, 0x3D, 0x74,
0x56, 0x85, 0x1D, 0x0F, 0x6C, 0x14, 0x5A, 0x29, 0x54, 0x0C, 0x87,
0x4F, 0x30, 0x92, 0xC9, 0x34, 0xB4, 0x3D, 0x22, 0x2B, 0x89, 0x62,
0xC0, 0xF4, 0x10, 0xCE, 0xF1, 0xDB, 0x75, 0x89, 0x2A, 0xF1, 0x16,
0xB4, 0x4A, 0x96, 0xF5, 0xD3, 0x5A, 0xDE, 0xA3, 0x82, 0x2F, 0xC7,
0x14, 0x6F, 0x60, 0x04, 0x38, 0x5B, 0xCB, 0x69, 0xB6, 0x5C, 0x99,
0xE7, 0xEB, 0x69, 0x19, 0x78, 0x67, 0x03, 0xC0, 0xD8, 0xCD, 0x41,
0xE8, 0xF7, 0x5C, 0xCA, 0x44, 0xAA, 0x8A, 0xB7, 0x25, 0xAD, 0x8E,
0x79, 0x9F, 0xF3, 0xA8, 0x69, 0x6A, 0x6F, 0x1B, 0x26, 0x56, 0xE6,
0x31, 0xB1, 0xE4, 0x01, 0x83, 0xC0, 0x8F, 0xDA, 0x53, 0xFA, 0x4A,
0x8F, 0x85, 0xA0, 0x56, 0x93, 0x94, 0x4A, 0xE1, 0x79, 0xA1, 0x33,
0x9D, 0x00, 0x2D, 0x15, 0xCA, 0xBD, 0x81, 0x00, 0x90, 0xEC, 0x72,
0x2E, 0xF5, 0xDE, 0xF9, 0x96, 0x5A, 0x37, 0x1D, 0x41, 0x5D, 0x62,
0x4B, 0x68, 0xA2, 0x70, 0x7C, 0xAD, 0x97, 0xBC, 0xDD, 0x17, 0x85,
0xAF, 0x97, 0xE2, 0x58, 0xF3, 0x3D, 0xF5, 0x6A, 0x03, 0x1A, 0xA0,
0x35, 0x6D, 0x8E, 0x8D, 0x5E, 0xBC, 0xAD, 0xC7, 0x4E, 0x07, 0x16,
0x36, 0xC6, 0xB1, 0x10, 0xAC, 0xE5, 0xCC, 0x9B, 0x90, 0xDF, 0xEA,
0xCA, 0xE6, 0x40, 0xFF, 0x1B, 0xB0, 0xF1, 0xFE, 0x5D, 0xB4, 0xEF,
0xF7, 0xA9, 0x5F, 0x06, 0x07, 0x33, 0xF5
// clang-format on
};
// Components of the CBOR needed to form an authenticator object.
// Combined diagnostic notation:
// {"fmt": "fido-u2f", "attStmt": {"sig": h'30...}, "authData": h'D4C9D9...'}
constexpr uint8_t kFormatFidoU2fCBOR[] = {
// clang-format off
0xA3, // map(3)
0x63, // text(3)
0x66, 0x6D, 0x74, // "fmt"
0x68, // text(8)
0x66, 0x69, 0x64, 0x6F, 0x2D, 0x75, 0x32, 0x66 // "fido-u2f"
// clang-format on
};
constexpr uint8_t kAttStmtCBOR[] = {
// clang-format off
0x67, // text(7)
0x61, 0x74, 0x74, 0x53, 0x74, 0x6D, 0x74 // "attStmt"
// clang-format on
};
constexpr uint8_t kAuthDataCBOR[] = {
// clang-format off
0x68, // text(8)
0x61, 0x75, 0x74, 0x68, 0x44, 0x61, 0x74, 0x61, // "authData"
0x58, 0xCA //bytes(202). i.e.,the authenticator_data bytearray
// clang-format on
};
// Helpers.
const std::vector<uint8_t>& GetTestECPublicKeyCBOR() {
static const std::vector<uint8_t> data(std::begin(kTestECPublicKeyCBOR),
std::end(kTestECPublicKeyCBOR));
return data;
}
const std::vector<uint8_t>& GetTestRegisterResponse() {
static const std::vector<uint8_t> data(std::begin(kTestU2fRegisterResponse),
std::end(kTestU2fRegisterResponse));
return data;
}
const std::vector<uint8_t>& GetTestCredentialRawIdBytes() {
static const std::vector<uint8_t> data(std::begin(kTestCredentialRawIdBytes),
std::end(kTestCredentialRawIdBytes));
return data;
}
const std::vector<uint8_t>& GetTestChallengeBytes() {
static const std::vector<uint8_t> data(std::begin(kTestChallengeBytes),
std::end(kTestChallengeBytes));
return data;
}
const std::vector<uint8_t>& GetU2fAttestationStatementCBOR() {
static const std::vector<uint8_t> data(
std::begin(kU2fAttestationStatementCBOR),
std::end(kU2fAttestationStatementCBOR));
return data;
}
PublicKeyCredentialEntityPtr GetTestPublicKeyCredentialRPEntity() {
auto entity = PublicKeyCredentialEntity::New();
entity->id = std::string("localhost");
entity->name = std::string("TestRP@example.com");
return entity;
}
PublicKeyCredentialEntityPtr GetTestPublicKeyCredentialUserEntity() {
auto entity = PublicKeyCredentialEntity::New();
entity->display_name = std::string("User A. Name");
entity->id = std::string("1098237235409872");
entity->name = std::string("username@example.com");
entity->icon = GURL("fakeurl2.png");
return entity;
}
std::vector<PublicKeyCredentialParametersPtr>
GetTestPublicKeyCredentialParameters(int32_t algorithm_identifier) {
std::vector<PublicKeyCredentialParametersPtr> parameters;
auto fake_parameter = PublicKeyCredentialParameters::New();
fake_parameter->type = webauth::mojom::PublicKeyCredentialType::PUBLIC_KEY;
fake_parameter->algorithm_identifier = algorithm_identifier;
parameters.push_back(std::move(fake_parameter));
return parameters;
}
MakeCredentialOptionsPtr GetTestMakeCredentialOptions() {
auto options = MakeCredentialOptions::New();
std::vector<uint8_t> buffer(32, 0x0A);
options->relying_party = GetTestPublicKeyCredentialRPEntity();
options->user = GetTestPublicKeyCredentialUserEntity();
options->crypto_parameters = GetTestPublicKeyCredentialParameters(kCoseEs256);
options->challenge = std::move(buffer);
options->adjusted_timeout = base::TimeDelta::FromMinutes(1);
return options;
}
std::unique_ptr<CollectedClientData> GetTestClientData() {
std::unique_ptr<CollectedClientData> client_data =
CollectedClientData::Create(kTestRelyingPartyId, GetTestChallengeBytes());
return client_data;
}
std::vector<uint8_t> GetTestAttestationDataBytes() {
// Combine kTestAttestationDataPrefix and kTestECPublicKeyCBOR.
std::vector<uint8_t> test_attestation_data(
std::begin(kTestAttestationDataPrefix),
std::end(kTestAttestationDataPrefix));
test_attestation_data.insert(test_attestation_data.end(),
std::begin(kTestECPublicKeyCBOR),
std::end(kTestECPublicKeyCBOR));
return test_attestation_data;
}
std::vector<uint8_t> GetTestAuthenticatorDataBytes() {
// Build the test authenticator data.
std::vector<uint8_t> test_authenticator_data(
std::begin(kTestAuthenticatorDataPrefix),
std::end(kTestAuthenticatorDataPrefix));
std::vector<uint8_t> test_attestation_data = GetTestAttestationDataBytes();
test_authenticator_data.insert(test_authenticator_data.end(),
test_attestation_data.begin(),
test_attestation_data.end());
return test_authenticator_data;
}
std::vector<uint8_t> GetTestAttestationObjectBytes() {
std::vector<uint8_t> test_authenticator_object(std::begin(kFormatFidoU2fCBOR),
std::end(kFormatFidoU2fCBOR));
test_authenticator_object.insert(test_authenticator_object.end(),
std::begin(kAttStmtCBOR),
std::end(kAttStmtCBOR));
test_authenticator_object.insert(test_authenticator_object.end(),
std::begin(kU2fAttestationStatementCBOR),
std::end(kU2fAttestationStatementCBOR));
test_authenticator_object.insert(test_authenticator_object.end(),
std::begin(kAuthDataCBOR),
std::end(kAuthDataCBOR));
std::vector<uint8_t> test_authenticator_data =
GetTestAuthenticatorDataBytes();
test_authenticator_object.insert(test_authenticator_object.end(),
test_authenticator_data.begin(),
test_authenticator_data.end());
return test_authenticator_object;
}
class AuthenticatorImplTest : public content::RenderViewHostTestHarness {
public:
AuthenticatorImplTest() {}
~AuthenticatorImplTest() override {}
protected:
// Simulates navigating to a page and getting the page contents and language
// for that navigation.
void SimulateNavigation(const GURL& url) {
if (main_rfh()->GetLastCommittedURL() != url)
NavigateAndCommit(url);
}
AuthenticatorPtr ConnectToAuthenticator() {
AuthenticatorPtr authenticator;
AuthenticatorImpl::Create(main_rfh(), mojo::MakeRequest(&authenticator));
return authenticator;
}
};
class TestMakeCredentialCallback {
public:
TestMakeCredentialCallback()
: callback_(base::Bind(&TestMakeCredentialCallback::ReceivedCallback,
base::Unretained(this))) {}
~TestMakeCredentialCallback() {}
void ReceivedCallback(AuthenticatorStatus status,
PublicKeyCredentialInfoPtr credential) {
response_ = std::make_pair(status, std::move(credential));
closure_.Run();
}
std::pair<AuthenticatorStatus, PublicKeyCredentialInfoPtr>&
WaitForCallback() {
closure_ = run_loop_.QuitClosure();
run_loop_.Run();
return response_;
}
const base::Callback<void(AuthenticatorStatus status,
PublicKeyCredentialInfoPtr credential)>&
callback() {
return callback_;
}
private:
std::pair<AuthenticatorStatus, PublicKeyCredentialInfoPtr> response_;
base::Closure closure_;
base::Callback<void(AuthenticatorStatus status,
PublicKeyCredentialInfoPtr credential)>
callback_;
base::RunLoop run_loop_;
};
} // namespace
// Test that service returns NOT_ALLOWED_ERROR on a call to MakeCredential with
// an opaque origin.
TEST_F(AuthenticatorImplTest, MakeCredentialOpaqueOrigin) {
NavigateAndCommit(GURL("data:text/html,opaque"));
AuthenticatorPtr authenticator = ConnectToAuthenticator();
MakeCredentialOptionsPtr options = GetTestMakeCredentialOptions();
TestMakeCredentialCallback cb;
authenticator->MakeCredential(std::move(options), cb.callback());
std::pair<webauth::mojom::AuthenticatorStatus,
webauth::mojom::PublicKeyCredentialInfoPtr>& response =
cb.WaitForCallback();
EXPECT_EQ(webauth::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR,
response.first);
}
// Test that service returns NOT_SUPPORTED_ERROR if no parameters contain
// a supported algorithm.
TEST_F(AuthenticatorImplTest, MakeCredentialNoSupportedAlgorithm) {
SimulateNavigation(GURL(kTestOrigin1));
AuthenticatorPtr authenticator = ConnectToAuthenticator();
MakeCredentialOptionsPtr options = GetTestMakeCredentialOptions();
options->crypto_parameters = GetTestPublicKeyCredentialParameters(123);
TestMakeCredentialCallback cb;
authenticator->MakeCredential(std::move(options), cb.callback());
std::pair<webauth::mojom::AuthenticatorStatus,
webauth::mojom::PublicKeyCredentialInfoPtr>& response =
cb.WaitForCallback();
EXPECT_EQ(webauth::mojom::AuthenticatorStatus::NOT_SUPPORTED_ERROR,
response.first);
}
// Test that client data serializes to JSON properly.
TEST_F(AuthenticatorImplTest, TestSerializedClientData) {
std::unique_ptr<CollectedClientData> client_data =
CollectedClientData::Create(kTestRelyingPartyId, GetTestChallengeBytes());
EXPECT_EQ(kTestClientDataJsonString, client_data->SerializeToJson());
}
// Test that an EC public key serializes to CBOR properly.
TEST_F(AuthenticatorImplTest, TestSerializedPublicKey) {
std::unique_ptr<ECPublicKey> public_key =
ECPublicKey::ExtractFromU2fRegistrationResponse(
authenticator_utils::kEs256, GetTestRegisterResponse());
EXPECT_EQ(GetTestECPublicKeyCBOR(), public_key->EncodeAsCBOR());
}
// Test that the attestation statement cbor map is constructed properly.
TEST_F(AuthenticatorImplTest, TestU2fAttestationStatementCBOR) {
std::unique_ptr<FidoAttestationStatement> fido_attestation_statement =
FidoAttestationStatement::CreateFromU2fRegisterResponse(
GetTestRegisterResponse());
auto cbor =
CBORWriter::Write(CBORValue(fido_attestation_statement->GetAsCBORMap()));
ASSERT_TRUE(cbor.has_value());
EXPECT_EQ(GetU2fAttestationStatementCBOR(), cbor.value());
}
// Tests that well-formed attestation data serializes properly.
TEST_F(AuthenticatorImplTest, TestAttestationData) {
std::unique_ptr<ECPublicKey> public_key =
ECPublicKey::ExtractFromU2fRegistrationResponse(
authenticator_utils::kEs256, GetTestRegisterResponse());
std::unique_ptr<AttestationData> attestation_data =
AttestationData::CreateFromU2fRegisterResponse(
GetTestRegisterResponse(), std::vector<uint8_t>(16, 0) /* aaguid */,
std::move(public_key));
EXPECT_EQ(GetTestAttestationDataBytes(),
attestation_data->SerializeAsBytes());
}
// Tests that well-formed authenticator data serializes properly.
TEST_F(AuthenticatorImplTest, TestAuthenticatorData) {
std::unique_ptr<ECPublicKey> public_key =
ECPublicKey::ExtractFromU2fRegistrationResponse(
authenticator_utils::kEs256, GetTestRegisterResponse());
std::unique_ptr<AttestationData> attestation_data =
AttestationData::CreateFromU2fRegisterResponse(
GetTestRegisterResponse(), std::vector<uint8_t>(16, 0) /* aaguid */,
std::move(public_key));
AuthenticatorData::Flags flags =
static_cast<AuthenticatorData::Flags>(
AuthenticatorData::Flag::TEST_OF_USER_PRESENCE) |
static_cast<AuthenticatorData::Flags>(
AuthenticatorData::Flag::ATTESTATION);
std::unique_ptr<AuthenticatorData> authenticator_data =
AuthenticatorData::Create(GetTestClientData()->SerializeToJson(), flags,
std::vector<uint8_t>(4, 0) /* counter */,
std::move(attestation_data));
EXPECT_EQ(GetTestAuthenticatorDataBytes(),
authenticator_data->SerializeToByteArray());
}
// Tests that a U2F attestation object serializes properly.
TEST_F(AuthenticatorImplTest, TestU2fAttestationObject) {
std::unique_ptr<ECPublicKey> public_key =
ECPublicKey::ExtractFromU2fRegistrationResponse(
authenticator_utils::kEs256, GetTestRegisterResponse());
std::unique_ptr<AttestationData> attestation_data =
AttestationData::CreateFromU2fRegisterResponse(
GetTestRegisterResponse(), std::vector<uint8_t>(16, 0) /* aaguid */,
std::move(public_key));
AuthenticatorData::Flags flags =
static_cast<AuthenticatorData::Flags>(
AuthenticatorData::Flag::TEST_OF_USER_PRESENCE) |
static_cast<AuthenticatorData::Flags>(
AuthenticatorData::Flag::ATTESTATION);
std::unique_ptr<AuthenticatorData> authenticator_data =
AuthenticatorData::Create(GetTestClientData()->SerializeToJson(), flags,
std::vector<uint8_t>(4, 0) /* counter */,
std::move(attestation_data));
// Construct the attestation statement.
std::unique_ptr<FidoAttestationStatement> fido_attestation_statement =
FidoAttestationStatement::CreateFromU2fRegisterResponse(
GetTestRegisterResponse());
// Construct the attestation object.
auto attestation_object = std::make_unique<AttestationObject>(
std::move(authenticator_data), std::move(fido_attestation_statement));
EXPECT_EQ(GetTestAttestationObjectBytes(),
attestation_object->SerializeToCBOREncodedBytes());
}
// Test that a U2F register response is properly parsed.
TEST_F(AuthenticatorImplTest, TestRegisterResponseData) {
std::unique_ptr<CollectedClientData> client_data = GetTestClientData();
std::unique_ptr<RegisterResponseData> response =
RegisterResponseData::CreateFromU2fRegisterResponse(
std::move(client_data), GetTestRegisterResponse());
EXPECT_EQ(std::vector<uint8_t>(
kTestClientDataJsonString,
kTestClientDataJsonString + strlen(kTestClientDataJsonString)),
response->GetClientDataJSONBytes());
EXPECT_EQ(GetTestCredentialRawIdBytes(), response->raw_id());
EXPECT_EQ(GetTestAttestationObjectBytes(),
response->GetCBOREncodedAttestationObject());
}
} // namespace content