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