1// Copyright 2024 The Chromium Authors 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "crypto/user_verifying_key.h" 6 7#import <LocalAuthentication/LocalAuthentication.h> 8 9#include <atomic> 10#include <functional> 11#include <memory> 12#include <utility> 13 14#include "base/functional/bind.h" 15#include "base/functional/callback_helpers.h" 16#include "base/location.h" 17#include "base/logging.h" 18#include "base/memory/scoped_refptr.h" 19#include "base/task/bind_post_task.h" 20#include "base/task/single_thread_task_runner.h" 21#include "base/task/thread_pool.h" 22#include "base/threading/scoped_thread_priority.h" 23#include "base/types/expected.h" 24#include "crypto/apple_keychain_v2.h" 25#include "crypto/scoped_lacontext.h" 26#include "crypto/unexportable_key.h" 27#include "crypto/unexportable_key_mac.h" 28 29namespace crypto { 30 31namespace { 32 33// Refcounted wrapper for UnexportableSigningKey. 34class RefCountedUnexportableSigningKey 35 : public base::RefCountedThreadSafe<RefCountedUnexportableSigningKey> { 36 public: 37 explicit RefCountedUnexportableSigningKey( 38 std::unique_ptr<UnexportableSigningKey> key) 39 : key_(std::move(key)) {} 40 41 UnexportableSigningKey* key() { return key_.get(); } 42 43 private: 44 friend class base::RefCountedThreadSafe<RefCountedUnexportableSigningKey>; 45 ~RefCountedUnexportableSigningKey() = default; 46 47 std::unique_ptr<UnexportableSigningKey> key_; 48}; 49 50// Wraps signing |data| with |key|. 51base::expected<std::vector<uint8_t>, UserVerifyingKeySigningError> DoSign( 52 std::vector<uint8_t> data, 53 scoped_refptr<RefCountedUnexportableSigningKey> key) { 54 auto opt_signature = key->key()->SignSlowly(data); 55 if (!opt_signature.has_value()) { 56 return base::unexpected(UserVerifyingKeySigningError::kUnknownError); 57 } 58 return base::ok(*opt_signature); 59} 60 61std::string ToString(const std::vector<uint8_t>& vec) { 62 return std::string(vec.begin(), vec.end()); 63} 64 65// User verifying key implementation that delegates the heavy lifting to 66// UnexportableKeyMac. 67class UserVerifyingSigningKeyMac : public UserVerifyingSigningKey { 68 public: 69 explicit UserVerifyingSigningKeyMac( 70 std::unique_ptr<UnexportableSigningKey> key) 71 : key_name_(ToString(key->GetWrappedKey())), 72 key_(base::MakeRefCounted<RefCountedUnexportableSigningKey>( 73 std::move(key))) {} 74 ~UserVerifyingSigningKeyMac() override = default; 75 76 void Sign(base::span<const uint8_t> data, 77 UserVerifyingKeySignatureCallback callback) override { 78 // Signing will result in the system TouchID prompt being shown if the 79 // caller does not pass an authenticated LAContext, so we run the signing 80 // code in a separate thread. 81 scoped_refptr<base::SequencedTaskRunner> worker_task_runner = 82 base::ThreadPool::CreateSequencedTaskRunner( 83 {base::MayBlock(), base::TaskPriority::USER_BLOCKING}); 84 85 // Copy |data| to avoid needing to guarantee its backing storage to outlive 86 // the thread. 87 std::vector<uint8_t> data_copy(data.begin(), data.end()); 88 89 worker_task_runner->PostTaskAndReplyWithResult( 90 FROM_HERE, base::BindOnce(&DoSign, std::move(data_copy), key_), 91 std::move(callback)); 92 } 93 94 std::vector<uint8_t> GetPublicKey() const override { 95 return key_->key()->GetSubjectPublicKeyInfo(); 96 } 97 98 const UserVerifyingKeyLabel& GetKeyLabel() const override { 99 return key_name_; 100 } 101 102 bool IsHardwareBacked() const override { return true; } 103 104 private: 105 // The key's wrapped key as a binary string. 106 const std::string key_name_; 107 const scoped_refptr<RefCountedUnexportableSigningKey> key_; 108}; 109 110base::expected<std::unique_ptr<UserVerifyingSigningKey>, 111 UserVerifyingKeyCreationError> 112DoGenerateKey(base::span<const SignatureVerifier::SignatureAlgorithm> 113 acceptable_algorithms, 114 UnexportableKeyProvider::Config config, 115 LAContext* lacontext) { 116 std::unique_ptr<UnexportableKeyProviderMac> key_provider = 117 GetUnexportableKeyProviderMac(std::move(config)); 118 if (!key_provider) { 119 return base::unexpected(UserVerifyingKeyCreationError::kPlatformApiError); 120 } 121 122 std::unique_ptr<UnexportableSigningKey> key = 123 key_provider->GenerateSigningKeySlowly(acceptable_algorithms, lacontext); 124 if (!key) { 125 return base::unexpected(UserVerifyingKeyCreationError::kPlatformApiError); 126 } 127 return base::ok(std::make_unique<UserVerifyingSigningKeyMac>(std::move(key))); 128} 129 130base::expected<std::unique_ptr<UserVerifyingSigningKey>, 131 UserVerifyingKeyCreationError> 132DoGetKey(std::vector<uint8_t> wrapped_key, 133 UnexportableKeyProvider::Config config, 134 LAContext* lacontext) { 135 std::unique_ptr<UnexportableKeyProviderMac> key_provider = 136 GetUnexportableKeyProviderMac(std::move(config)); 137 if (!key_provider) { 138 return base::unexpected(UserVerifyingKeyCreationError::kPlatformApiError); 139 } 140 std::unique_ptr<UnexportableSigningKey> key = 141 key_provider->FromWrappedSigningKeySlowly(wrapped_key, lacontext); 142 if (!key) { 143 return base::unexpected(UserVerifyingKeyCreationError::kPlatformApiError); 144 } 145 return base::ok(std::make_unique<UserVerifyingSigningKeyMac>(std::move(key))); 146} 147 148bool DoDeleteKey(std::vector<uint8_t> wrapped_key, 149 UnexportableKeyProvider::Config config) { 150 std::unique_ptr<UnexportableKeyProvider> key_provider = 151 GetUnexportableKeyProvider(std::move(config)); 152 if (!key_provider) { 153 return false; 154 } 155 return key_provider->DeleteSigningKeySlowly(wrapped_key); 156} 157 158class UserVerifyingKeyProviderMac : public UserVerifyingKeyProvider { 159 public: 160 explicit UserVerifyingKeyProviderMac(UserVerifyingKeyProvider::Config config) 161 : lacontext_(config.lacontext ? config.lacontext->release() : nil), 162 config_(std::move(config)) {} 163 ~UserVerifyingKeyProviderMac() override = default; 164 165 void GenerateUserVerifyingSigningKey( 166 base::span<const SignatureVerifier::SignatureAlgorithm> 167 acceptable_algorithms, 168 UserVerifyingKeyCreationCallback callback) override { 169 // Creating a key may result in disk access, so do it in a separate thread 170 // to avoid blocking the UI. 171 scoped_refptr<base::SequencedTaskRunner> worker_task_runner = 172 base::ThreadPool::CreateSequencedTaskRunner( 173 {base::MayBlock(), base::TaskPriority::USER_BLOCKING}); 174 std::vector<SignatureVerifier::SignatureAlgorithm> algorithms( 175 acceptable_algorithms.begin(), acceptable_algorithms.end()); 176 worker_task_runner->PostTaskAndReplyWithResult( 177 FROM_HERE, 178 base::BindOnce(&DoGenerateKey, std::move(algorithms), 179 MakeUnexportableKeyConfig(), lacontext_), 180 std::move(callback)); 181 } 182 183 void GetUserVerifyingSigningKey( 184 UserVerifyingKeyLabel key_label, 185 UserVerifyingKeyCreationCallback callback) override { 186 // Retrieving a key may result in disk access, so do it in a separate thread 187 // to avoid blocking the UI. 188 scoped_refptr<base::SequencedTaskRunner> worker_task_runner = 189 base::ThreadPool::CreateSequencedTaskRunner( 190 {base::MayBlock(), base::TaskPriority::USER_BLOCKING}); 191 std::vector<uint8_t> wrapped_key(key_label.begin(), key_label.end()); 192 worker_task_runner->PostTaskAndReplyWithResult( 193 FROM_HERE, 194 base::BindOnce(&DoGetKey, std::move(std::move(wrapped_key)), 195 MakeUnexportableKeyConfig(), lacontext_), 196 std::move(callback)); 197 } 198 199 void DeleteUserVerifyingKey( 200 UserVerifyingKeyLabel key_label, 201 base::OnceCallback<void(bool)> callback) override { 202 // Deleting a key may result in disk access, so do it in a separate thread 203 // to avoid blocking the UI. 204 scoped_refptr<base::SequencedTaskRunner> worker_task_runner = 205 base::ThreadPool::CreateSequencedTaskRunner( 206 {base::MayBlock(), base::TaskPriority::USER_BLOCKING}); 207 std::vector<uint8_t> wrapped_key(key_label.begin(), key_label.end()); 208 worker_task_runner->PostTaskAndReplyWithResult( 209 FROM_HERE, 210 base::BindOnce(&DoDeleteKey, std::move(wrapped_key), 211 MakeUnexportableKeyConfig()), 212 std::move(callback)); 213 } 214 215 private: 216 UnexportableKeyProvider::Config MakeUnexportableKeyConfig() { 217 return { 218 .keychain_access_group = config_.keychain_access_group, 219 .access_control = 220 UnexportableKeyProvider::Config::AccessControl::kUserPresence, 221 }; 222 } 223 LAContext* __strong lacontext_; 224 const UserVerifyingKeyProvider::Config config_; 225}; 226 227} // namespace 228 229std::unique_ptr<UserVerifyingKeyProvider> GetUserVerifyingKeyProviderMac( 230 UserVerifyingKeyProvider::Config config) { 231 return std::make_unique<UserVerifyingKeyProviderMac>(std::move(config)); 232} 233 234void AreMacUnexportableKeysAvailable(UserVerifyingKeyProvider::Config config, 235 base::OnceCallback<void(bool)> callback) { 236 if (!GetUnexportableKeyProvider( 237 {.keychain_access_group = std::move(config.keychain_access_group)})) { 238 std::move(callback).Run(false); 239 return; 240 } 241 std::move(callback).Run( 242 AppleKeychainV2::GetInstance().LAContextCanEvaluatePolicy( 243 LAPolicyDeviceOwnerAuthentication, /*error=*/nil)); 244} 245 246} // namespace crypto 247