Software APIs
keyblob.c
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 
5 #include "sw/device/lib/crypto/impl/keyblob.h"
6 
9 #include "sw/device/lib/crypto/impl/integrity.h"
10 #include "sw/device/lib/crypto/impl/status.h"
11 
12 // Module ID for status codes.
13 #define MODULE_ID MAKE_MODULE_ID('k', 'b', 'b')
14 
15 /**
16  * Determine the number of bytes in one share of a blinded key.
17  *
18  * Normally, this is the same length as the unblinded key material. However, in
19  * the case of some asymmetric keys, the shares might be longer.
20  *
21  * @param config Key configuration.
22  * @return Number of bytes in one share of the blinded key.
23  */
24 static size_t keyblob_share_num_bytes(const otcrypto_key_config_t config) {
25  // Get the key type from the top 16 bits of the full mode.
26  otcrypto_key_type_t key_type = (otcrypto_key_type_t)(config.key_mode >> 16);
27  switch (launder32(key_type)) {
28  case kOtcryptoKeyTypeEcc:
29  // ECC keys have 64 extra redundant bits per share.
30  HARDENED_CHECK_EQ(config.key_mode >> 16, kOtcryptoKeyTypeEcc);
31  return config.key_length + (64 / 8);
32  case kOtcryptoKeyTypeRsa:
33  // RSA key shares are the same size as the unmasked key.
34  // TODO: update once masking is implemented for RSA keys.
35  HARDENED_CHECK_EQ(config.key_mode >> 16, kOtcryptoKeyTypeRsa);
36  return config.key_length;
37  default:
38  // Symmetric key shares are simply the same size as the unmasked key.
39  HARDENED_CHECK_NE(config.key_mode >> 16, kOtcryptoKeyTypeEcc);
40  HARDENED_CHECK_NE(config.key_mode >> 16, kOtcryptoKeyTypeRsa);
41  return config.key_length;
42  }
43  HARDENED_TRAP();
44 }
45 
46 size_t keyblob_share_num_words(const otcrypto_key_config_t config) {
47  size_t len_bytes = keyblob_share_num_bytes(config);
48  return ceil_div(len_bytes, sizeof(uint32_t));
49 }
50 
51 size_t keyblob_num_words(const otcrypto_key_config_t config) {
52  if (launder32(config.hw_backed) == kHardenedBoolTrue) {
53  HARDENED_CHECK_EQ(config.hw_backed, kHardenedBoolTrue);
54  return kKeyblobHwBackedWords;
55  }
56  HARDENED_CHECK_NE(config.hw_backed, kHardenedBoolTrue);
57  return 2 * keyblob_share_num_words(config);
58 }
59 
60 /**
61  * Check that the keyblob length matches expectations from the key config.
62  *
63  * Returns an OK status if the keyblob length is correct, a BAD_ARGS status
64  * otherwise.
65  *
66  * @param key Blinded key.
67  * @returns OK if the keyblob length is correct, BAD_ARGS otherwise.
68  */
69 static status_t check_keyblob_length(const otcrypto_blinded_key_t *key) {
70  size_t num_words = keyblob_num_words(key->config);
71  if (launder32(key->keyblob_length) == num_words * sizeof(uint32_t)) {
72  HARDENED_CHECK_EQ(key->keyblob_length, num_words * sizeof(uint32_t));
73  HARDENED_CHECK_LE(key->keyblob_length / sizeof(uint32_t), num_words);
74  return OTCRYPTO_OK;
75  }
76  return OTCRYPTO_BAD_ARGS;
77 }
78 
79 status_t keyblob_to_shares(const otcrypto_blinded_key_t *key, uint32_t **share0,
80  uint32_t **share1) {
81  // Double-check the length of the keyblob.
82  HARDENED_TRY(check_keyblob_length(key));
83 
84  size_t key_words = keyblob_share_num_words(key->config);
85  *share0 = key->keyblob;
86  *share1 = &key->keyblob[key_words];
87  return OTCRYPTO_OK;
88 }
89 
90 void keyblob_from_shares(const uint32_t *share0, const uint32_t *share1,
91  const otcrypto_key_config_t config,
92  uint32_t *keyblob) {
93  size_t share_words = keyblob_share_num_words(config);
94  hardened_memcpy(keyblob, share0, share_words);
95  hardened_memcpy(keyblob + share_words, share1, share_words);
96 }
97 
98 status_t keyblob_buffer_to_keymgr_diversification(
99  const uint32_t *keyblob, otcrypto_key_mode_t mode,
100  keymgr_diversification_t *diversification) {
101  // Set the version to the first word of the keyblob.
102  diversification->version = launder32(keyblob[0]);
103 
104  // Copy the remainder of the keyblob into the salt.
105  hardened_memcpy(diversification->salt, &keyblob[1], kKeymgrSaltNumWords - 1);
106 
107  // Set the key mode as the last word of the salt.
108  diversification->salt[kKeymgrSaltNumWords - 1] = launder32(mode);
109 
110  HARDENED_CHECK_EQ(diversification->version, keyblob[0]);
111  HARDENED_CHECK_EQ(hardened_memeq(diversification->salt, &keyblob[1],
112  kKeymgrSaltNumWords - 1),
114  HARDENED_CHECK_EQ(diversification->salt[kKeymgrSaltNumWords - 1], mode);
115  return OTCRYPTO_OK;
116 }
117 
118 status_t keyblob_to_keymgr_diversification(
119  const otcrypto_blinded_key_t *key,
120  keymgr_diversification_t *diversification) {
121  if (launder32(key->config.hw_backed) != kHardenedBoolTrue ||
122  key->keyblob == NULL) {
123  return OTCRYPTO_BAD_ARGS;
124  }
125  HARDENED_CHECK_EQ(key->config.hw_backed, kHardenedBoolTrue);
126 
127  if (key->keyblob_length != kKeyblobHwBackedBytes) {
128  return OTCRYPTO_BAD_ARGS;
129  }
130 
131  return keyblob_buffer_to_keymgr_diversification(
132  key->keyblob, key->config.key_mode, diversification);
133 }
134 
135 status_t keyblob_ensure_xor_masked(const otcrypto_key_config_t config) {
136  // Reject hardware-backed keys, since the keyblob is not the actual key
137  // material in this case but the version/salt.
138  if (launder32(config.hw_backed) != kHardenedBoolFalse) {
139  return OTCRYPTO_BAD_ARGS;
140  }
141  HARDENED_CHECK_EQ(config.hw_backed, kHardenedBoolFalse);
142 
143  // Get the key type from the top 16 bits of the full mode.
144  otcrypto_key_type_t key_type =
145  (otcrypto_key_type_t)(launder32((uint32_t)config.key_mode) >> 16);
146  int32_t result = (int32_t)launder32((uint32_t)(OTCRYPTO_OK.value ^ key_type));
147  switch (launder32(key_type)) {
148  case kOtcryptoKeyTypeAes:
149  HARDENED_CHECK_EQ(config.key_mode >> 16, kOtcryptoKeyTypeAes);
150  result ^= launder32(kOtcryptoKeyTypeAes);
151  break;
152  case kOtcryptoKeyTypeHmac:
153  HARDENED_CHECK_EQ(config.key_mode >> 16, kOtcryptoKeyTypeHmac);
154  result ^= launder32(kOtcryptoKeyTypeHmac);
155  break;
156  case kOtcryptoKeyTypeKmac:
157  HARDENED_CHECK_EQ(config.key_mode >> 16, kOtcryptoKeyTypeKmac);
158  result ^= launder32(kOtcryptoKeyTypeKmac);
159  break;
160  case kOtcryptoKeyTypeKdf:
161  HARDENED_CHECK_EQ(config.key_mode >> 16, kOtcryptoKeyTypeKdf);
162  result ^= launder32(kOtcryptoKeyTypeKdf);
163  break;
164  case kOtcryptoKeyTypeEcc:
165  // Asymmetric!
166  return OTCRYPTO_BAD_ARGS;
167  case kOtcryptoKeyTypeRsa:
168  // Asymmetric!
169  return OTCRYPTO_BAD_ARGS;
170  default:
171  // Unrecognized key type.
172  return OTCRYPTO_BAD_ARGS;
173  }
174  HARDENED_CHECK_NE(config.key_mode >> 16, kOtcryptoKeyTypeEcc);
175  HARDENED_CHECK_NE(config.key_mode >> 16, kOtcryptoKeyTypeRsa);
176 
177  // If we get here, the result should be OTCRYPTO_OK.
178  return (status_t){.value = result};
179 }
180 
181 status_t keyblob_from_key_and_mask(const uint32_t *key, const uint32_t *mask,
182  const otcrypto_key_config_t config,
183  uint32_t *keyblob) {
184  // Check that the key is masked with XOR.
185  HARDENED_TRY(keyblob_ensure_xor_masked(config));
186 
187  // share0 = key ^ mask, share1 = mask
188  size_t key_words = keyblob_share_num_words(config);
189  uint32_t share0[key_words];
190  size_t i = 0;
191  for (; launder32(i) < key_words; i++) {
192  share0[i] = key[i] ^ mask[i];
193  }
194  HARDENED_CHECK_EQ(i, key_words);
195 
196  keyblob_from_shares(share0, mask, config, keyblob);
197  return OTCRYPTO_OK;
198 }
199 
200 status_t keyblob_remask(otcrypto_blinded_key_t *key, const uint32_t *mask) {
201  // Check that the key is masked with XOR.
202  HARDENED_TRY(keyblob_ensure_xor_masked(key->config));
203 
204  // Double-check the length of the keyblob.
205  HARDENED_TRY(check_keyblob_length(key));
206 
207  size_t key_share_words = keyblob_share_num_words(key->config);
208  size_t keyblob_words = keyblob_num_words(key->config);
209 
210  // Construct a new keyblob by re-masking.
211  size_t i = 0;
212  for (; launder32(i) < keyblob_words; i++) {
213  key->keyblob[i] ^= mask[i % key_share_words];
214  }
215  HARDENED_CHECK_EQ(i, keyblob_words);
216 
217  // Update the key checksum.
218  key->checksum = integrity_blinded_checksum(key);
219  return OTCRYPTO_OK;
220 }
221 
222 status_t keyblob_key_unmask(const otcrypto_blinded_key_t *key,
223  size_t unmasked_key_len, uint32_t *unmasked_key) {
224  if (key == NULL || unmasked_key == NULL) {
225  return OTCRYPTO_BAD_ARGS;
226  }
227  if (keyblob_share_num_words(key->config) != unmasked_key_len) {
228  return OTCRYPTO_BAD_ARGS;
229  }
230 
231  uint32_t *share0;
232  uint32_t *share1;
233  HARDENED_TRY(keyblob_to_shares(key, &share0, &share1));
234 
235  for (size_t i = 0; i < unmasked_key_len; i++) {
236  unmasked_key[i] = share0[i] ^ share1[i];
237  }
238  return OTCRYPTO_OK;
239 }
240 
241 status_t keyblob_sideload_key_otbn(const otcrypto_blinded_key_t *key) {
242  keymgr_diversification_t diversification;
243  HARDENED_TRY(keyblob_to_keymgr_diversification(key, &diversification));
244  return keymgr_generate_key_otbn(diversification);
245 }