1 // Copyright 2021 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 #ifndef CRYPTO_UNEXPORTABLE_KEY_H_ 6 #define CRYPTO_UNEXPORTABLE_KEY_H_ 7 8 #include <memory> 9 #include <optional> 10 11 #include "build/build_config.h" 12 #include "crypto/crypto_export.h" 13 #include "crypto/signature_verifier.h" 14 15 #if BUILDFLAG(IS_MAC) 16 #import <Security/Security.h> 17 #endif // BUILDFLAG(IS_MAC) 18 19 namespace crypto { 20 21 // UnexportableSigningKey provides a hardware-backed signing oracle on platforms 22 // that support it. Current support is: 23 // Windows: RSA_PKCS1_SHA256 via TPM 1.2+ and ECDSA_SHA256 via TPM 2.0. 24 // macOS: ECDSA_SHA256 via the Secure Enclave. 25 // Tests: ECDSA_SHA256 via ScopedMockUnexportableSigningKeyForTesting. 26 // 27 // See also //components/unexportable_keys for a higher-level key management 28 // API. 29 class CRYPTO_EXPORT UnexportableSigningKey { 30 public: 31 virtual ~UnexportableSigningKey(); 32 33 // Algorithm returns the algorithm of the key in this object. 34 virtual SignatureVerifier::SignatureAlgorithm Algorithm() const = 0; 35 36 // GetSubjectPublicKeyInfo returns an SPKI that contains the public key of 37 // this object. 38 virtual std::vector<uint8_t> GetSubjectPublicKeyInfo() const = 0; 39 40 // GetWrappedKey returns a handle to the private key of this object. Usually, 41 // it is the private key encrypted to a key that is kept in hardware and the 42 // unencrypted private key never exists in the CPU's memory, hence the name. 43 // On Mac, this is instead a hash of the public key and the wrapped key 44 // material is stored in the Keychain. 45 // 46 // A key handle may be used with a future instance of this code to recreate 47 // the key so long as it's running on the same computer. 48 // 49 // Note: on Windows it is possible to export this wrapped key off machine, but 50 // it must be sealed with an AEAD first. The wrapped key may contain machine 51 // identifiers and other values that you wouldn't want to export. Additionally 52 // |UnexportableKeyProvider::FromWrappedSigningKey| should not be presented 53 // attacked-controlled input and the AEAD would serve to authenticate the 54 // wrapped key. 55 virtual std::vector<uint8_t> GetWrappedKey() const = 0; 56 57 // SignSlowly returns a signature of |data|, or |nullopt| if an error occurs 58 // during signing. 59 // 60 // Note: this may take a second or more to run. 61 virtual std::optional<std::vector<uint8_t>> SignSlowly( 62 base::span<const uint8_t> data) = 0; 63 64 // Returns true if the underlying key is stored in "hardware". Something like 65 // ARM TrustZone would count as hardware for these purposes. Ideally all 66 // implementations of this class would return true here, because software 67 // implementations aren't really "unexportable", but a software implementation 68 // does exist. 69 virtual bool IsHardwareBacked() const; 70 71 #if BUILDFLAG(IS_MAC) 72 // Returns the underlying reference to a Keychain key owned by the current 73 // instance. 74 virtual SecKeyRef GetSecKeyRef() const = 0; 75 #endif // BUILDFLAG(IS_MAC) 76 }; 77 78 // UnexportableKeyProvider creates |UnexportableSigningKey|s. 79 class CRYPTO_EXPORT UnexportableKeyProvider { 80 public: 81 virtual ~UnexportableKeyProvider(); 82 83 // Platform-specific configuration parameters for the provider. 84 struct Config { 85 #if BUILDFLAG(IS_MAC) 86 // Determines the level of user verification needed to sign with the key. 87 // https://developer.apple.com/documentation/security/secaccesscontrolcreateflags?language=objc 88 enum class AccessControl { 89 // No access control. User presence is not required to access this secret. 90 kNone, 91 92 // Either biometry or the local account password are required to access 93 // this secret. This is equivalent to kSecAccessControlUserPresence. 94 // Note that if you set this and choose not to pass an authenticated 95 // LAContext when signing, macOS will prompt the user for biometrics and 96 // the thread will block until that resolves. 97 kUserPresence, 98 }; 99 100 // The keychain access group the key is shared with. The binary must be 101 // codesigned with the corresponding entitlement. 102 // https://developer.apple.com/documentation/bundleresources/entitlements/keychain-access-groups?language=objc 103 // This must be set to a non empty value when using unexportable keys on 104 // macOS. 105 std::string keychain_access_group; 106 107 // An optional application tag that will be set for all keys created by this 108 // provider. If non empty, this should uniquely identify a group of related 109 // keys, and can be used to query or delete all credentials with the same 110 // tag. 111 // https://developer.apple.com/documentation/security/ksecattrapplicationtag?language=objc 112 std::string application_tag; 113 114 // The access control set for keys created by the provider. 115 AccessControl access_control = AccessControl::kNone; 116 #endif // BUILDFLAG(IS_MAC) 117 }; 118 119 // SelectAlgorithm returns which signature algorithm from 120 // |acceptable_algorithms| would be used if |acceptable_algorithms| was passed 121 // to |GenerateSigningKeySlowly|. 122 virtual std::optional<SignatureVerifier::SignatureAlgorithm> SelectAlgorithm( 123 base::span<const SignatureVerifier::SignatureAlgorithm> 124 acceptable_algorithms) = 0; 125 126 // GenerateSigningKeySlowly creates a new opaque signing key in hardware. The 127 // first supported value of |acceptable_algorithms| determines the type of the 128 // key. Returns nullptr if no supported hardware exists, if no value in 129 // |acceptable_algorithms| is supported, or if there was an error creating the 130 // key. 131 // 132 // Note: this may take one or two seconds to run. 133 virtual std::unique_ptr<UnexportableSigningKey> GenerateSigningKeySlowly( 134 base::span<const SignatureVerifier::SignatureAlgorithm> 135 acceptable_algorithms) = 0; 136 137 // FromWrappedSigningKey creates an |UnexportableSigningKey| from 138 // |wrapped_key|, which must have resulted from calling |GetWrappedKey| on a 139 // previous instance of |UnexportableSigningKey|. Returns nullptr if 140 // |wrapped_key| cannot be imported. 141 // 142 // Note: this may take up to a second. 143 // 144 // Note: do not call this with attacker-controlled data. The underlying 145 // interfaces to the secure hardware may not be robust. See |GetWrappedKey|. 146 virtual std::unique_ptr<UnexportableSigningKey> FromWrappedSigningKeySlowly( 147 base::span<const uint8_t> wrapped_key) = 0; 148 149 // Unexportable key implementations may be stateful. This is the case for 150 // macOS. |DeleteSigningKey| deletes all state associated with a given signing 151 // key on such implementations. For stateless implementations, this is a 152 // no-op. 153 // Returns true on successful deletion, false otherwise. 154 // This can sometimes block, and therefore must not be called from the UI 155 // thread. 156 virtual bool DeleteSigningKeySlowly( 157 base::span<const uint8_t> wrapped_key) = 0; 158 }; 159 160 // This is an experimental API as it uses an unofficial Windows API. 161 // The current implementation is here to gather metrics only. It should not be 162 // used outside of metrics gathering without knowledge of crypto OWNERS. 163 // 164 // UnexportableSigningKey provides a software-backed signing oracle based in a 165 // specialized virtual machine on platforms that support it. Current support is: 166 // Windows: RSA_PKCS1_SHA256 and ECDSA_SHA256. 167 // 168 // These keys differs from UnexportableSigningKey in several ways: 169 // - They are backed not by hardware, but by a specialized limited virtual 170 // machine resistant to attacks. 171 // - The latency of operations are expected to be about 100 times less, making 172 // them much more practical in cases that would otherwise disrupt the user 173 // experience. 174 // - The keys are stored in the virtual machine by name, this namespace is 175 // shared by all applications and there is a limited number of available keys 176 // (~65k from testing). 177 // 178 // For more info see: 179 // https://learn.microsoft.com/en-us/windows/security/identity-protection/credential-guard/credential-guard 180 class CRYPTO_EXPORT VirtualUnexportableSigningKey { 181 public: 182 virtual ~VirtualUnexportableSigningKey(); 183 184 // Algorithm returns the algorithm of the key in this object. 185 virtual SignatureVerifier::SignatureAlgorithm Algorithm() const = 0; 186 187 // GetSubjectPublicKeyInfo returns an SPKI that contains the public key of 188 // this object. 189 virtual std::vector<uint8_t> GetSubjectPublicKeyInfo() const = 0; 190 191 // GetKeyName may be used with a future instance of this code to recreate 192 // the key so long as it's running on the same computer. 193 // 194 // Note: All local applications can enumerate all keys on device and 195 // recreate them. Private keys can also be exported with the first HANDLE 196 // after creation. 197 virtual std::string GetKeyName() const = 0; 198 199 // Sign returns a signature of |data|, or |nullopt| if an error occurs 200 // during signing. 201 // 202 // Note: this is expected to be under 10ms. 203 virtual std::optional<std::vector<uint8_t>> Sign( 204 base::span<const uint8_t> data) = 0; 205 206 // Deletes the key from storage in the virtual machine. As the virtual machine 207 // has limited storage shared by all applications it is important to delete 208 // keys no longer in use. 209 virtual void DeleteKey() = 0; 210 }; 211 212 // VirtualUnexportableKeyProvider creates |VirtualUnexportableSigningKey|s. 213 class CRYPTO_EXPORT VirtualUnexportableKeyProvider { 214 public: 215 virtual ~VirtualUnexportableKeyProvider(); 216 217 // SelectAlgorithm returns which signature algorithm from 218 // |acceptable_algorithms| would be used if |acceptable_algorithms| was passed 219 // to |GenerateSigningKeySlowly|. 220 virtual std::optional<SignatureVerifier::SignatureAlgorithm> SelectAlgorithm( 221 base::span<const SignatureVerifier::SignatureAlgorithm> 222 acceptable_algorithms) = 0; 223 224 // GenerateSigningKey creates a new opaque signing key in a virtual machine. 225 // The first supported value of |acceptable_algorithms| determines the type of 226 // the key. Returns nullptr if it is not supported in the operating system, 227 // if no value in |acceptable_algorithms| is supported, or if there was an 228 // error creating the key. 229 // As the namespace is shared between all applications care should be taken to 230 // use a name that will not already be used by other applications. If a new 231 // key is created with the same name as a current key the creation will fail. 232 // Do not create a key with NULL or empty string as the name. 233 // 234 // Note: This may take milliseconds to run. 235 virtual std::unique_ptr<VirtualUnexportableSigningKey> GenerateSigningKey( 236 base::span<const SignatureVerifier::SignatureAlgorithm> 237 acceptable_algorithms, 238 std::string name) = 0; 239 240 // FromKeyName creates an |UnexportableSigningKey| from |name|, which is the 241 // name used to create the key. Returns nullptr if |name| cannot be imported. 242 // 243 // Note: This may take milliseconds to run. 244 virtual std::unique_ptr<VirtualUnexportableSigningKey> FromKeyName( 245 std::string name) = 0; 246 }; 247 248 // GetUnexportableKeyProvider returns an |UnexportableKeyProvider| 249 // for the current platform, or nullptr if there isn't one. This can be called 250 // from any thread but, in tests, but be sequenced with 251 // |SetUnexportableSigningKeyProvider|. 252 CRYPTO_EXPORT std::unique_ptr<UnexportableKeyProvider> 253 GetUnexportableKeyProvider(UnexportableKeyProvider::Config config); 254 255 // GetVirtualUnexportableKeyProvider_DO_NOT_USE_METRICS_ONLY returns a 256 // |VirtualUnexportableKeyProvider| for the current platform, or nullptr if 257 // there isn't one. This should currently only be used for metrics gathering. 258 CRYPTO_EXPORT std::unique_ptr<VirtualUnexportableKeyProvider> 259 GetVirtualUnexportableKeyProvider_DO_NOT_USE_METRICS_ONLY(); 260 261 // `GetSoftwareUnsecureUnexportableKeyProvider()` returns a mock software 262 // implementation of `UnexportableKeyProvider` that can be used on platforms 263 // that do not have a native secure implementation. 264 // This should be used for development purposes only since these keys are not 265 // backed by hardware and are not stored securely. 266 CRYPTO_EXPORT std::unique_ptr<UnexportableKeyProvider> 267 GetSoftwareUnsecureUnexportableKeyProvider(); 268 269 namespace internal { 270 271 CRYPTO_EXPORT bool HasScopedUnexportableKeyProvider(); 272 273 CRYPTO_EXPORT void SetUnexportableKeyProviderForTesting( 274 std::unique_ptr<UnexportableKeyProvider> (*func)()); 275 276 } // namespace internal 277 278 } // namespace crypto 279 280 #endif // CRYPTO_UNEXPORTABLE_KEY_H_ 281