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
This diff is collapsed.
...@@ -76,7 +76,7 @@ std::string GenerateCredentialMetadataSecret(); ...@@ -76,7 +76,7 @@ std::string GenerateCredentialMetadataSecret();
// //
// Credential IDs have following format: // Credential IDs have following format:
// //
// | version | nonce | AEAD(pt=CBOR(metadata), | // | version | nonce | AEAD(pt=CBOR(metadata), |
// | (1 byte) | (12 bytes) | nonce=nonce, | // | (1 byte) | (12 bytes) | nonce=nonce, |
// | | | ad=(version, rpID)) | // | | | ad=(version, rpID)) |
// //
...@@ -86,10 +86,9 @@ std::string GenerateCredentialMetadataSecret(); ...@@ -86,10 +86,9 @@ std::string GenerateCredentialMetadataSecret();
// The |user_name| and |user_display_name| fields may be truncated before // The |user_name| and |user_display_name| fields may be truncated before
// encryption. The truncated values are guaranteed to be valid UTF-8. // encryption. The truncated values are guaranteed to be valid UTF-8.
COMPONENT_EXPORT(DEVICE_FIDO) COMPONENT_EXPORT(DEVICE_FIDO)
base::Optional<std::vector<uint8_t>> SealCredentialId( std::vector<uint8_t> SealCredentialId(const std::string& secret,
const std::string& secret, const std::string& rp_id,
const std::string& rp_id, const CredentialMetadata& metadata);
const CredentialMetadata& metadata);
// UnsealCredentialId attempts to decrypt a CredentialMetadata from a credential // UnsealCredentialId attempts to decrypt a CredentialMetadata from a credential
// id. // id.
...@@ -105,15 +104,13 @@ base::Optional<CredentialMetadata> UnsealCredentialId( ...@@ -105,15 +104,13 @@ base::Optional<CredentialMetadata> UnsealCredentialId(
// This encoding allows lookup of credentials for a given RP and user but // This encoding allows lookup of credentials for a given RP and user but
// without the credential ID. // without the credential ID.
COMPONENT_EXPORT(DEVICE_FIDO) COMPONENT_EXPORT(DEVICE_FIDO)
base::Optional<std::string> EncodeRpIdAndUserId( std::string EncodeRpIdAndUserId(const std::string& secret,
const std::string& secret, const std::string& rp_id,
const std::string& rp_id, base::span<const uint8_t> user_id);
base::span<const uint8_t> user_id);
// EncodeRpId encodes the given RP ID for storage in the macOS keychain. // EncodeRpId encodes the given RP ID for storage in the macOS keychain.
COMPONENT_EXPORT(DEVICE_FIDO) COMPONENT_EXPORT(DEVICE_FIDO)
base::Optional<std::string> EncodeRpId(const std::string& secret, std::string EncodeRpId(const std::string& secret, const std::string& rp_id);
const std::string& rp_id);
// DecodeRpId attempts to decode a given RP ID from the keychain. // DecodeRpId attempts to decode a given RP ID from the keychain.
// //
...@@ -126,7 +123,7 @@ base::Optional<std::string> DecodeRpId(const std::string& secret, ...@@ -126,7 +123,7 @@ base::Optional<std::string> DecodeRpId(const std::string& secret,
// Seals a legacy V0 credential ID. // Seals a legacy V0 credential ID.
COMPONENT_EXPORT(DEVICE_FIDO) COMPONENT_EXPORT(DEVICE_FIDO)
base::Optional<std::vector<uint8_t>> SealLegacyV0CredentialIdForTestingOnly( std::vector<uint8_t> SealLegacyV0CredentialIdForTestingOnly(
const std::string& secret, const std::string& secret,
const std::string& rp_id, const std::string& rp_id,
const std::vector<uint8_t>& user_id, const std::vector<uint8_t>& user_id,
......
...@@ -35,7 +35,7 @@ class CredentialMetadataTest : public ::testing::Test { ...@@ -35,7 +35,7 @@ class CredentialMetadataTest : public ::testing::Test {
} }
std::vector<uint8_t> SealCredentialId(CredentialMetadata user) { 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( CredentialMetadata UnsealCredentialId(
...@@ -44,11 +44,11 @@ class CredentialMetadataTest : public ::testing::Test { ...@@ -44,11 +44,11 @@ class CredentialMetadataTest : public ::testing::Test {
} }
std::string EncodeRpIdAndUserId(base::StringPiece user_id) { std::string EncodeRpIdAndUserId(base::StringPiece user_id) {
return *device::fido::mac::EncodeRpIdAndUserId(key_, rp_id_, return device::fido::mac::EncodeRpIdAndUserId(key_, rp_id_,
to_bytes(user_id)); to_bytes(user_id));
} }
std::string EncodeRpId() { 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) { std::string DecodeRpId(const std::string& ct) {
...@@ -70,11 +70,11 @@ TEST_F(CredentialMetadataTest, CredentialId) { ...@@ -70,11 +70,11 @@ TEST_F(CredentialMetadataTest, CredentialId) {
TEST_F(CredentialMetadataTest, LegacyCredentialId) { TEST_F(CredentialMetadataTest, LegacyCredentialId) {
auto user = DefaultUser(); 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); key_, rp_id_, user.user_id, user.user_name, user.user_display_name);
EXPECT_EQ(0, (*id)[0]); EXPECT_EQ(0, id[0]);
EXPECT_EQ(54u, id->size()); EXPECT_EQ(54u, id.size());
EXPECT_TRUE(MetadataEq(UnsealCredentialId(*id), DefaultUser())); EXPECT_TRUE(MetadataEq(UnsealCredentialId(id), DefaultUser()));
} }
TEST_F(CredentialMetadataTest, CredentialId_IsRandom) { TEST_F(CredentialMetadataTest, CredentialId_IsRandom) {
...@@ -106,26 +106,26 @@ TEST_F(CredentialMetadataTest, EncodeRpIdAndUserId) { ...@@ -106,26 +106,26 @@ TEST_F(CredentialMetadataTest, EncodeRpIdAndUserId) {
EXPECT_EQ(EncodeRpIdAndUserId("user"), EncodeRpIdAndUserId("user")); EXPECT_EQ(EncodeRpIdAndUserId("user"), EncodeRpIdAndUserId("user"));
EXPECT_NE(EncodeRpIdAndUserId("userA"), EncodeRpIdAndUserId("userB")); EXPECT_NE(EncodeRpIdAndUserId("userA"), EncodeRpIdAndUserId("userB"));
EXPECT_NE(EncodeRpIdAndUserId("user"), EXPECT_NE(EncodeRpIdAndUserId("user"),
*device::fido::mac::EncodeRpIdAndUserId(key_, "notacme.com", device::fido::mac::EncodeRpIdAndUserId(key_, "notacme.com",
to_bytes("user"))); to_bytes("user")));
EXPECT_NE(EncodeRpIdAndUserId("user"), EXPECT_NE(EncodeRpIdAndUserId("user"),
*device::fido::mac::EncodeRpIdAndUserId(wrong_key_, rp_id_, device::fido::mac::EncodeRpIdAndUserId(wrong_key_, rp_id_,
to_bytes("user"))); to_bytes("user")));
} }
TEST_F(CredentialMetadataTest, EncodeRpId) { TEST_F(CredentialMetadataTest, EncodeRpId) {
EXPECT_EQ(48u, EncodeRpId().size()); EXPECT_EQ(48u, EncodeRpId().size());
EXPECT_EQ(EncodeRpId(), EncodeRpId()); EXPECT_EQ(EncodeRpId(), EncodeRpId());
EXPECT_NE(EncodeRpId(), *device::fido::mac::EncodeRpId(key_, "notacme.com")); 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(wrong_key_, rp_id_));
} }
TEST_F(CredentialMetadataTest, DecodeRpId) { TEST_F(CredentialMetadataTest, DecodeRpId) {
EXPECT_EQ(rp_id_, DecodeRpId(EncodeRpId())); EXPECT_EQ(rp_id_, DecodeRpId(EncodeRpId()));
EXPECT_NE(rp_id_, EXPECT_NE(rp_id_,
*device::fido::mac::DecodeRpId( *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())); EXPECT_FALSE(device::fido::mac::DecodeRpId(wrong_key_, EncodeRpId()));
} }
......
...@@ -46,12 +46,7 @@ const std::string& GetAssertionOperation::RpId() const { ...@@ -46,12 +46,7 @@ const std::string& GetAssertionOperation::RpId() const {
} }
void GetAssertionOperation::Run() { void GetAssertionOperation::Run() {
if (!Init()) { Init();
std::move(callback())
.Run(CtapDeviceResponseCode::kCtap2ErrOther, base::nullopt);
return;
}
// Display the macOS Touch ID prompt. // Display the macOS Touch ID prompt.
PromptTouchId(l10n_util::GetStringFUTF16(IDS_WEBAUTHN_TOUCH_ID_PROMPT_REASON, PromptTouchId(l10n_util::GetStringFUTF16(IDS_WEBAUTHN_TOUCH_ID_PROMPT_REASON,
base::UTF8ToUTF16(RpId()))); base::UTF8ToUTF16(RpId())));
......
...@@ -87,19 +87,14 @@ static std::list<Credential> FindCredentialsImpl( ...@@ -87,19 +87,14 @@ static std::list<Credential> FindCredentialsImpl(
const std::string& rp_id, const std::string& rp_id,
const std::set<std::vector<uint8_t>>& allowed_credential_ids, const std::set<std::vector<uint8_t>>& allowed_credential_ids,
LAContext* authentication_context) API_AVAILABLE(macosx(10.12.2)) { 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( base::ScopedCFTypeRef<CFMutableDictionaryRef> query(
CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr)); CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr));
CFDictionarySetValue(query, kSecClass, kSecClassKey); CFDictionarySetValue(query, kSecClass, kSecClassKey);
CFDictionarySetValue(query, kSecAttrAccessGroup, CFDictionarySetValue(query, kSecAttrAccessGroup,
base::SysUTF8ToNSString(keychain_access_group)); base::SysUTF8ToNSString(keychain_access_group));
CFDictionarySetValue(query, kSecAttrLabel, CFDictionarySetValue(
base::SysUTF8ToNSString(*encoded_rp_id)); query, kSecAttrLabel,
base::SysUTF8ToNSString(EncodeRpId(metadata_secret, rp_id)));
if (authentication_context) { if (authentication_context) {
CFDictionarySetValue(query, kSecUseAuthenticationContext, CFDictionarySetValue(query, kSecUseAuthenticationContext,
authentication_context); authentication_context);
......
...@@ -59,10 +59,6 @@ class API_AVAILABLE(macosx(10.12.2)) ...@@ -59,10 +59,6 @@ class API_AVAILABLE(macosx(10.12.2))
// OperationBase: // OperationBase:
const std::string& RpId() const override; const std::string& RpId() const override;
void PromptTouchIdDone(bool success) 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 } // namespace mac
......
...@@ -49,12 +49,7 @@ const std::string& MakeCredentialOperation::RpId() const { ...@@ -49,12 +49,7 @@ const std::string& MakeCredentialOperation::RpId() const {
} }
void MakeCredentialOperation::Run() { void MakeCredentialOperation::Run() {
if (!Init()) { Init();
std::move(callback())
.Run(CtapDeviceResponseCode::kCtap2ErrOther, base::nullopt);
return;
}
// Verify pubKeyCredParams contains ES-256, which is the only algorithm we // Verify pubKeyCredParams contains ES-256, which is the only algorithm we
// support. // support.
auto is_es256 = auto is_es256 =
...@@ -113,17 +108,12 @@ void MakeCredentialOperation::PromptTouchIdDone(bool success) { ...@@ -113,17 +108,12 @@ void MakeCredentialOperation::PromptTouchIdDone(bool success) {
// //
// Note that because the rk bit is not encoded here, a resident credential // Note that because the rk bit is not encoded here, a resident credential
// may overwrite a non-resident credential and vice versa. // 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); 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(); ScopedCFTypeRef<CFMutableDictionaryRef> query = DefaultKeychainQuery();
CFDictionarySetValue(query, kSecAttrApplicationTag, CFDictionarySetValue(query, kSecAttrApplicationTag,
base::SysUTF8ToNSString(*encoded_rp_id_user_id)); base::SysUTF8ToNSString(encoded_rp_id_user_id));
OSStatus status = Keychain::GetInstance().ItemDelete(query); OSStatus status = Keychain::GetInstance().ItemDelete(query);
if (status != errSecSuccess && status != errSecItemNotFound) { if (status != errSecSuccess && status != errSecItemNotFound) {
OSSTATUS_DLOG(ERROR, status) << "SecItemDelete failed"; OSSTATUS_DLOG(ERROR, status) << "SecItemDelete failed";
...@@ -134,14 +124,10 @@ void MakeCredentialOperation::PromptTouchIdDone(bool success) { ...@@ -134,14 +124,10 @@ void MakeCredentialOperation::PromptTouchIdDone(bool success) {
} }
// Generate the new key pair. // Generate the new key pair.
base::Optional<std::vector<uint8_t>> credential_id = const std::vector<uint8_t> credential_id =
GenerateCredentialIdForRequest(); SealCredentialId(metadata_secret(), RpId(),
if (!credential_id) { CredentialMetadata::FromPublicKeyCredentialUserEntity(
FIDO_LOG(ERROR) << "GenerateCredentialIdForRequest failed"; request().user, request().resident_key_required));
std::move(callback())
.Run(CtapDeviceResponseCode::kCtap2ErrOther, base::nullopt);
return;
}
ScopedCFTypeRef<CFMutableDictionaryRef> params( ScopedCFTypeRef<CFMutableDictionaryRef> params(
CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr)); CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr));
...@@ -160,10 +146,10 @@ void MakeCredentialOperation::PromptTouchIdDone(bool success) { ...@@ -160,10 +146,10 @@ void MakeCredentialOperation::PromptTouchIdDone(bool success) {
CFDictionarySetValue(private_key_params, kSecUseAuthenticationContext, CFDictionarySetValue(private_key_params, kSecUseAuthenticationContext,
authentication_context()); authentication_context());
CFDictionarySetValue(private_key_params, kSecAttrApplicationTag, CFDictionarySetValue(private_key_params, kSecAttrApplicationTag,
base::SysUTF8ToNSString(*encoded_rp_id_user_id)); base::SysUTF8ToNSString(encoded_rp_id_user_id));
CFDictionarySetValue(private_key_params, kSecAttrApplicationLabel, CFDictionarySetValue(private_key_params, kSecAttrApplicationLabel,
[NSData dataWithBytes:credential_id->data() [NSData dataWithBytes:credential_id.data()
length:credential_id->size()]); length:credential_id.size()]);
ScopedCFTypeRef<CFErrorRef> cferr; ScopedCFTypeRef<CFErrorRef> cferr;
ScopedCFTypeRef<SecKeyRef> private_key( ScopedCFTypeRef<SecKeyRef> private_key(
...@@ -187,7 +173,7 @@ void MakeCredentialOperation::PromptTouchIdDone(bool success) { ...@@ -187,7 +173,7 @@ void MakeCredentialOperation::PromptTouchIdDone(bool success) {
// Create attestation object. There is no separate attestation key pair, so // Create attestation object. There is no separate attestation key pair, so
// we perform self-attestation. // we perform self-attestation.
base::Optional<AttestedCredentialData> attested_credential_data = base::Optional<AttestedCredentialData> attested_credential_data =
MakeAttestedCredentialData(*credential_id, MakeAttestedCredentialData(credential_id,
SecKeyRefToECPublicKey(public_key)); SecKeyRefToECPublicKey(public_key));
if (!attested_credential_data) { if (!attested_credential_data) {
FIDO_LOG(ERROR) << "MakeAttestedCredentialData failed"; FIDO_LOG(ERROR) << "MakeAttestedCredentialData failed";
...@@ -216,13 +202,6 @@ void MakeCredentialOperation::PromptTouchIdDone(bool success) { ...@@ -216,13 +202,6 @@ void MakeCredentialOperation::PromptTouchIdDone(bool success) {
.Run(CtapDeviceResponseCode::kSuccess, std::move(response)); .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 mac
} // namespace fido } // namespace fido
} // namespace device } // namespace device
...@@ -43,15 +43,7 @@ class API_AVAILABLE(macosx(10.12.2)) OperationBase : public Operation { ...@@ -43,15 +43,7 @@ class API_AVAILABLE(macosx(10.12.2)) OperationBase : public Operation {
protected: protected:
// Subclasses must call Init() at the beginning of Run(). // Subclasses must call Init() at the beginning of Run().
bool Init() { void Init() { encoded_rp_id_ = EncodeRpId(metadata_secret(), RpId()); }
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;
}
// PromptTouchId triggers a Touch ID consent dialog with the given reason // PromptTouchId triggers a Touch ID consent dialog with the given reason
// string. Subclasses implement the PromptTouchIdDone callback to receive the // 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