| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CRYPTO_UNEXPORTABLE_KEY_H_ |
| #define CRYPTO_UNEXPORTABLE_KEY_H_ |
| |
| #include <memory> |
| |
| #include <optional> |
| #include "crypto/crypto_export.h" |
| #include "crypto/signature_verifier.h" |
| |
| namespace crypto { |
| |
| // UnexportableSigningKey provides a hardware-backed signing oracle on platforms |
| // that support it. Current support is: |
| // Windows: RSA_PKCS1_SHA256 via TPM 1.2+ and ECDSA_SHA256 via TPM 2.0. |
| // Tests: ECDSA_SHA256 via ScopedMockUnexportableSigningKeyForTesting. |
| // |
| // See also //components/unexportable_keys for a higher-level key management |
| // API. |
| class CRYPTO_EXPORT UnexportableSigningKey { |
| public: |
| virtual ~UnexportableSigningKey(); |
| |
| // Algorithm returns the algorithm of the key in this object. |
| virtual SignatureVerifier::SignatureAlgorithm Algorithm() const = 0; |
| |
| // GetSubjectPublicKeyInfo returns an SPKI that contains the public key of |
| // this object. |
| virtual std::vector<uint8_t> GetSubjectPublicKeyInfo() const = 0; |
| |
| // GetWrappedKey returns the encrypted private key of this object. It is |
| // encrypted to a key that is kept in hardware and the unencrypted private |
| // key never exists in the CPU's memory. |
| // |
| // A wrapped key may be used with a future instance of this code to recreate |
| // the key so long as it's running on the same computer. |
| // |
| // Note: it is possible to export this wrapped key off machine, but it must be |
| // sealed with an AEAD first. The wrapped key may contain machine identifiers |
| // and other values that you wouldn't want to export. Additionally |
| // |UnexportableKeyProvider::FromWrappedSigningKey| should not be presented |
| // attacked-controlled input and the AEAD would serve to authenticate the |
| // wrapped key. |
| virtual std::vector<uint8_t> GetWrappedKey() const = 0; |
| |
| // SignSlowly returns a signature of |data|, or |nullopt| if an error occurs |
| // during signing. |
| // |
| // Note: this may take a second or more to run. |
| virtual std::optional<std::vector<uint8_t>> SignSlowly( |
| base::span<const uint8_t> data) = 0; |
| }; |
| |
| // UnexportableKeyProvider creates |UnexportableSigningKey|s. |
| class CRYPTO_EXPORT UnexportableKeyProvider { |
| public: |
| virtual ~UnexportableKeyProvider(); |
| |
| // SelectAlgorithm returns which signature algorithm from |
| // |acceptable_algorithms| would be used if |acceptable_algorithms| was passed |
| // to |GenerateSigningKeySlowly|. |
| virtual std::optional<SignatureVerifier::SignatureAlgorithm> SelectAlgorithm( |
| base::span<const SignatureVerifier::SignatureAlgorithm> |
| acceptable_algorithms) = 0; |
| |
| // GenerateSigningKeySlowly creates a new opaque signing key in hardware. The |
| // first supported value of |acceptable_algorithms| determines the type of the |
| // key. Returns nullptr if no supported hardware exists, if no value in |
| // |acceptable_algorithms| is supported, or if there was an error creating the |
| // key. |
| // |
| // Note: this may take one or two seconds to run. |
| virtual std::unique_ptr<UnexportableSigningKey> GenerateSigningKeySlowly( |
| base::span<const SignatureVerifier::SignatureAlgorithm> |
| acceptable_algorithms) = 0; |
| |
| // FromWrappedSigningKey creates an |UnexportableSigningKey| from |
| // |wrapped_key|, which must have resulted from calling |GetWrappedKey| on a |
| // previous instance of |UnexportableSigningKey|. Returns nullptr if |
| // |wrapped_key| cannot be imported. |
| // |
| // Note: this may take up to a second. |
| // |
| // Note: do not call this with attacker-controlled data. The underlying |
| // interfaces to the secure hardware may not be robust. See |GetWrappedKey|. |
| virtual std::unique_ptr<UnexportableSigningKey> FromWrappedSigningKeySlowly( |
| base::span<const uint8_t> wrapped_key) = 0; |
| }; |
| |
| // This is an experimental API as it uses an unofficial Windows API. |
| // The current implementation is here to gather metrics only. It should not be |
| // used outside of metrics gathering without knowledge of crypto OWNERS. |
| // |
| // UnexportableSigningKey provides a software-backed signing oracle based in a |
| // specialized virtual machine on platforms that support it. Current support is: |
| // Windows: RSA_PKCS1_SHA256 and ECDSA_SHA256. |
| // |
| // These keys differs from UnexportableSigningKey in several ways: |
| // - They are backed not by hardware, but by a specialized limited virtual |
| // machine resistant to attacks. |
| // - The latency of operations are expected to be about 100 times less, making |
| // them much more practical in cases that would otherwise disrupt the user |
| // experience. |
| // - The keys are stored in the virtual machine by name, this namespace is |
| // shared by all applications and there is a limited number of available keys |
| // (~65k from testing). |
| // |
| // For more info see: |
| // https://learn.microsoft.com/en-us/windows/security/identity-protection/credential-guard/credential-guard |
| class CRYPTO_EXPORT VirtualUnexportableSigningKey { |
| public: |
| virtual ~VirtualUnexportableSigningKey(); |
| |
| // Algorithm returns the algorithm of the key in this object. |
| virtual SignatureVerifier::SignatureAlgorithm Algorithm() const = 0; |
| |
| // GetSubjectPublicKeyInfo returns an SPKI that contains the public key of |
| // this object. |
| virtual std::vector<uint8_t> GetSubjectPublicKeyInfo() const = 0; |
| |
| // GetKeyName may be used with a future instance of this code to recreate |
| // the key so long as it's running on the same computer. |
| // |
| // Note: All local applications can enumerate all keys on device and |
| // recreate them. Private keys can also be exported with the first HANDLE |
| // after creation. |
| virtual std::string GetKeyName() const = 0; |
| |
| // Sign returns a signature of |data|, or |nullopt| if an error occurs |
| // during signing. |
| // |
| // Note: this is expected to be under 10ms. |
| virtual std::optional<std::vector<uint8_t>> Sign( |
| base::span<const uint8_t> data) = 0; |
| |
| // Deletes the key from storage in the virtual machine. As the virtual machine |
| // has limited storage shared by all applications it is important to delete |
| // keys no longer in use. |
| virtual void DeleteKey() = 0; |
| }; |
| |
| // VirtualUnexportableKeyProvider creates |VirtualUnexportableSigningKey|s. |
| class CRYPTO_EXPORT VirtualUnexportableKeyProvider { |
| public: |
| virtual ~VirtualUnexportableKeyProvider(); |
| |
| // SelectAlgorithm returns which signature algorithm from |
| // |acceptable_algorithms| would be used if |acceptable_algorithms| was passed |
| // to |GenerateSigningKeySlowly|. |
| virtual std::optional<SignatureVerifier::SignatureAlgorithm> SelectAlgorithm( |
| base::span<const SignatureVerifier::SignatureAlgorithm> |
| acceptable_algorithms) = 0; |
| |
| // GenerateSigningKey creates a new opaque signing key in a virtual machine. |
| // The first supported value of |acceptable_algorithms| determines the type of |
| // the key. Returns nullptr if it is not supported in the operating system, |
| // if no value in |acceptable_algorithms| is supported, or if there was an |
| // error creating the key. |
| // As the namespace is shared between all applications care should be taken to |
| // use a name that will not already be used by other applications. If a new |
| // key is created with the same name as a current key the creation will fail. |
| // Do not create a key with NULL or empty string as the name. |
| // |
| // Note: This may take milliseconds to run. |
| virtual std::unique_ptr<VirtualUnexportableSigningKey> GenerateSigningKey( |
| base::span<const SignatureVerifier::SignatureAlgorithm> |
| acceptable_algorithms, |
| std::string name) = 0; |
| |
| // FromKeyName creates an |UnexportableSigningKey| from |name|, which is the |
| // name used to create the key. Returns nullptr if |name| cannot be imported. |
| // |
| // Note: This may take milliseconds to run. |
| virtual std::unique_ptr<VirtualUnexportableSigningKey> FromKeyName( |
| std::string name) = 0; |
| }; |
| |
| // GetUnexportableKeyProvider returns an |UnexportableKeyProvider| |
| // for the current platform, or nullptr if there isn't one. This can be called |
| // from any thread but, in tests, but be sequenced with |
| // |SetUnexportableSigningKeyProvider|. |
| CRYPTO_EXPORT std::unique_ptr<UnexportableKeyProvider> |
| GetUnexportableKeyProvider(); |
| |
| // GetVirtualUnexportableKeyProvider_DO_NOT_USE_METRICS_ONLY returns a |
| // |VirtualUnexportableKeyProvider| for the current platform, or nullptr if |
| // there isn't one. This should currently only be used for metrics gathering. |
| CRYPTO_EXPORT std::unique_ptr<VirtualUnexportableKeyProvider> |
| GetVirtualUnexportableKeyProvider_DO_NOT_USE_METRICS_ONLY(); |
| |
| // `GetSoftwareUnsecureUnexportableKeyProvider()` returns a mock software |
| // implementation of `UnexportableKeyProvider` that can be used on platforms |
| // that do not have a native secure implementation. |
| // This should be used for development purposes only since these keys are not |
| // backed by hardware and are not stored securely. |
| CRYPTO_EXPORT std::unique_ptr<UnexportableKeyProvider> |
| GetSoftwareUnsecureUnexportableKeyProvider(); |
| |
| namespace internal { |
| |
| CRYPTO_EXPORT void SetUnexportableKeyProviderForTesting( |
| std::unique_ptr<UnexportableKeyProvider> (*func)()); |
| |
| } // namespace internal |
| |
| } // namespace crypto |
| |
| #endif // CRYPTO_UNEXPORTABLE_KEY_H_ |