1 /*
2  * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "esp_ds.h"
8 #include "rsa_sign_alt.h"
9 #include "esp_memory_utils.h"
10 
11 #ifdef CONFIG_IDF_TARGET_ESP32S2
12 #include "esp32s2/rom/digital_signature.h"
13 #elif CONFIG_IDF_TARGET_ESP32C3
14 #include "esp32c3/rom/digital_signature.h"
15 #elif CONFIG_IDF_TARGET_ESP32S3
16 #include "esp32s3/rom/digital_signature.h"
17 #elif CONFIG_IDF_TARGET_ESP32C6
18 #include "esp32c6/rom/digital_signature.h"
19 #elif CONFIG_IDF_TARGET_ESP32H2
20 #include "esp32h2/rom/digital_signature.h"
21 #else
22 #error   "Selected target does not support esp_rsa_sign_alt (for DS)"
23 #endif
24 
25 #include "esp_log.h"
26 #include "esp_heap_caps.h"
27 #include "freertos/FreeRTOS.h"
28 #include "freertos/semphr.h"
29 #include <mbedtls/build_info.h>
30 static const char *TAG = "ESP_RSA_SIGN_ALT";
31 #define SWAP_INT32(x) (((x) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | ((x) << 24))
32 
33 #include "mbedtls/rsa.h"
34 #include "mbedtls/oid.h"
35 #include "mbedtls/platform_util.h"
36 #include <string.h>
37 
38 static hmac_key_id_t s_esp_ds_hmac_key_id;
39 static esp_ds_data_t *s_ds_data;
40 static SemaphoreHandle_t s_ds_lock;
41 static int s_timeout_ms = 0;
42 
43 /* key length in bytes = (esp_digital_signature_length_t key + 1 ) * FACTOR_KEYLEN_IN_BYTES */
44 #define FACTOR_KEYLEN_IN_BYTES 4
45 
46 /* Lock for the DS session, other TLS connections trying to use the DS peripheral will be blocked
47  * till this DS session is completed (i.e. TLS handshake for this connection is completed) */
esp_ds_conn_lock(void)48 static void __attribute__((constructor)) esp_ds_conn_lock (void)
49 {
50     if ((s_ds_lock = xSemaphoreCreateMutex()) == NULL) {
51         ESP_EARLY_LOGE(TAG, "mutex for the DS session lock could not be created");
52     }
53 }
54 
esp_ds_set_session_timeout(int timeout)55 void esp_ds_set_session_timeout(int timeout)
56 {
57     /* add additional offset of 1000 ms to have enough time for deleting the TLS connection and free the previous ds context after exceeding timeout value (this offset also helps when timeout is set to 0) */
58     if (timeout > s_timeout_ms) {
59         s_timeout_ms = timeout + 1000;
60     }
61 }
62 
esp_ds_init_data_ctx(esp_ds_data_ctx_t * ds_data)63 esp_err_t esp_ds_init_data_ctx(esp_ds_data_ctx_t *ds_data)
64 {
65     if (ds_data == NULL || ds_data->esp_ds_data == NULL) {
66         return ESP_ERR_INVALID_ARG;
67     }
68     /* mutex is given back when the DS context is freed after the TLS handshake is completed or in case of failure (at cleanup) */
69     if ((xSemaphoreTake(s_ds_lock, s_timeout_ms / portTICK_PERIOD_MS) != pdTRUE)) {
70         ESP_LOGE(TAG, "ds_lock could not be obtained in specified time");
71         return ESP_FAIL;
72     }
73     s_ds_data = ds_data->esp_ds_data;
74     ESP_LOGD(TAG, "Using DS with key block %u, RSA length %u", ds_data->efuse_key_id, ds_data->rsa_length_bits);
75     s_esp_ds_hmac_key_id = (hmac_key_id_t) ds_data->efuse_key_id;
76 
77     const unsigned rsa_length_int = (ds_data->rsa_length_bits / 32) - 1;
78     if (esp_ptr_byte_accessible(s_ds_data)) {
79         /* calculate the rsa_length in terms of esp_digital_signature_length_t which is required for the internal DS API */
80         s_ds_data->rsa_length = rsa_length_int;
81     } else if (s_ds_data->rsa_length != rsa_length_int) {
82         /*
83          * Configuration data is most likely from DROM segment and it
84          * is not properly formatted for all parameters consideration.
85          * Moreover, we can not modify as it is read-only and hence
86          * the error.
87          */
88         ESP_LOGE(TAG, "RSA length mismatch %u, %u", s_ds_data->rsa_length, rsa_length_int);
89         return ESP_ERR_INVALID_ARG;
90     }
91 
92     return ESP_OK;
93 }
94 
esp_ds_release_ds_lock(void)95 void esp_ds_release_ds_lock(void)
96 {
97     if (xSemaphoreGetMutexHolder(s_ds_lock) == xTaskGetCurrentTaskHandle()) {
98         /* Give back the semaphore (DS lock) */
99         xSemaphoreGive(s_ds_lock);
100     }
101 }
102 
esp_ds_get_keylen(void * ctx)103 size_t esp_ds_get_keylen(void *ctx)
104 {
105     /* calculating the rsa_length in bytes */
106     return ((s_ds_data->rsa_length + 1) * FACTOR_KEYLEN_IN_BYTES);
107 }
108 
rsa_rsassa_pkcs1_v15_encode(mbedtls_md_type_t md_alg,unsigned int hashlen,const unsigned char * hash,size_t dst_len,unsigned char * dst)109 static int rsa_rsassa_pkcs1_v15_encode( mbedtls_md_type_t md_alg,
110                                         unsigned int hashlen,
111                                         const unsigned char *hash,
112                                         size_t dst_len,
113                                         unsigned char *dst )
114 {
115     size_t oid_size  = 0;
116     size_t nb_pad    = dst_len;
117     unsigned char *p = dst;
118     const char *oid  = NULL;
119 
120     /* Are we signing hashed or raw data? */
121     if ( md_alg != MBEDTLS_MD_NONE ) {
122         const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_alg );
123         if ( md_info == NULL ) {
124             return ( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
125         }
126 
127         if ( mbedtls_oid_get_oid_by_md( md_alg, &oid, &oid_size ) != 0 ) {
128             return ( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
129         }
130 
131         hashlen = mbedtls_md_get_size( md_info );
132 
133         /* Double-check that 8 + hashlen + oid_size can be used as a
134          * 1-byte ASN.1 length encoding and that there's no overflow. */
135         if ( 8 + hashlen + oid_size  >= 0x80         ||
136                 10 + hashlen            <  hashlen      ||
137                 10 + hashlen + oid_size <  10 + hashlen ) {
138             return ( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
139         }
140 
141         /*
142          * Static bounds check:
143          * - Need 10 bytes for five tag-length pairs.
144          *   (Insist on 1-byte length encodings to protect against variants of
145          *    Bleichenbacher's forgery attack against lax PKCS#1v1.5 verification)
146          * - Need hashlen bytes for hash
147          * - Need oid_size bytes for hash alg OID.
148          */
149         if ( nb_pad < 10 + hashlen + oid_size ) {
150             return ( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
151         }
152         nb_pad -= 10 + hashlen + oid_size;
153     } else {
154         if ( nb_pad < hashlen ) {
155             return ( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
156         }
157 
158         nb_pad -= hashlen;
159     }
160 
161     /* Need space for signature header and padding delimiter (3 bytes),
162      * and 8 bytes for the minimal padding */
163     if ( nb_pad < 3 + 8 ) {
164         return ( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
165     }
166     nb_pad -= 3;
167 
168     /* Now nb_pad is the amount of memory to be filled
169      * with padding, and at least 8 bytes long. */
170 
171     /* Write signature header and padding */
172     *p++ = 0;
173     *p++ = MBEDTLS_RSA_SIGN;
174     memset( p, 0xFF, nb_pad );
175     p += nb_pad;
176     *p++ = 0;
177 
178     /* Are we signing raw data? */
179     if ( md_alg == MBEDTLS_MD_NONE ) {
180         memcpy( p, hash, hashlen );
181         return ( 0 );
182     }
183 
184     /* Signing hashed data, add corresponding ASN.1 structure
185      *
186      * DigestInfo ::= SEQUENCE {
187      *   digestAlgorithm DigestAlgorithmIdentifier,
188      *   digest Digest }
189      * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
190      * Digest ::= OCTET STRING
191      *
192      * Schematic:
193      * TAG-SEQ + LEN [ TAG-SEQ + LEN [ TAG-OID  + LEN [ OID  ]
194      *                                 TAG-NULL + LEN [ NULL ] ]
195      *                 TAG-OCTET + LEN [ HASH ] ]
196      */
197     *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED;
198     *p++ = (unsigned char)( 0x08 + oid_size + hashlen );
199     *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED;
200     *p++ = (unsigned char)( 0x04 + oid_size );
201     *p++ = MBEDTLS_ASN1_OID;
202     *p++ = (unsigned char) oid_size;
203     memcpy( p, oid, oid_size );
204     p += oid_size;
205     *p++ = MBEDTLS_ASN1_NULL;
206     *p++ = 0x00;
207     *p++ = MBEDTLS_ASN1_OCTET_STRING;
208     *p++ = (unsigned char) hashlen;
209     memcpy( p, hash, hashlen );
210     p += hashlen;
211 
212     /* Just a sanity-check, should be automatic
213      * after the initial bounds check. */
214     if ( p != dst + dst_len ) {
215         mbedtls_platform_zeroize( dst, dst_len );
216         return ( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
217     }
218 
219     return ( 0 );
220 }
221 
222 
esp_ds_rsa_sign(void * ctx,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng,mbedtls_md_type_t md_alg,unsigned int hashlen,const unsigned char * hash,unsigned char * sig)223 int esp_ds_rsa_sign( void *ctx,
224                      int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
225                      mbedtls_md_type_t md_alg, unsigned int hashlen,
226                      const unsigned char *hash, unsigned char *sig )
227 {
228     esp_ds_context_t *esp_ds_ctx;
229     esp_err_t ds_r;
230     int ret = -1;
231     uint32_t *signature = heap_caps_malloc_prefer((s_ds_data->rsa_length + 1) * FACTOR_KEYLEN_IN_BYTES, 2, MALLOC_CAP_32BIT | MALLOC_CAP_INTERNAL, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL);
232     if (signature == NULL) {
233         ESP_LOGE(TAG, "Could not allocate memory for internal DS operations");
234         return -1;
235     }
236 
237     if ((ret = (rsa_rsassa_pkcs1_v15_encode( md_alg, hashlen, hash, ((s_ds_data->rsa_length + 1) * FACTOR_KEYLEN_IN_BYTES), sig ))) != 0) {
238         ESP_LOGE(TAG, "Error in pkcs1_v15 encoding, returned %d", ret);
239         heap_caps_free(signature);
240         return -1;
241     }
242 
243     for (unsigned int i = 0; i < (s_ds_data->rsa_length + 1); i++) {
244         signature[i] = SWAP_INT32(((uint32_t *)sig)[(s_ds_data->rsa_length + 1) - (i + 1)]);
245     }
246 
247     ds_r = esp_ds_start_sign((const void *)signature,
248                              s_ds_data,
249                              s_esp_ds_hmac_key_id,
250                              &esp_ds_ctx);
251     if (ds_r != ESP_OK) {
252         ESP_LOGE(TAG, "Error in esp_ds_start_sign, returned %d ", ds_r);
253         heap_caps_free(signature);
254         return -1;
255     }
256 
257     ds_r = esp_ds_finish_sign((void *)signature, esp_ds_ctx);
258     if (ds_r != ESP_OK) {
259         if (ds_r == ESP_ERR_HW_CRYPTO_DS_INVALID_DIGEST) {
260             ESP_LOGE(TAG, "Invalid digest in DS data reported by esp_ds_finish_sign");
261         } else {
262             ESP_LOGE(TAG, "Error in esp_ds_finish_sign, returned %d ", ds_r);
263         }
264         heap_caps_free(signature);
265         return -1;
266     }
267 
268     for (unsigned int i = 0; i < (s_ds_data->rsa_length + 1); i++) {
269         ((uint32_t *)sig)[i] = SWAP_INT32(((uint32_t *)signature)[(s_ds_data->rsa_length + 1) - (i + 1)]);
270     }
271     heap_caps_free(signature);
272     return 0;
273 }
274