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