1
1
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
2
+ // Copyright 2022 Jeff Epler for Adafruit Industries
2
3
//
3
4
// Licensed under the Apache License, Version 2.0 (the "License");
4
5
// you may not use this file except in compliance with the License.
12
13
// See the License for the specific language governing permissions and
13
14
// limitations under the License.
14
15
16
+ #define BUNDLE_MAX_CERTS (200)
15
17
16
18
#include <string.h>
17
- #include <esp_system.h>
18
- #include "esp_crt_bundle.h"
19
- #include "esp_log.h"
19
+
20
+ #include "py/runtime.h"
21
+ #include "py/mperrno.h"
22
+ #include "mbedtls/x509_crt.h"
23
+ #include "mbedtls/crt_bundle.h"
20
24
21
25
#define BUNDLE_HEADER_OFFSET 2
22
26
#define CRT_HEADER_OFFSET 4
23
27
24
- static const char * TAG = "esp-x509-crt-bundle" ;
25
-
26
28
/* a dummy certificate so that
27
29
* cacert_ptr passes non-NULL check during handshake */
28
30
static mbedtls_x509_crt s_dummy_crt ;
29
31
32
+ #define TAG "x509-crt-bundle"
33
+
34
+ #define LOGE (tag , fmt , ...) mp_printf(&mp_plat_print, tag ":" fmt "\n",##__VA_ARGS__)
35
+ #if 0
36
+ #define LOGI (tag , fmt , ...) mp_printf(&mp_plat_print, tag ":" fmt "\n",##__VA_ARGS__)
37
+ #define LOGD (tag , fmt , ...) mp_printf(&mp_plat_print, tag ":" fmt "\n",##__VA_ARGS__)
38
+ #else
39
+ #define LOGI (tag , fmt , ...) do {} while (0)
40
+ #define LOGD (tag , fmt , ...) do {} while (0)
41
+ #endif
30
42
31
- extern const uint8_t x509_crt_imported_bundle_bin_start [] asm("_binary_x509_crt_bundle_start" );
32
- extern const uint8_t x509_crt_imported_bundle_bin_end [] asm("_binary_x509_crt_bundle_end" );
43
+ extern const uint8_t x509_crt_imported_bundle_bin_start [] asm ("_binary_x509_crt_bundle_start" );
44
+ extern const uint8_t x509_crt_imported_bundle_bin_end [] asm ("_binary_x509_crt_bundle_end" );
33
45
34
46
35
47
typedef struct crt_bundle_t {
@@ -40,42 +52,41 @@ typedef struct crt_bundle_t {
40
52
41
53
static crt_bundle_t s_crt_bundle ;
42
54
43
- static int esp_crt_check_signature (mbedtls_x509_crt * child , const uint8_t * pub_key_buf , size_t pub_key_len );
55
+ static int crt_check_signature (mbedtls_x509_crt * child , const uint8_t * pub_key_buf , size_t pub_key_len );
44
56
45
57
46
- static int esp_crt_check_signature (mbedtls_x509_crt * child , const uint8_t * pub_key_buf , size_t pub_key_len )
47
- {
58
+ static int crt_check_signature (mbedtls_x509_crt * child , const uint8_t * pub_key_buf , size_t pub_key_len ) {
48
59
int ret = 0 ;
49
60
mbedtls_x509_crt parent ;
50
61
const mbedtls_md_info_t * md_info ;
51
62
unsigned char hash [MBEDTLS_MD_MAX_SIZE ];
52
63
53
64
mbedtls_x509_crt_init (& parent );
54
65
55
- if ( (ret = mbedtls_pk_parse_public_key (& parent .pk , pub_key_buf , pub_key_len ) ) != 0 ) {
56
- ESP_LOGE (TAG , "PK parse failed with error %X" , ret );
66
+ if ((ret = mbedtls_pk_parse_public_key (& parent .pk , pub_key_buf , pub_key_len )) != 0 ) {
67
+ LOGE (TAG , "PK parse failed with error %X" , ret );
57
68
goto cleanup ;
58
69
}
59
70
60
71
61
72
// Fast check to avoid expensive computations when not necessary
62
73
if (!mbedtls_pk_can_do (& parent .pk , child -> sig_pk )) {
63
- ESP_LOGE (TAG , "Simple compare failed" );
74
+ LOGE (TAG , "Simple compare failed" );
64
75
ret = -1 ;
65
76
goto cleanup ;
66
77
}
67
78
68
79
md_info = mbedtls_md_info_from_type (child -> sig_md );
69
- if ( (ret = mbedtls_md ( md_info , child -> tbs .p , child -> tbs .len , hash )) != 0 ) {
70
- ESP_LOGE (TAG , "Internal mbedTLS error %X" , ret );
80
+ if ((ret = mbedtls_md (md_info , child -> tbs .p , child -> tbs .len , hash )) != 0 ) {
81
+ LOGE (TAG , "Internal mbedTLS error %X" , ret );
71
82
goto cleanup ;
72
83
}
73
84
74
- if ( (ret = mbedtls_pk_verify_ext ( child -> sig_pk , child -> sig_opts , & parent .pk ,
75
- child -> sig_md , hash , mbedtls_md_get_size ( md_info ),
76
- child -> sig .p , child -> sig .len )) != 0 ) {
85
+ if ((ret = mbedtls_pk_verify_ext (child -> sig_pk , child -> sig_opts , & parent .pk ,
86
+ child -> sig_md , hash , mbedtls_md_get_size (md_info ),
87
+ child -> sig .p , child -> sig .len )) != 0 ) {
77
88
78
- ESP_LOGE (TAG , "PK verify failed with error %X" , ret );
89
+ LOGE (TAG , "PK verify failed with error %X" , ret );
79
90
goto cleanup ;
80
91
}
81
92
cleanup :
@@ -91,8 +102,7 @@ static int esp_crt_check_signature(mbedtls_x509_crt *child, const uint8_t *pub_k
91
102
* only verify the first untrusted link in the chain is signed by the
92
103
* root certificate in the trusted bundle
93
104
*/
94
- int esp_crt_verify_callback (void * buf , mbedtls_x509_crt * crt , int depth , uint32_t * flags )
95
- {
105
+ static int crt_verify_callback (void * buf , mbedtls_x509_crt * crt , int depth , uint32_t * flags ) {
96
106
mbedtls_x509_crt * child = crt ;
97
107
98
108
/* It's OK for a trusted cert to have a weak signature hash alg.
@@ -105,11 +115,11 @@ int esp_crt_verify_callback(void *buf, mbedtls_x509_crt *crt, int depth, uint32_
105
115
106
116
107
117
if (s_crt_bundle .crts == NULL ) {
108
- ESP_LOGE (TAG , "No certificates in bundle" );
118
+ LOGE (TAG , "No certificates in bundle" );
109
119
return MBEDTLS_ERR_X509_FATAL_ERROR ;
110
120
}
111
121
112
- ESP_LOGD (TAG , "%d certificates in bundle" , s_crt_bundle .num_certs );
122
+ LOGD (TAG , "%d certificates in bundle" , s_crt_bundle .num_certs );
113
123
114
124
size_t name_len = 0 ;
115
125
const uint8_t * crt_name ;
@@ -124,7 +134,7 @@ int esp_crt_verify_callback(void *buf, mbedtls_x509_crt *crt, int depth, uint32_
124
134
name_len = s_crt_bundle .crts [middle ][0 ] << 8 | s_crt_bundle .crts [middle ][1 ];
125
135
crt_name = s_crt_bundle .crts [middle ] + CRT_HEADER_OFFSET ;
126
136
127
- int cmp_res = memcmp (child -> issuer_raw .p , crt_name , name_len );
137
+ int cmp_res = memcmp (child -> issuer_raw .p , crt_name , name_len );
128
138
if (cmp_res == 0 ) {
129
139
crt_found = true;
130
140
break ;
@@ -139,42 +149,41 @@ int esp_crt_verify_callback(void *buf, mbedtls_x509_crt *crt, int depth, uint32_
139
149
int ret = MBEDTLS_ERR_X509_FATAL_ERROR ;
140
150
if (crt_found ) {
141
151
size_t key_len = s_crt_bundle .crts [middle ][2 ] << 8 | s_crt_bundle .crts [middle ][3 ];
142
- ret = esp_crt_check_signature (child , s_crt_bundle .crts [middle ] + CRT_HEADER_OFFSET + name_len , key_len );
152
+ ret = crt_check_signature (child , s_crt_bundle .crts [middle ] + CRT_HEADER_OFFSET + name_len , key_len );
143
153
}
144
154
145
155
if (ret == 0 ) {
146
- ESP_LOGI (TAG , "Certificate validated" );
156
+ LOGI (TAG , "Certificate validated" );
147
157
* flags = 0 ;
148
158
return 0 ;
149
159
}
150
160
151
- ESP_LOGE (TAG , "Failed to verify certificate" );
161
+ LOGE (TAG , "Failed to verify certificate" );
152
162
return MBEDTLS_ERR_X509_FATAL_ERROR ;
153
163
}
154
164
155
165
156
166
/* Initialize the bundle into an array so we can do binary search for certs,
157
167
the bundle generated by the python utility is already presorted by subject name
158
168
*/
159
- static esp_err_t esp_crt_bundle_init (const uint8_t * x509_bundle , size_t bundle_size )
160
- {
169
+ static err_t crt_bundle_init (const uint8_t * x509_bundle , size_t bundle_size ) {
161
170
if (bundle_size < BUNDLE_HEADER_OFFSET + CRT_HEADER_OFFSET ) {
162
- ESP_LOGE (TAG , "Invalid certificate bundle" );
163
- return ESP_ERR_INVALID_ARG ;
171
+ LOGE (TAG , "Invalid certificate bundle" );
172
+ return - MP_EINVAL ;
164
173
}
165
174
166
175
uint16_t num_certs = (x509_bundle [0 ] << 8 ) | x509_bundle [1 ];
167
- if (num_certs > CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS ) {
168
- ESP_LOGE ( TAG , " No. of certs in the certificate bundle = %d exceeds\n"
169
- " Max allowed certificates in the certificate bundle = %d\n"
170
- " Please update the menuconfig option with appropriate value" , num_certs , CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS );
171
- return ESP_ERR_INVALID_ARG ;
176
+ if (num_certs > BUNDLE_MAX_CERTS ) {
177
+ // No. of certs in the certificate bundle = %d exceeds\n"
178
+ // Max allowed certificates in the certificate bundle = %d\n"
179
+ // Please update the menuconfig option with appropriate value", num_certs, BUNDLE_MAX_CERTS
180
+ return - MP_E2BIG ;
172
181
}
173
182
174
- const uint8_t * * crts = calloc (num_certs , sizeof (x509_bundle ));
183
+ const uint8_t * * crts = m_tracked_calloc (num_certs , sizeof (x509_bundle ));
175
184
if (crts == NULL ) {
176
- ESP_LOGE (TAG , "Unable to allocate memory for bundle" );
177
- return ESP_ERR_NO_MEM ;
185
+ LOGE (TAG , "Unable to allocate memory for bundle" );
186
+ return - MP_ENOMEM ;
178
187
}
179
188
180
189
const uint8_t * cur_crt ;
@@ -185,67 +194,62 @@ static esp_err_t esp_crt_bundle_init(const uint8_t *x509_bundle, size_t bundle_s
185
194
for (int i = 0 ; i < num_certs ; i ++ ) {
186
195
crts [i ] = cur_crt ;
187
196
if (cur_crt + CRT_HEADER_OFFSET > bundle_end ) {
188
- ESP_LOGE (TAG , "Invalid certificate bundle" );
189
- free (crts );
190
- return ESP_ERR_INVALID_ARG ;
197
+ LOGE (TAG , "Invalid certificate bundle" );
198
+ m_tracked_free (crts );
199
+ return - MP_EINVAL ;
191
200
}
192
201
size_t name_len = cur_crt [0 ] << 8 | cur_crt [1 ];
193
202
size_t key_len = cur_crt [2 ] << 8 | cur_crt [3 ];
194
203
cur_crt = cur_crt + CRT_HEADER_OFFSET + name_len + key_len ;
195
204
}
196
205
197
206
if (cur_crt > bundle_end ) {
198
- ESP_LOGE (TAG , "Invalid certificate bundle" );
199
- free (crts );
200
- return ESP_ERR_INVALID_ARG ;
207
+ LOGE (TAG , "Invalid certificate bundle" );
208
+ m_tracked_free (crts );
209
+ return - MP_EINVAL ;
201
210
}
202
211
203
212
/* The previous crt bundle is only updated when initialization of the
204
213
* current crt_bundle is successful */
205
214
/* Free previous crt_bundle */
206
- free (s_crt_bundle .crts );
215
+ m_tracked_free (s_crt_bundle .crts );
207
216
s_crt_bundle .num_certs = num_certs ;
208
217
s_crt_bundle .crts = crts ;
209
- return ESP_OK ;
218
+ return 0 ;
210
219
}
211
220
212
- esp_err_t esp_crt_bundle_attach (void * conf )
213
- {
214
- esp_err_t ret = ESP_OK ;
221
+ int crt_bundle_attach (mbedtls_ssl_config * ssl_conf ) {
222
+ int ret = 0 ;
215
223
// If no bundle has been set by the user then use the bundle embedded in the binary
216
224
if (s_crt_bundle .crts == NULL ) {
217
- ret = esp_crt_bundle_init (x509_crt_imported_bundle_bin_start , x509_crt_imported_bundle_bin_end - x509_crt_imported_bundle_bin_start );
225
+ ret = crt_bundle_init (x509_crt_imported_bundle_bin_start , x509_crt_imported_bundle_bin_end - x509_crt_imported_bundle_bin_start );
218
226
}
219
227
220
- if (ret != ESP_OK ) {
221
- ESP_LOGE (TAG , "Failed to attach bundle" );
228
+ if (ret != 0 ) {
222
229
return ret ;
223
230
}
224
231
225
- if (conf ) {
232
+ if (ssl_conf ) {
226
233
/* point to a dummy certificate
227
234
* This is only required so that the
228
235
* cacert_ptr passes non-NULL check during handshake
229
236
*/
230
- mbedtls_ssl_config * ssl_conf = (mbedtls_ssl_config * )conf ;
231
237
mbedtls_x509_crt_init (& s_dummy_crt );
232
238
mbedtls_ssl_conf_ca_chain (ssl_conf , & s_dummy_crt , NULL );
233
- mbedtls_ssl_conf_verify (ssl_conf , esp_crt_verify_callback , NULL );
239
+ mbedtls_ssl_conf_verify (ssl_conf , crt_verify_callback , NULL );
234
240
}
235
241
236
242
return ret ;
237
243
}
238
244
239
- void esp_crt_bundle_detach (mbedtls_ssl_config * conf )
240
- {
241
- free (s_crt_bundle .crts );
245
+ void crt_bundle_detach (mbedtls_ssl_config * conf ) {
246
+ m_tracked_free (s_crt_bundle .crts );
242
247
s_crt_bundle .crts = NULL ;
243
248
if (conf ) {
244
249
mbedtls_ssl_conf_verify (conf , NULL , NULL );
245
250
}
246
251
}
247
252
248
- esp_err_t esp_crt_bundle_set (const uint8_t * x509_bundle , size_t bundle_size )
249
- {
250
- return esp_crt_bundle_init (x509_bundle , bundle_size );
253
+ int crt_bundle_set (const uint8_t * x509_bundle , size_t bundle_size ) {
254
+ return crt_bundle_init (x509_bundle , bundle_size );
251
255
}
0 commit comments