Adam Langley | 979ee87 | 2021-03-12 02:47:19 | [diff] [blame] | 1 | // Copyright (c) 2021 The Chromium Authors. All rights reserved. |
| 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 | |
Adam Langley | 979ee87 | 2021-03-12 02:47:19 | [diff] [blame] | 10 | #include "crypto/crypto_export.h" |
| 11 | #include "crypto/signature_verifier.h" |
Anton Bikineev | a3f961db | 2021-05-15 17:56:12 | [diff] [blame] | 12 | #include "third_party/abseil-cpp/absl/types/optional.h" |
Adam Langley | 979ee87 | 2021-03-12 02:47:19 | [diff] [blame] | 13 | |
| 14 | namespace crypto { |
| 15 | |
| 16 | // UnexportableSigningKey provides a hardware-backed signing oracle on platforms |
| 17 | // that support it. Current support is: |
| 18 | // Windows: RSA_PKCS1_SHA256 via TPM 1.2+ and ECDSA_SHA256 via TPM 2.0. |
| 19 | // Tests: ECDSA_SHA256 via ScopedMockUnexportableSigningKeyForTesting. |
| 20 | class CRYPTO_EXPORT UnexportableSigningKey { |
| 21 | public: |
| 22 | virtual ~UnexportableSigningKey(); |
| 23 | |
| 24 | // Algorithm returns the algorithm of the key in this object. |
| 25 | virtual SignatureVerifier::SignatureAlgorithm Algorithm() const = 0; |
| 26 | |
| 27 | // GetSubjectPublicKeyInfo returns an SPKI that contains the public key of |
| 28 | // this object. |
| 29 | virtual std::vector<uint8_t> GetSubjectPublicKeyInfo() const = 0; |
| 30 | |
| 31 | // GetWrappedKey returns the encrypted private key of this object. It is |
| 32 | // encrypted to a key that is kept in hardware and the unencrypted private |
| 33 | // key never exists in the CPU's memory. |
| 34 | // |
| 35 | // A wrapped key may be used with a future instance of this code to recreate |
| 36 | // the key so long as it's running on the same computer. |
| 37 | // |
| 38 | // Note: it is possible to export this wrapped key off machine, but it must be |
| 39 | // sealed with an AEAD first. The wrapped key may contain machine identifiers |
| 40 | // and other values that you wouldn't want to export. Additionally |
| 41 | // |UnexportableKeyProvider::FromWrappedSigningKey| should not be presented |
| 42 | // attacked-controlled input and the AEAD would serve to authenticate the |
| 43 | // wrapped key. |
| 44 | virtual std::vector<uint8_t> GetWrappedKey() const = 0; |
| 45 | |
| 46 | // SignSlowly returns a signature of |data|, or |nullopt| if an error occurs |
| 47 | // during signing. |
| 48 | // |
| 49 | // Note: this may take a second or more to run. |
Anton Bikineev | a3f961db | 2021-05-15 17:56:12 | [diff] [blame] | 50 | virtual absl::optional<std::vector<uint8_t>> SignSlowly( |
Adam Langley | 979ee87 | 2021-03-12 02:47:19 | [diff] [blame] | 51 | base::span<const uint8_t> data) = 0; |
| 52 | }; |
| 53 | |
| 54 | // UnexportableKeyProvider creates |UnexportableSigningKey|s. |
| 55 | class CRYPTO_EXPORT UnexportableKeyProvider { |
| 56 | public: |
| 57 | virtual ~UnexportableKeyProvider(); |
| 58 | |
| 59 | // SelectAlgorithm returns which signature algorithm from |
| 60 | // |acceptable_algorithms| would be used if |acceptable_algorithms| was passed |
| 61 | // to |GenerateSigningKeySlowly|. |
Anton Bikineev | a3f961db | 2021-05-15 17:56:12 | [diff] [blame] | 62 | virtual absl::optional<SignatureVerifier::SignatureAlgorithm> SelectAlgorithm( |
Adam Langley | 979ee87 | 2021-03-12 02:47:19 | [diff] [blame] | 63 | base::span<const SignatureVerifier::SignatureAlgorithm> |
| 64 | acceptable_algorithms) = 0; |
| 65 | |
| 66 | // GenerateSigningKeySlowly creates a new opaque signing key in hardware. The |
| 67 | // first supported value of |acceptable_algorithms| determines the type of the |
| 68 | // key. Returns nullptr if no supported hardware exists, if no value in |
| 69 | // |acceptable_algorithms| is supported, or if there was an error creating the |
| 70 | // key. |
| 71 | // |
| 72 | // Note: this may take one or two seconds to run. |
| 73 | virtual std::unique_ptr<UnexportableSigningKey> GenerateSigningKeySlowly( |
| 74 | base::span<const SignatureVerifier::SignatureAlgorithm> |
| 75 | acceptable_algorithms) = 0; |
| 76 | |
| 77 | // FromWrappedSigningKey creates an |UnexportableSigningKey| from |
| 78 | // |wrapped_key|, which must have resulted from calling |GetWrappedKey| on a |
| 79 | // previous instance of |UnexportableSigningKey|. Returns nullptr if |
| 80 | // |wrapped_key| cannot be imported. |
| 81 | // |
| 82 | // Note: this may take up to a second. |
| 83 | // |
| 84 | // Note: do not call this with attacker-controlled data. The underlying |
| 85 | // interfaces to the secure hardware may not be robust. See |GetWrappedKey|. |
| 86 | virtual std::unique_ptr<UnexportableSigningKey> FromWrappedSigningKeySlowly( |
| 87 | base::span<const uint8_t> wrapped_key) = 0; |
| 88 | }; |
| 89 | |
| 90 | // GetUnexportableKeyProvider returns an |UnexportableKeyProvider| |
| 91 | // for the current platform, or nullptr if there isn't one. This can be called |
| 92 | // from any thread but, in tests, but be sequenced with |
| 93 | // |SetUnexportableSigningKeyProvider|. |
| 94 | CRYPTO_EXPORT std::unique_ptr<UnexportableKeyProvider> |
| 95 | GetUnexportableKeyProvider(); |
| 96 | |
Adam Langley | 979ee87 | 2021-03-12 02:47:19 | [diff] [blame] | 97 | namespace internal { |
| 98 | |
| 99 | CRYPTO_EXPORT void SetUnexportableKeyProviderForTesting( |
| 100 | std::unique_ptr<UnexportableKeyProvider> (*func)()); |
| 101 | |
| 102 | } // namespace internal |
| 103 | |
| 104 | } // namespace crypto |
| 105 | |
| 106 | #endif // CRYPTO_UNEXPORTABLE_KEY_H_ |