xref: /aosp_15_r20/external/cronet/crypto/user_verifying_key_mac.mm (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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