Commit 652394e7 authored by Martin Kreichgauer's avatar Martin Kreichgauer Committed by Commit Bot

fido/mac: simplify CredentialMetadata interface

Change the SealCredentialId(), EncodeRpId(), EncodeRpIdAndUserId() and
SealLegacyV0CredentialIdForTestingOnly() methods to not return base::Optional
in order to make them less clunky. No functional changes intended.

Change-Id: Ic7088e3e016c09b1df5e4bcdc665d72c5ea3286b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1963861Reviewed-by: default avatarAdam Langley <agl@chromium.org>
Commit-Queue: Martin Kreichgauer <martinkr@google.com>
Cr-Commit-Position: refs/heads/master@{#727456}
parent 9a8d8f4d
......@@ -19,10 +19,6 @@ namespace device {
namespace fido {
namespace mac {
using cbor::Reader;
using cbor::Value;
using cbor::Writer;
// The version tag encoded into encrypted credential metadata.
static constexpr uint8_t kVersionLegacy0 = 0x00;
......@@ -35,8 +31,10 @@ namespace {
// MakeAad returns the concatenation of |version| and |rp_id|,
// which is used as the additional authenticated data (AAD) input to the AEAD.
std::string MakeAad(const uint8_t version, const std::string& rp_id) {
return std::string(1, version) + rp_id;
std::vector<uint8_t> MakeAad(const uint8_t version, const std::string& rp_id) {
std::vector<uint8_t> result = {version};
result.insert(result.end(), rp_id.data(), rp_id.data() + rp_id.size());
return result;
}
// Cryptor provides methods for encrypting and authenticating credential
......@@ -54,18 +52,18 @@ class Cryptor {
kAes256GcmSiv = 2,
};
base::Optional<std::string> Seal(Algorithm alg,
base::span<const uint8_t> nonce,
base::span<const uint8_t> plaintext,
base::StringPiece authenticated_data) const;
std::vector<uint8_t> Seal(Algorithm alg,
base::span<const uint8_t> nonce,
base::span<const uint8_t> plaintext,
base::span<const uint8_t> authenticated_data) const;
base::Optional<std::string> Unseal(
base::Optional<std::vector<uint8_t>> Unseal(
Algorithm alg,
base::span<const uint8_t> nonce,
base::span<const uint8_t> ciphertext,
base::StringPiece authenticated_data) const;
base::span<const uint8_t> authenticated_data) const;
base::Optional<std::string> HmacForStorage(base::StringPiece data) const;
std::string HmacForStorage(base::StringPiece data) const;
private:
static base::Optional<crypto::Aead::AeadAlgorithm> ToAeadAlgorithm(
......@@ -84,62 +82,35 @@ class Cryptor {
std::string secret_;
};
base::Optional<std::string> Cryptor::Seal(
std::vector<uint8_t> Cryptor::Seal(
Algorithm algorithm,
base::span<const uint8_t> nonce,
base::span<const uint8_t> plaintext,
base::StringPiece authenticated_data) const {
auto opt_aead_algorithm = ToAeadAlgorithm(algorithm);
if (!opt_aead_algorithm)
return base::nullopt;
base::span<const uint8_t> authenticated_data) const {
const std::string key = DeriveKey(algorithm);
crypto::Aead aead(*opt_aead_algorithm);
crypto::Aead aead(*ToAeadAlgorithm(algorithm));
aead.Init(&key);
std::string ciphertext;
if (!aead.Seal(
base::StringPiece(reinterpret_cast<const char*>(plaintext.data()),
plaintext.size()),
base::StringPiece(reinterpret_cast<const char*>(nonce.data()),
nonce.size()),
authenticated_data, &ciphertext)) {
return base::nullopt;
}
return ciphertext;
return aead.Seal(plaintext, nonce, authenticated_data);
}
base::Optional<std::string> Cryptor::Unseal(
base::Optional<std::vector<uint8_t>> Cryptor::Unseal(
Algorithm algorithm,
base::span<const uint8_t> nonce,
base::span<const uint8_t> ciphertext,
base::StringPiece authenticated_data) const {
auto opt_aead_algorithm = ToAeadAlgorithm(algorithm);
if (!opt_aead_algorithm)
return base::nullopt;
base::span<const uint8_t> authenticated_data) const {
const std::string key = DeriveKey(algorithm);
crypto::Aead aead(*opt_aead_algorithm);
crypto::Aead aead(*ToAeadAlgorithm(algorithm));
aead.Init(&key);
std::string plaintext;
if (!aead.Open(
base::StringPiece(reinterpret_cast<const char*>(ciphertext.data()),
ciphertext.size()),
base::StringPiece(reinterpret_cast<const char*>(nonce.data()),
nonce.size()),
authenticated_data, &plaintext)) {
return base::nullopt;
}
return plaintext;
return aead.Open(ciphertext, nonce, authenticated_data);
}
base::Optional<std::string> Cryptor::HmacForStorage(
base::StringPiece data) const {
std::string Cryptor::HmacForStorage(base::StringPiece data) const {
crypto::HMAC hmac(crypto::HMAC::SHA256);
const std::string key = DeriveKey(Algorithm::kHmacSha256);
std::vector<uint8_t> digest(hmac.DigestLength());
if (!hmac.Init(key) || !hmac.Sign(data, digest.data(), hmac.DigestLength())) {
return base::nullopt;
}
CHECK(hmac.Init(key));
CHECK(hmac.Sign(data, digest.data(), hmac.DigestLength()));
// The keychain fields that store RP ID and User ID seem to only accept
// NSString (not NSData), so we HexEncode to ensure the result to be
// UTF-8-decodable.
......@@ -232,10 +203,9 @@ static std::string MaybeTruncateWithTrailingEllipsis(const std::string& in) {
return out;
}
base::Optional<std::vector<uint8_t>> SealCredentialId(
const std::string& secret,
const std::string& rp_id,
const CredentialMetadata& metadata) {
std::vector<uint8_t> SealCredentialId(const std::string& secret,
const std::string& rp_id,
const CredentialMetadata& metadata) {
// The first 13 bytes are the version and nonce.
std::vector<uint8_t> result(1 + kNonceLength);
result[0] = kVersion;
......@@ -248,28 +218,22 @@ base::Optional<std::vector<uint8_t>> SealCredentialId(
// The remaining bytes are the CBOR-encoded CredentialMetadata, encrypted with
// AES-256-GCM and authenticated with the version and RP ID.
Value::ArrayValue cbor_user;
cbor_user.emplace_back(Value(metadata.user_id));
cbor::Value::ArrayValue cbor_user;
cbor_user.emplace_back(cbor::Value(metadata.user_id));
cbor_user.emplace_back(
Value(MaybeTruncateWithTrailingEllipsis(metadata.user_name),
Value::Type::BYTE_STRING));
cbor::Value(MaybeTruncateWithTrailingEllipsis(metadata.user_name),
cbor::Value::Type::BYTE_STRING));
cbor_user.emplace_back(
Value(MaybeTruncateWithTrailingEllipsis(metadata.user_display_name),
Value::Type::BYTE_STRING));
cbor_user.emplace_back(Value(metadata.is_resident));
cbor::Value(MaybeTruncateWithTrailingEllipsis(metadata.user_display_name),
cbor::Value::Type::BYTE_STRING));
cbor_user.emplace_back(cbor::Value(metadata.is_resident));
base::Optional<std::vector<uint8_t>> pt =
Writer::Write(Value(std::move(cbor_user)));
if (!pt) {
return base::nullopt;
}
base::Optional<std::string> ciphertext = Cryptor(secret).Seal(
cbor::Writer::Write(cbor::Value(std::move(cbor_user)));
DCHECK(pt);
const std::vector<uint8_t> ct = Cryptor(secret).Seal(
Cryptor::Algorithm::kAes256Gcm, nonce, *pt, MakeAad(kVersion, rp_id));
if (!ciphertext) {
return base::nullopt;
}
base::span<const char> cts(reinterpret_cast<const char*>(ciphertext->data()),
ciphertext->size());
result.insert(result.end(), cts.begin(), cts.end());
result.insert(result.end(), ct.begin(), ct.end());
return result;
}
......@@ -290,7 +254,7 @@ static base::Optional<CredentialMetadata> UnsealLegacyCredentialId(
return base::nullopt;
}
base::Optional<std::string> plaintext = Cryptor(secret).Unseal(
base::Optional<std::vector<uint8_t>> plaintext = Cryptor(secret).Unseal(
Cryptor::Algorithm::kAes256Gcm, credential_id.subspan(1, kNonceLength),
credential_id.subspan(1 + kNonceLength), MakeAad(kVersionLegacy0, rp_id));
if (!plaintext) {
......@@ -298,12 +262,11 @@ static base::Optional<CredentialMetadata> UnsealLegacyCredentialId(
}
// The recovered plaintext should decode into the CredentialMetadata struct.
base::Optional<Value> maybe_array = Reader::Read(base::make_span(
reinterpret_cast<const uint8_t*>(plaintext->data()), plaintext->size()));
base::Optional<cbor::Value> maybe_array = cbor::Reader::Read(*plaintext);
if (!maybe_array || !maybe_array->is_array()) {
return base::nullopt;
}
const Value::ArrayValue& array = maybe_array->GetArray();
const cbor::Value::ArrayValue& array = maybe_array->GetArray();
if (array.size() != 3 || !array[0].is_bytestring() ||
!array[1].is_bytestring() || !array[2].is_bytestring()) {
return base::nullopt;
......@@ -327,7 +290,7 @@ base::Optional<CredentialMetadata> UnsealCredentialId(
return base::nullopt;
}
base::Optional<std::string> plaintext = Cryptor(secret).Unseal(
base::Optional<std::vector<uint8_t>> plaintext = Cryptor(secret).Unseal(
Cryptor::Algorithm::kAes256Gcm, credential_id.subspan(1, kNonceLength),
credential_id.subspan(1 + kNonceLength), MakeAad(kVersion, rp_id));
if (!plaintext) {
......@@ -335,12 +298,12 @@ base::Optional<CredentialMetadata> UnsealCredentialId(
}
// The recovered plaintext should decode into the CredentialMetadata struct.
base::Optional<Value> maybe_array = Reader::Read(base::make_span(
base::Optional<cbor::Value> maybe_array = cbor::Reader::Read(base::make_span(
reinterpret_cast<const uint8_t*>(plaintext->data()), plaintext->size()));
if (!maybe_array || !maybe_array->is_array()) {
return base::nullopt;
}
const Value::ArrayValue& array = maybe_array->GetArray();
const cbor::Value::ArrayValue& array = maybe_array->GetArray();
if (array.size() != 4 || !array[0].is_bytestring() ||
!array[1].is_bytestring() || !array[2].is_bytestring() ||
!array[3].is_bool()) {
......@@ -351,10 +314,9 @@ base::Optional<CredentialMetadata> UnsealCredentialId(
array[2].GetBytestringAsString().as_string(), array[3].GetBool());
}
base::Optional<std::string> EncodeRpIdAndUserId(
const std::string& secret,
const std::string& rp_id,
base::span<const uint8_t> user_id) {
std::string EncodeRpIdAndUserId(const std::string& secret,
const std::string& rp_id,
base::span<const uint8_t> user_id) {
// Encoding RP ID along with the user ID hides whether the same user ID was
// reused on different RPs.
const auto* user_id_data = reinterpret_cast<const char*>(user_id.data());
......@@ -362,24 +324,21 @@ base::Optional<std::string> EncodeRpIdAndUserId(
rp_id + "/" + std::string(user_id_data, user_id_data + user_id.size()));
}
base::Optional<std::string> EncodeRpId(const std::string& secret,
const std::string& rp_id) {
std::string EncodeRpId(const std::string& secret, const std::string& rp_id) {
// Encrypt with a fixed nonce to make the result deterministic while still
// allowing the RP ID to be recovered from the ciphertext later.
static constexpr std::array<uint8_t, kNonceLength> fixed_zero_nonce = {};
base::span<const uint8_t> pt(reinterpret_cast<const uint8_t*>(rp_id.data()),
rp_id.size());
std::string empty_ad;
// Using AES-GCM with a fixed nonce would break confidentiality, so this uses
// AES-GCM-SIV instead.
base::Optional<std::string> ct = Cryptor(secret).Seal(
Cryptor::Algorithm::kAes256GcmSiv, fixed_zero_nonce, pt, empty_ad);
if (!ct) {
return base::nullopt;
}
const std::vector<uint8_t> ct =
Cryptor(secret).Seal(Cryptor::Algorithm::kAes256GcmSiv, fixed_zero_nonce,
pt, /*authenticated_data=*/{});
// The keychain field that stores the encrypted RP ID only accepts NSString
// (not NSData), so we HexEncode to ensure the result is UTF-8-decodable.
return base::HexEncode(ct->data(), ct->size());
return base::HexEncode(ct.data(), ct.size());
}
base::Optional<std::string> DecodeRpId(const std::string& secret,
......@@ -389,12 +348,16 @@ base::Optional<std::string> DecodeRpId(const std::string& secret,
return base::nullopt;
}
static constexpr std::array<uint8_t, kNonceLength> fixed_zero_nonce = {};
std::string empty_ad;
return Cryptor(secret).Unseal(Cryptor::Algorithm::kAes256GcmSiv,
fixed_zero_nonce, ct, empty_ad);
base::Optional<std::vector<uint8_t>> pt = Cryptor(secret).Unseal(
Cryptor::Algorithm::kAes256GcmSiv, fixed_zero_nonce, ct,
/*authenticated_data=*/{});
if (!pt) {
return base::nullopt;
}
return std::string(pt->begin(), pt->end());
}
base::Optional<std::vector<uint8_t>> SealLegacyV0CredentialIdForTestingOnly(
std::vector<uint8_t> SealLegacyV0CredentialIdForTestingOnly(
const std::string& secret,
const std::string& rp_id,
const std::vector<uint8_t>& user_id,
......@@ -409,24 +372,22 @@ base::Optional<std::vector<uint8_t>> SealLegacyV0CredentialIdForTestingOnly(
base::span<uint8_t> nonce(result.data() + 1, 12);
RAND_bytes(nonce.data(), nonce.size()); // RAND_bytes always returns 1.
Value::ArrayValue cbor_user;
cbor_user.emplace_back(Value(user_id));
cbor_user.emplace_back(Value(user_name, Value::Type::BYTE_STRING));
cbor_user.emplace_back(Value(user_display_name, Value::Type::BYTE_STRING));
cbor::Value::ArrayValue cbor_user;
cbor_user.emplace_back(cbor::Value(user_id));
cbor_user.emplace_back(
cbor::Value(user_name, cbor::Value::Type::BYTE_STRING));
cbor_user.emplace_back(
cbor::Value(user_display_name, cbor::Value::Type::BYTE_STRING));
base::Optional<std::vector<uint8_t>> pt =
Writer::Write(Value(std::move(cbor_user)));
if (!pt) {
return base::nullopt;
}
std::string aad = std::string(1, version) + rp_id;
base::Optional<std::string> ciphertext =
cbor::Writer::Write(cbor::Value(std::move(cbor_user)));
DCHECK(pt);
std::vector<uint8_t> aad;
aad.push_back(version);
aad.insert(aad.end(), rp_id.data(), rp_id.data() + rp_id.size());
const std::vector<uint8_t> ct =
Cryptor(secret).Seal(Cryptor::Algorithm::kAes256Gcm, nonce, *pt, aad);
if (!ciphertext) {
return base::nullopt;
}
base::span<const char> cts(reinterpret_cast<const char*>(ciphertext->data()),
ciphertext->size());
result.insert(result.end(), cts.begin(), cts.end());
result.insert(result.end(), ct.begin(), ct.end());
return result;
}
......
......@@ -76,7 +76,7 @@ std::string GenerateCredentialMetadataSecret();
//
// Credential IDs have following format:
//
// | version | nonce | AEAD(pt=CBOR(metadata), |
// | version | nonce | AEAD(pt=CBOR(metadata), |
// | (1 byte) | (12 bytes) | nonce=nonce, |
// | | | ad=(version, rpID)) |
//
......@@ -86,10 +86,9 @@ std::string GenerateCredentialMetadataSecret();
// The |user_name| and |user_display_name| fields may be truncated before
// encryption. The truncated values are guaranteed to be valid UTF-8.
COMPONENT_EXPORT(DEVICE_FIDO)
base::Optional<std::vector<uint8_t>> SealCredentialId(
const std::string& secret,
const std::string& rp_id,
const CredentialMetadata& metadata);
std::vector<uint8_t> SealCredentialId(const std::string& secret,
const std::string& rp_id,
const CredentialMetadata& metadata);
// UnsealCredentialId attempts to decrypt a CredentialMetadata from a credential
// id.
......@@ -105,15 +104,13 @@ base::Optional<CredentialMetadata> UnsealCredentialId(
// This encoding allows lookup of credentials for a given RP and user but
// without the credential ID.
COMPONENT_EXPORT(DEVICE_FIDO)
base::Optional<std::string> EncodeRpIdAndUserId(
const std::string& secret,
const std::string& rp_id,
base::span<const uint8_t> user_id);
std::string EncodeRpIdAndUserId(const std::string& secret,
const std::string& rp_id,
base::span<const uint8_t> user_id);
// EncodeRpId encodes the given RP ID for storage in the macOS keychain.
COMPONENT_EXPORT(DEVICE_FIDO)
base::Optional<std::string> EncodeRpId(const std::string& secret,
const std::string& rp_id);
std::string EncodeRpId(const std::string& secret, const std::string& rp_id);
// DecodeRpId attempts to decode a given RP ID from the keychain.
//
......@@ -126,7 +123,7 @@ base::Optional<std::string> DecodeRpId(const std::string& secret,
// Seals a legacy V0 credential ID.
COMPONENT_EXPORT(DEVICE_FIDO)
base::Optional<std::vector<uint8_t>> SealLegacyV0CredentialIdForTestingOnly(
std::vector<uint8_t> SealLegacyV0CredentialIdForTestingOnly(
const std::string& secret,
const std::string& rp_id,
const std::vector<uint8_t>& user_id,
......
......@@ -35,7 +35,7 @@ class CredentialMetadataTest : public ::testing::Test {
}
std::vector<uint8_t> SealCredentialId(CredentialMetadata user) {
return *device::fido::mac::SealCredentialId(key_, rp_id_, std::move(user));
return device::fido::mac::SealCredentialId(key_, rp_id_, std::move(user));
}
CredentialMetadata UnsealCredentialId(
......@@ -44,11 +44,11 @@ class CredentialMetadataTest : public ::testing::Test {
}
std::string EncodeRpIdAndUserId(base::StringPiece user_id) {
return *device::fido::mac::EncodeRpIdAndUserId(key_, rp_id_,
to_bytes(user_id));
return device::fido::mac::EncodeRpIdAndUserId(key_, rp_id_,
to_bytes(user_id));
}
std::string EncodeRpId() {
return *device::fido::mac::EncodeRpId(key_, rp_id_);
return device::fido::mac::EncodeRpId(key_, rp_id_);
}
std::string DecodeRpId(const std::string& ct) {
......@@ -70,11 +70,11 @@ TEST_F(CredentialMetadataTest, CredentialId) {
TEST_F(CredentialMetadataTest, LegacyCredentialId) {
auto user = DefaultUser();
auto id = SealLegacyV0CredentialIdForTestingOnly(
std::vector<uint8_t> id = SealLegacyV0CredentialIdForTestingOnly(
key_, rp_id_, user.user_id, user.user_name, user.user_display_name);
EXPECT_EQ(0, (*id)[0]);
EXPECT_EQ(54u, id->size());
EXPECT_TRUE(MetadataEq(UnsealCredentialId(*id), DefaultUser()));
EXPECT_EQ(0, id[0]);
EXPECT_EQ(54u, id.size());
EXPECT_TRUE(MetadataEq(UnsealCredentialId(id), DefaultUser()));
}
TEST_F(CredentialMetadataTest, CredentialId_IsRandom) {
......@@ -106,26 +106,26 @@ TEST_F(CredentialMetadataTest, EncodeRpIdAndUserId) {
EXPECT_EQ(EncodeRpIdAndUserId("user"), EncodeRpIdAndUserId("user"));
EXPECT_NE(EncodeRpIdAndUserId("userA"), EncodeRpIdAndUserId("userB"));
EXPECT_NE(EncodeRpIdAndUserId("user"),
*device::fido::mac::EncodeRpIdAndUserId(key_, "notacme.com",
to_bytes("user")));
device::fido::mac::EncodeRpIdAndUserId(key_, "notacme.com",
to_bytes("user")));
EXPECT_NE(EncodeRpIdAndUserId("user"),
*device::fido::mac::EncodeRpIdAndUserId(wrong_key_, rp_id_,
to_bytes("user")));
device::fido::mac::EncodeRpIdAndUserId(wrong_key_, rp_id_,
to_bytes("user")));
}
TEST_F(CredentialMetadataTest, EncodeRpId) {
EXPECT_EQ(48u, EncodeRpId().size());
EXPECT_EQ(EncodeRpId(), EncodeRpId());
EXPECT_NE(EncodeRpId(), *device::fido::mac::EncodeRpId(key_, "notacme.com"));
EXPECT_NE(EncodeRpId(), *device::fido::mac::EncodeRpId(wrong_key_, rp_id_));
EXPECT_NE(EncodeRpId(), device::fido::mac::EncodeRpId(key_, "notacme.com"));
EXPECT_NE(EncodeRpId(), device::fido::mac::EncodeRpId(wrong_key_, rp_id_));
}
TEST_F(CredentialMetadataTest, DecodeRpId) {
EXPECT_EQ(rp_id_, DecodeRpId(EncodeRpId()));
EXPECT_NE(rp_id_,
*device::fido::mac::DecodeRpId(
key_, *device::fido::mac::EncodeRpId(key_, "notacme.com")));
key_, device::fido::mac::EncodeRpId(key_, "notacme.com")));
EXPECT_FALSE(device::fido::mac::DecodeRpId(wrong_key_, EncodeRpId()));
}
......
......@@ -46,12 +46,7 @@ const std::string& GetAssertionOperation::RpId() const {
}
void GetAssertionOperation::Run() {
if (!Init()) {
std::move(callback())
.Run(CtapDeviceResponseCode::kCtap2ErrOther, base::nullopt);
return;
}
Init();
// Display the macOS Touch ID prompt.
PromptTouchId(l10n_util::GetStringFUTF16(IDS_WEBAUTHN_TOUCH_ID_PROMPT_REASON,
base::UTF8ToUTF16(RpId())));
......
......@@ -87,19 +87,14 @@ static std::list<Credential> FindCredentialsImpl(
const std::string& rp_id,
const std::set<std::vector<uint8_t>>& allowed_credential_ids,
LAContext* authentication_context) API_AVAILABLE(macosx(10.12.2)) {
base::Optional<std::string> encoded_rp_id =
EncodeRpId(metadata_secret, rp_id);
if (!encoded_rp_id) {
return {};
}
base::ScopedCFTypeRef<CFMutableDictionaryRef> query(
CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr));
CFDictionarySetValue(query, kSecClass, kSecClassKey);
CFDictionarySetValue(query, kSecAttrAccessGroup,
base::SysUTF8ToNSString(keychain_access_group));
CFDictionarySetValue(query, kSecAttrLabel,
base::SysUTF8ToNSString(*encoded_rp_id));
CFDictionarySetValue(
query, kSecAttrLabel,
base::SysUTF8ToNSString(EncodeRpId(metadata_secret, rp_id)));
if (authentication_context) {
CFDictionarySetValue(query, kSecUseAuthenticationContext,
authentication_context);
......
......@@ -59,10 +59,6 @@ class API_AVAILABLE(macosx(10.12.2))
// OperationBase:
const std::string& RpId() const override;
void PromptTouchIdDone(bool success) override;
// Generates a credential ID by invoking SealCredentialId() with parameters
// for the request. Note that results are non-deterministic.
base::Optional<std::vector<uint8_t>> GenerateCredentialIdForRequest() const;
};
} // namespace mac
......
......@@ -49,12 +49,7 @@ const std::string& MakeCredentialOperation::RpId() const {
}
void MakeCredentialOperation::Run() {
if (!Init()) {
std::move(callback())
.Run(CtapDeviceResponseCode::kCtap2ErrOther, base::nullopt);
return;
}
Init();
// Verify pubKeyCredParams contains ES-256, which is the only algorithm we
// support.
auto is_es256 =
......@@ -113,17 +108,12 @@ void MakeCredentialOperation::PromptTouchIdDone(bool success) {
//
// Note that because the rk bit is not encoded here, a resident credential
// may overwrite a non-resident credential and vice versa.
base::Optional<std::string> encoded_rp_id_user_id =
const std::string encoded_rp_id_user_id =
EncodeRpIdAndUserId(metadata_secret(), RpId(), request().user.id);
if (!encoded_rp_id_user_id) {
std::move(callback())
.Run(CtapDeviceResponseCode::kCtap2ErrOther, base::nullopt);
return;
}
{
ScopedCFTypeRef<CFMutableDictionaryRef> query = DefaultKeychainQuery();
CFDictionarySetValue(query, kSecAttrApplicationTag,
base::SysUTF8ToNSString(*encoded_rp_id_user_id));
base::SysUTF8ToNSString(encoded_rp_id_user_id));
OSStatus status = Keychain::GetInstance().ItemDelete(query);
if (status != errSecSuccess && status != errSecItemNotFound) {
OSSTATUS_DLOG(ERROR, status) << "SecItemDelete failed";
......@@ -134,14 +124,10 @@ void MakeCredentialOperation::PromptTouchIdDone(bool success) {
}
// Generate the new key pair.
base::Optional<std::vector<uint8_t>> credential_id =
GenerateCredentialIdForRequest();
if (!credential_id) {
FIDO_LOG(ERROR) << "GenerateCredentialIdForRequest failed";
std::move(callback())
.Run(CtapDeviceResponseCode::kCtap2ErrOther, base::nullopt);
return;
}
const std::vector<uint8_t> credential_id =
SealCredentialId(metadata_secret(), RpId(),
CredentialMetadata::FromPublicKeyCredentialUserEntity(
request().user, request().resident_key_required));
ScopedCFTypeRef<CFMutableDictionaryRef> params(
CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr));
......@@ -160,10 +146,10 @@ void MakeCredentialOperation::PromptTouchIdDone(bool success) {
CFDictionarySetValue(private_key_params, kSecUseAuthenticationContext,
authentication_context());
CFDictionarySetValue(private_key_params, kSecAttrApplicationTag,
base::SysUTF8ToNSString(*encoded_rp_id_user_id));
base::SysUTF8ToNSString(encoded_rp_id_user_id));
CFDictionarySetValue(private_key_params, kSecAttrApplicationLabel,
[NSData dataWithBytes:credential_id->data()
length:credential_id->size()]);
[NSData dataWithBytes:credential_id.data()
length:credential_id.size()]);
ScopedCFTypeRef<CFErrorRef> cferr;
ScopedCFTypeRef<SecKeyRef> private_key(
......@@ -187,7 +173,7 @@ void MakeCredentialOperation::PromptTouchIdDone(bool success) {
// Create attestation object. There is no separate attestation key pair, so
// we perform self-attestation.
base::Optional<AttestedCredentialData> attested_credential_data =
MakeAttestedCredentialData(*credential_id,
MakeAttestedCredentialData(credential_id,
SecKeyRefToECPublicKey(public_key));
if (!attested_credential_data) {
FIDO_LOG(ERROR) << "MakeAttestedCredentialData failed";
......@@ -216,13 +202,6 @@ void MakeCredentialOperation::PromptTouchIdDone(bool success) {
.Run(CtapDeviceResponseCode::kSuccess, std::move(response));
}
base::Optional<std::vector<uint8_t>>
MakeCredentialOperation::GenerateCredentialIdForRequest() const {
return SealCredentialId(metadata_secret(), RpId(),
CredentialMetadata::FromPublicKeyCredentialUserEntity(
request().user, request().resident_key_required));
}
} // namespace mac
} // namespace fido
} // namespace device
......@@ -43,15 +43,7 @@ class API_AVAILABLE(macosx(10.12.2)) OperationBase : public Operation {
protected:
// Subclasses must call Init() at the beginning of Run().
bool Init() {
base::Optional<std::string> encoded_rp_id =
EncodeRpId(metadata_secret(), RpId());
if (!encoded_rp_id)
return false;
encoded_rp_id_ = std::move(*encoded_rp_id);
return true;
}
void Init() { encoded_rp_id_ = EncodeRpId(metadata_secret(), RpId()); }
// PromptTouchId triggers a Touch ID consent dialog with the given reason
// string. Subclasses implement the PromptTouchIdDone callback to receive the
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment