1 /*
2 * SPDX-License-Identifier: Apache-2.0
3 *
4 * Copyright (c) 2023 Arm Limited
5 */
6
7 /*
8 * This module provides a thin abstraction over some of the crypto
9 * primitives to make it easier to swap out the used crypto library.
10 *
11 * At this point, the choices are: MCUBOOT_USE_MBED_TLS and
12 * MCUBOOT_USE_PSA_CRYPTO. Note that support for MCUBOOT_USE_PSA_CRYPTO is
13 * still experimental and it might not support all the crypto abstractions
14 * that MCUBOOT_USE_MBED_TLS supports. For this reason, it's allowed to have
15 * both of them defined, and for crypto modules that support both abstractions,
16 * the MCUBOOT_USE_PSA_CRYPTO will take precedence.
17 */
18
19 /*
20 * Note: The source file that includes this header should either define one of the
21 * two options BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED or BOOTUTIL_CRYPTO_RSA_SIGN_ENABLED
22 * This will make the signature functions or encryption functions visible without
23 * generating a "defined but not used" compiler warning
24 */
25
26 #ifndef __BOOTUTIL_CRYPTO_RSA_H_
27 #define __BOOTUTIL_CRYPTO_RSA_H_
28
29 #include "mcuboot_config/mcuboot_config.h"
30
31 #if defined(MCUBOOT_USE_PSA_CRYPTO) || defined(MCUBOOT_USE_MBED_TLS)
32 #define MCUBOOT_USE_PSA_OR_MBED_TLS
33 #endif /* MCUBOOT_USE_PSA_CRYPTO || MCUBOOT_USE_MBED_TLS */
34
35 #if (defined(MCUBOOT_USE_PSA_OR_MBED_TLS)) != 1
36 #error "One crypto backend must be defined: either MBED_TLS/PSA_CRYPTO"
37 #endif
38
39 #if defined(MCUBOOT_USE_PSA_CRYPTO)
40
41 #include <psa/crypto.h>
42 #include "bootutil/enc_key_public.h"
43
44 #elif defined(MCUBOOT_USE_MBED_TLS)
45
46 #include "mbedtls/rsa.h"
47 #include "mbedtls/version.h"
48 #if defined(BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED)
49 #if MBEDTLS_VERSION_NUMBER >= 0x03000000
50 #include "rsa_alt_helpers.h"
51 #else
52 #include "mbedtls/rsa_internal.h"
53 #endif
54 #endif /* BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED */
55 #include "mbedtls/asn1.h"
56 #include "bootutil/crypto/common.h"
57
58 #endif /* MCUBOOT_USE_MBED_TLS */
59
60 #include <stdint.h>
61
62 #ifdef __cplusplus
63 extern "C" {
64 #endif
65
66 #if defined(MCUBOOT_USE_PSA_CRYPTO)
67
68 typedef struct {
69 psa_key_id_t key_id;
70 } bootutil_rsa_context;
71
bootutil_rsa_init(bootutil_rsa_context * ctx)72 static inline void bootutil_rsa_init(bootutil_rsa_context *ctx)
73 {
74 ctx->key_id = PSA_KEY_ID_NULL;
75 }
76
bootutil_rsa_drop(bootutil_rsa_context * ctx)77 static inline void bootutil_rsa_drop(bootutil_rsa_context *ctx)
78 {
79 if (ctx->key_id != PSA_KEY_ID_NULL) {
80 (void)psa_destroy_key(ctx->key_id);
81 }
82 }
83
84 #if defined(BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED)
bootutil_rsa_oaep_decrypt(bootutil_rsa_context * ctx,size_t * olen,const uint8_t * input,uint8_t * output,size_t output_max_len)85 static int bootutil_rsa_oaep_decrypt(
86 bootutil_rsa_context *ctx,
87 size_t *olen,
88 const uint8_t *input,
89 uint8_t *output,
90 size_t output_max_len)
91 {
92 psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
93
94 /* Perform an additional defensive check to compare the modulus of the RSA
95 * key to the expected input of the decryption function, i.e. TLV_ENC_RSA_SZ
96 */
97 psa_key_attributes_t key_attr = psa_key_attributes_init();
98 status = psa_get_key_attributes(ctx->key_id, &key_attr);
99 if (status != PSA_SUCCESS) {
100 return -1;
101 }
102 size_t input_size = PSA_BITS_TO_BYTES(psa_get_key_bits(&key_attr));
103 if (input_size != TLV_ENC_RSA_SZ) {
104 return -1;
105 }
106
107 status = psa_asymmetric_decrypt(ctx->key_id, PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256),
108 input, TLV_ENC_RSA_SZ, NULL, 0,
109 output, output_max_len, olen);
110 return (int)status;
111 }
112
113 /*
114 * Parse a RSA private key with format specified in RFC3447 A.1.2
115 *
116 * The key is meant to be used for OAEP decrypt hence algorithm and usage are hardcoded
117 */
118 static int
bootutil_rsa_parse_private_key(bootutil_rsa_context * ctx,uint8_t ** p,uint8_t * end)119 bootutil_rsa_parse_private_key(bootutil_rsa_context *ctx, uint8_t **p, uint8_t *end)
120 {
121 psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
122 psa_key_attributes_t key_attributes = psa_key_attributes_init();
123
124 /* Set attributes and import key */
125 psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_DECRYPT);
126 psa_set_key_algorithm(&key_attributes, PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256));
127 psa_set_key_type(&key_attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
128
129 status = psa_import_key(&key_attributes, *p, (end - *p), &ctx->key_id);
130 return (int)status;
131 }
132
133 #endif /* BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED */
134
135 #if defined(BOOTUTIL_CRYPTO_RSA_SIGN_ENABLED)
136 /*
137 * Parse a RSA public key with format specified in RFC3447 A.1.1
138 *
139 * The key is meant to be used for PSS signature verification hence algorithm and usage are hardcoded
140 */
141 static int
bootutil_rsa_parse_public_key(bootutil_rsa_context * ctx,uint8_t ** p,uint8_t * end)142 bootutil_rsa_parse_public_key(bootutil_rsa_context *ctx, uint8_t **p, uint8_t *end)
143 {
144 psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
145 psa_key_attributes_t key_attributes = psa_key_attributes_init();
146
147 /* Set attributes and import key */
148 psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_VERIFY_HASH);
149 psa_set_key_algorithm(&key_attributes, PSA_ALG_RSA_PSS(PSA_ALG_SHA_256));
150 psa_set_key_type(&key_attributes, PSA_KEY_TYPE_RSA_PUBLIC_KEY);
151
152 status = psa_import_key(&key_attributes, *p, (end - *p), &ctx->key_id);
153 return (int)status;
154 }
155
156 /* Get the modulus (N) length in bytes */
bootutil_rsa_get_len(const bootutil_rsa_context * ctx)157 static size_t bootutil_rsa_get_len(const bootutil_rsa_context *ctx)
158 {
159 psa_key_attributes_t key_attributes = psa_key_attributes_init();
160 psa_status_t status = psa_get_key_attributes(ctx->key_id, &key_attributes);
161 if (status != PSA_SUCCESS) {
162 return 0;
163 }
164 return PSA_BITS_TO_BYTES(psa_get_key_bits(&key_attributes));
165 }
166
167 /* PSA Crypto has a dedicated API for RSASSA-PSS verification */
bootutil_rsassa_pss_verify(const bootutil_rsa_context * ctx,uint8_t * hash,size_t hlen,uint8_t * sig,size_t slen)168 static inline int bootutil_rsassa_pss_verify(const bootutil_rsa_context *ctx,
169 uint8_t *hash, size_t hlen, uint8_t *sig, size_t slen)
170 {
171 return (int) psa_verify_hash(ctx->key_id, PSA_ALG_RSA_PSS(PSA_ALG_SHA_256),
172 hash, hlen, sig, slen);
173 }
174 #endif /* BOOTUTIL_CRYPTO_RSA_SIGN_ENABLED */
175
176 #elif defined(MCUBOOT_USE_MBED_TLS)
177
178 typedef mbedtls_rsa_context bootutil_rsa_context;
179
180 static inline void bootutil_rsa_init(bootutil_rsa_context *ctx)
181 {
182 #if MBEDTLS_VERSION_NUMBER >= 0x03000000
183 mbedtls_rsa_init(ctx);
184 mbedtls_rsa_set_padding(ctx, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
185 #else
186 mbedtls_rsa_init(ctx, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
187 #endif
188 }
189
190 static inline void bootutil_rsa_drop(bootutil_rsa_context *ctx)
191 {
192 mbedtls_rsa_free(ctx);
193 }
194
195 #if defined(BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED) && (MBEDTLS_VERSION_NUMBER >= 0x03000000)
196 static int fake_rng(void *p_rng, unsigned char *output, size_t len);
197 #endif /* BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED && MBEDTLS_VERSION_NUMBER >= 3.0 */
198
199 #if defined(BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED)
200 static inline int bootutil_rsa_oaep_decrypt(
201 bootutil_rsa_context *ctx,
202 size_t *olen,
203 const uint8_t *input,
204 uint8_t *output,
205 size_t output_max_len)
206 {
207 int rc = -1;
208 #if MBEDTLS_VERSION_NUMBER >= 0x03000000
209 rc = mbedtls_rsa_rsaes_oaep_decrypt(ctx, fake_rng, NULL,
210 NULL, 0, olen, input, output, output_max_len);
211 #else
212 rc = mbedtls_rsa_rsaes_oaep_decrypt(ctx, NULL, NULL, MBEDTLS_RSA_PRIVATE,
213 NULL, 0, olen, input, output, output_max_len);
214 #endif
215 return rc;
216 }
217
218 /*
219 * Parse a RSA private key with format specified in RFC3447 A.1.2
220 */
221 static int
222 bootutil_rsa_parse_private_key(bootutil_rsa_context *ctx, uint8_t **p, uint8_t *end)
223 {
224 size_t len;
225
226 if (mbedtls_asn1_get_tag(p, end, &len,
227 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
228 return -1;
229 }
230
231 if (*p + len != end) {
232 return -2;
233 }
234
235 /* Non-optional fields. */
236 if ( /* version */
237 mbedtls_asn1_get_int(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(ver)) != 0 ||
238 /* public modulus */
239 mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(N)) != 0 ||
240 /* public exponent */
241 mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(E)) != 0 ||
242 /* private exponent */
243 mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(D)) != 0 ||
244 /* primes */
245 mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(P)) != 0 ||
246 mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(Q)) != 0) {
247
248 return -3;
249 }
250
251 #if !defined(MBEDTLS_RSA_NO_CRT)
252 /*
253 * DP/DQ/QP are only used inside mbedTLS if it was built with the
254 * Chinese Remainder Theorem enabled (default). In case it is disabled
255 * we parse, or if not available, we calculate those values.
256 */
257 if (*p < end) {
258 if ( /* d mod (p-1) and d mod (q-1) */
259 mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(DP)) != 0 ||
260 mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(DQ)) != 0 ||
261 /* q ^ (-1) mod p */
262 mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(QP)) != 0) {
263
264 return -4;
265 }
266 } else {
267 if (mbedtls_rsa_deduce_crt(&ctx->MBEDTLS_CONTEXT_MEMBER(P),
268 &ctx->MBEDTLS_CONTEXT_MEMBER(Q),
269 &ctx->MBEDTLS_CONTEXT_MEMBER(D),
270 &ctx->MBEDTLS_CONTEXT_MEMBER(DP),
271 &ctx->MBEDTLS_CONTEXT_MEMBER(DQ),
272 &ctx->MBEDTLS_CONTEXT_MEMBER(QP)) != 0) {
273 return -5;
274 }
275 }
276 #endif /* !MBEDTLS_RSA_NO_CRT */
277
278 ctx->MBEDTLS_CONTEXT_MEMBER(len) = mbedtls_mpi_size(&ctx->MBEDTLS_CONTEXT_MEMBER(N));
279
280 if (mbedtls_rsa_check_privkey(ctx) != 0) {
281 return -6;
282 }
283
284 return 0;
285 }
286 #endif /* BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED */
287
288 #if defined(BOOTUTIL_CRYPTO_RSA_SIGN_ENABLED)
289 /*
290 * Parse a RSA public key with format specified in RFC3447 A.1.1
291 */
292 static int
293 bootutil_rsa_parse_public_key(bootutil_rsa_context *ctx, uint8_t **p, uint8_t *end)
294 {
295 int rc;
296 size_t len;
297
298 if ((rc = mbedtls_asn1_get_tag(p, end, &len,
299 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
300 return -1;
301 }
302
303 if (*p + len != end) {
304 return -2;
305 }
306
307 if ((rc = mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(N))) != 0 ||
308 (rc = mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(E))) != 0) {
309 return -3;
310 }
311
312 ctx->MBEDTLS_CONTEXT_MEMBER(len) = mbedtls_mpi_size(&ctx->MBEDTLS_CONTEXT_MEMBER(N));
313
314 if (*p != end) {
315 return -4;
316 }
317
318 /* The Mbed TLS version is more than 2.6.1 */
319 #if MBEDTLS_VERSION_NUMBER > 0x02060100
320 rc = mbedtls_rsa_import(ctx, &ctx->MBEDTLS_CONTEXT_MEMBER(N), NULL,
321 NULL, NULL, &ctx->MBEDTLS_CONTEXT_MEMBER(E));
322 if (rc != 0) {
323 return -5;
324 }
325 #endif
326
327 rc = mbedtls_rsa_check_pubkey(ctx);
328 if (rc != 0) {
329 return -6;
330 }
331
332 ctx->MBEDTLS_CONTEXT_MEMBER(len) = mbedtls_mpi_size(&ctx->MBEDTLS_CONTEXT_MEMBER(N));
333
334 return 0;
335 }
336
337 /* Get the modulus (N) length in bytes */
338 static inline size_t bootutil_rsa_get_len(const bootutil_rsa_context *ctx)
339 {
340 return mbedtls_rsa_get_len(ctx);
341 }
342
343 /* Performs modular exponentiation using the public key output = input^E mod N */
344 static inline int bootutil_rsa_public(bootutil_rsa_context *ctx, const uint8_t *input, uint8_t *output)
345 {
346 return mbedtls_rsa_public(ctx, input, output);
347 }
348 #endif /* BOOTUTIL_CRYPTO_RSA_SIGN_ENABLED */
349
350 #endif /* MCUBOOT_USE_MBED_TLS */
351
352 #ifdef __cplusplus
353 }
354 #endif
355
356 #endif /* __BOOTUTIL_CRYPTO_RSA_H_ */
357