Software APIs
key_transport_unittest.cc
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
6 
7 #include <array>
8 
9 #include "gmock/gmock.h"
10 #include "gtest/gtest.h"
11 #include "sw/device/lib/crypto/impl/keyblob.h"
12 #include "sw/device/lib/crypto/impl/status.h"
14 
15 namespace key_transport_unittest {
16 namespace {
17 using ::testing::ElementsAreArray;
18 
19 // Key configuration for testing (128-bit AES-CTR hardware-backed key).
20 constexpr otcrypto_key_config_t kConfigHwBackedAesCtr128 = {
21  .version = kOtcryptoLibVersion1,
22  .key_mode = kOtcryptoKeyModeAesCtr,
23  .key_length = 128 / 8,
24  .hw_backed = kHardenedBoolTrue,
25  .exportable = kHardenedBoolFalse,
26  .security_level = kOtcryptoKeySecurityLevelLow,
27 };
28 
29 // Invalid RSA key configuration for testing (sideloaded RSA-2048 key).
30 constexpr otcrypto_key_config_t kConfigRsaInvalid = {
31  .version = kOtcryptoLibVersion1,
32  .key_mode = kOtcryptoKeyModeRsaSignPkcs,
33  .key_length = 2048 / 8,
34  .hw_backed = kHardenedBoolTrue,
35  .exportable = kHardenedBoolFalse,
36  .security_level = kOtcryptoKeySecurityLevelLow,
37 };
38 
39 // Key configuration for testing (128-bit AES-CTR exportable key).
40 constexpr otcrypto_key_config_t kConfigExportableAesCtr128 = {
41  .version = kOtcryptoLibVersion1,
42  .key_mode = kOtcryptoKeyModeAesCtr,
43  .key_length = 128 / 8,
44  .hw_backed = kHardenedBoolFalse,
45  .exportable = kHardenedBoolTrue,
46  .security_level = kOtcryptoKeySecurityLevelLow,
47 };
48 
49 // Key configuration for testing (128-bit AES-CTR non-exportable key).
50 constexpr otcrypto_key_config_t kConfigNonExportableAesCtr128 = {
51  .version = kOtcryptoLibVersion1,
52  .key_mode = kOtcryptoKeyModeAesCtr,
53  .key_length = 128 / 8,
54  .hw_backed = kHardenedBoolFalse,
55  .exportable = kHardenedBoolFalse,
56  .security_level = kOtcryptoKeySecurityLevelLow,
57 };
58 
59 TEST(KeyTransport, HwBackedKeyToDiversificationData) {
60  uint32_t test_version = 0xf0f1f2f3;
61  std::array<uint32_t, 7> test_salt = {0x01234567, 0x89abcdef, 0x00010203,
62  0x04050607, 0x08090a0b, 0x0c0d0e0f,
63  0x10111213};
64 
65  // Create a key handle from the test data.
66  uint32_t keyblob[32] = {0};
68  .config = kConfigHwBackedAesCtr128,
69  .keyblob_length = 32,
70  .keyblob = keyblob,
71  };
72  EXPECT_EQ(
73  status_ok(otcrypto_hw_backed_key(test_version, test_salt.data(), &key)),
74  true);
75 
76  // Expect that converting to keymgr diversification data generates the same
77  // version and salt.
78  keymgr_diversification_t diversification;
79  EXPECT_EQ(
80  status_ok(keyblob_to_keymgr_diversification(&key, &diversification)),
81  true);
82  EXPECT_EQ(diversification.version, test_version);
83  for (size_t i = 0; i < kKeymgrSaltNumWords - 1; i++) {
84  EXPECT_EQ(diversification.salt[i], test_salt[i]);
85  }
86  EXPECT_EQ(diversification.salt[kKeymgrSaltNumWords - 1],
87  kConfigHwBackedAesCtr128.key_mode);
88 }
89 
90 TEST(KeyTransport, HwBackedRsaKeyFails) {
91  uint32_t test_version = 0xf0f1f2f3;
92  std::array<uint32_t, 7> test_salt = {0x01234567, 0x89abcdef, 0x00010203,
93  0x04050607, 0x08090a0b, 0x0c0d0e0f,
94  0x10111213};
95 
96  // Create a key handle from the test data.
97  uint32_t keyblob[32] = {0};
99  .config = kConfigRsaInvalid,
100  .keyblob_length = 32,
101  .keyblob = keyblob,
102  };
103 
104  // Expect the hardware-backed RSA key to be rejected.
105  EXPECT_EQ(
106  status_ok(otcrypto_hw_backed_key(test_version, test_salt.data(), &key)),
107  false);
108 }
109 
110 TEST(KeyTransport, BlindedKeyImportExport) {
111  std::array<uint32_t, 4> share0 = {0x00010203, 0x04050607, 0x08090a0b,
112  0x0c0d0e0f};
113  std::array<uint32_t, 4> share1 = {0xf0f1f2f3, 0xf4f5f6f7, 0xf8f9fafb,
114  0xfcfdfeff};
115 
116  // Determine the unmasked value of the key.
117  std::array<uint32_t, 4> unmasked_key;
118  for (size_t i = 0; i < unmasked_key.size(); i++) {
119  unmasked_key[i] = share0[i] ^ share1[i];
120  }
121 
122  uint32_t keyblob[share0.size() * 2];
123  otcrypto_blinded_key_t blinded_key = {
124  .config = kConfigExportableAesCtr128,
125  .keyblob_length = sizeof(keyblob),
126  .keyblob = keyblob,
127  };
128 
129  // Import the key into the blinded key struct.
130  EXPECT_EQ(status_ok(otcrypto_import_blinded_key(
132  .data = share0.data(),
133  .len = share0.size(),
134  },
136  .data = share1.data(),
137  .len = share1.size(),
138  },
139  &blinded_key)),
140  true);
141 
142  // Zero the original inputs (they should now be safe to free).
143  memset(share0.data(), 0, sizeof(share0));
144  memset(share1.data(), 0, sizeof(share1));
145 
146  // Export the key again.
147  otcrypto_word32_buf_t share0_buf = {
148  .data = share0.data(),
149  .len = share0.size(),
150  };
151  otcrypto_word32_buf_t share1_buf = {
152  .data = share1.data(),
153  .len = share1.size(),
154  };
155  EXPECT_EQ(status_ok(otcrypto_export_blinded_key(blinded_key, share0_buf,
156  share1_buf)),
157  true);
158 
159  // Unmask the result and compare to the unmasked key.
160  for (size_t i = 0; i < unmasked_key.size(); i++) {
161  EXPECT_EQ(unmasked_key[i], share0[i] ^ share1[i]);
162  }
163 }
164 
165 TEST(KeyTransport, BlindedKeyImportBadLengths) {
166  std::array<uint32_t, 4> share0 = {0x00010203, 0x04050607, 0x08090a0b,
167  0x0c0d0e0f};
168  std::array<uint32_t, 4> share1 = {0xf0f1f2f3, 0xf4f5f6f7, 0xf8f9fafb,
169  0xfcfdfeff};
170 
171  // Create destination struct.
172  uint32_t keyblob[share0.size() * 2];
173  otcrypto_blinded_key_t blinded_key = {
174  .config = kConfigExportableAesCtr128,
175  .keyblob_length = sizeof(keyblob),
176  .keyblob = keyblob,
177  };
178 
179  // Set a bad length for share 0 and expect the import to fail.
180  EXPECT_EQ(status_ok(otcrypto_import_blinded_key(
182  .data = share0.data(),
183  .len = share0.size() - 1,
184  },
186  .data = share1.data(),
187  .len = share1.size(),
188  },
189  &blinded_key)),
190  false);
191 
192  // Set a bad length for share 1 and expect the import to fail.
193  EXPECT_EQ(status_ok(otcrypto_import_blinded_key(
195  .data = share0.data(),
196  .len = share0.size(),
197  },
199  .data = share1.data(),
200  .len = share1.size() - 1,
201  },
202  &blinded_key)),
203  false);
204 
205  // Set a bad length for the keyblob and expect the import to fail.
206  otcrypto_blinded_key_t bad_blinded_key = {
207  .config = kConfigExportableAesCtr128,
208  .keyblob_length = sizeof(keyblob) - 1,
209  .keyblob = keyblob,
210  };
211  EXPECT_EQ(status_ok(otcrypto_import_blinded_key(
213  .data = share0.data(),
214  .len = share0.size(),
215  },
217  .data = share1.data(),
218  .len = share1.size(),
219  },
220  &bad_blinded_key)),
221  false);
222 }
223 
224 TEST(KeyTransport, BlindedKeyExportBadLengths) {
225  std::array<uint32_t, 4> share0 = {0x00010203, 0x04050607, 0x08090a0b,
226  0x0c0d0e0f};
227  std::array<uint32_t, 4> share1 = {0xf0f1f2f3, 0xf4f5f6f7, 0xf8f9fafb,
228  0xfcfdfeff};
229 
230  // Create destination struct.
231  uint32_t keyblob[share0.size() * 2];
232  otcrypto_blinded_key_t blinded_key = {
233  .config = kConfigExportableAesCtr128,
234  .keyblob_length = sizeof(keyblob),
235  .keyblob = keyblob,
236  };
237 
238  // Import the key.
239  EXPECT_EQ(status_ok(otcrypto_import_blinded_key(
241  .data = share0.data(),
242  .len = share0.size(),
243  },
245  .data = share1.data(),
246  .len = share1.size(),
247  },
248  &blinded_key)),
249  true);
250 
251  otcrypto_word32_buf_t share_with_good_length = {
252  .data = share0.data(),
253  .len = share0.size(),
254  };
255  otcrypto_word32_buf_t share_with_bad_length = {
256  .data = share1.data(),
257  .len = share1.size() - 1,
258  };
259 
260  // Set a bad length for share 0 and expect the import to fail.
261  EXPECT_EQ(status_ok(otcrypto_export_blinded_key(
262  blinded_key, share_with_bad_length, share_with_good_length)),
263  false);
264 
265  // Set a bad length for share 1 and expect the import to fail.
266  EXPECT_EQ(status_ok(otcrypto_export_blinded_key(
267  blinded_key, share_with_good_length, share_with_bad_length)),
268  false);
269 
270  // Set a bad length for the keyblob and expect the export to fail.
271  otcrypto_blinded_key_t bad_blinded_key = {
272  .config = kConfigExportableAesCtr128,
273  .keyblob_length = sizeof(keyblob) - 1,
274  .keyblob = keyblob,
275  };
276  EXPECT_EQ(
277  status_ok(otcrypto_export_blinded_key(
278  bad_blinded_key, share_with_good_length, share_with_good_length)),
279  false);
280 }
281 
282 TEST(KeyTransport, BlindedKeyExportNotExportable) {
283  std::array<uint32_t, 4> share0 = {0x00010203, 0x04050607, 0x08090a0b,
284  0x0c0d0e0f};
285  std::array<uint32_t, 4> share1 = {0xf0f1f2f3, 0xf4f5f6f7, 0xf8f9fafb,
286  0xfcfdfeff};
287 
288  // Create destination struct.
289  uint32_t keyblob[share0.size() * 2];
290  otcrypto_blinded_key_t blinded_key = {
291  .config = kConfigNonExportableAesCtr128,
292  .keyblob_length = sizeof(keyblob),
293  .keyblob = keyblob,
294  };
295 
296  // Import the key.
297  EXPECT_EQ(status_ok(otcrypto_import_blinded_key(
299  .data = share0.data(),
300  .len = share0.size(),
301  },
303  .data = share1.data(),
304  .len = share1.size(),
305  },
306  &blinded_key)),
307  true);
308 
309  // Expect key export to fail.
310  otcrypto_word32_buf_t share0_buf = {
311  .data = share0.data(),
312  .len = share0.size(),
313  };
314  otcrypto_word32_buf_t share1_buf = {
315  .data = share1.data(),
316  .len = share1.size(),
317  };
318  EXPECT_EQ(status_ok(otcrypto_export_blinded_key(blinded_key, share0_buf,
319  share1_buf)),
320  false);
321 }
322 
323 } // namespace
324 } // namespace key_transport_unittest