Skip to content

Commit 944d388

Browse files
committed
copy esp_crt_bundle.c from esp-idf@d51f7d8821
1 parent a64c1a1 commit 944d388

File tree

1 file changed

+251
-0
lines changed

1 file changed

+251
-0
lines changed
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
16+
#include <string.h>
17+
#include <esp_system.h>
18+
#include "esp_crt_bundle.h"
19+
#include "esp_log.h"
20+
21+
#define BUNDLE_HEADER_OFFSET 2
22+
#define CRT_HEADER_OFFSET 4
23+
24+
static const char *TAG = "esp-x509-crt-bundle";
25+
26+
/* a dummy certificate so that
27+
* cacert_ptr passes non-NULL check during handshake */
28+
static mbedtls_x509_crt s_dummy_crt;
29+
30+
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");
33+
34+
35+
typedef struct crt_bundle_t {
36+
const uint8_t **crts;
37+
uint16_t num_certs;
38+
size_t x509_crt_bundle_len;
39+
} crt_bundle_t;
40+
41+
static crt_bundle_t s_crt_bundle;
42+
43+
static int esp_crt_check_signature(mbedtls_x509_crt *child, const uint8_t *pub_key_buf, size_t pub_key_len);
44+
45+
46+
static int esp_crt_check_signature(mbedtls_x509_crt *child, const uint8_t *pub_key_buf, size_t pub_key_len)
47+
{
48+
int ret = 0;
49+
mbedtls_x509_crt parent;
50+
const mbedtls_md_info_t *md_info;
51+
unsigned char hash[MBEDTLS_MD_MAX_SIZE];
52+
53+
mbedtls_x509_crt_init(&parent);
54+
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);
57+
goto cleanup;
58+
}
59+
60+
61+
// Fast check to avoid expensive computations when not necessary
62+
if (!mbedtls_pk_can_do(&parent.pk, child->sig_pk)) {
63+
ESP_LOGE(TAG, "Simple compare failed");
64+
ret = -1;
65+
goto cleanup;
66+
}
67+
68+
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);
71+
goto cleanup;
72+
}
73+
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 ) {
77+
78+
ESP_LOGE(TAG, "PK verify failed with error %X", ret);
79+
goto cleanup;
80+
}
81+
cleanup:
82+
mbedtls_x509_crt_free(&parent);
83+
84+
return ret;
85+
}
86+
87+
88+
/* This callback is called for every certificate in the chain. If the chain
89+
* is proper each intermediate certificate is validated through its parent
90+
* in the x509_crt_verify_chain() function. So this callback should
91+
* only verify the first untrusted link in the chain is signed by the
92+
* root certificate in the trusted bundle
93+
*/
94+
int esp_crt_verify_callback(void *buf, mbedtls_x509_crt *crt, int depth, uint32_t *flags)
95+
{
96+
mbedtls_x509_crt *child = crt;
97+
98+
/* It's OK for a trusted cert to have a weak signature hash alg.
99+
as we already trust this certificate */
100+
uint32_t flags_filtered = *flags & ~(MBEDTLS_X509_BADCERT_BAD_MD);
101+
102+
if (flags_filtered != MBEDTLS_X509_BADCERT_NOT_TRUSTED) {
103+
return 0;
104+
}
105+
106+
107+
if (s_crt_bundle.crts == NULL) {
108+
ESP_LOGE(TAG, "No certificates in bundle");
109+
return MBEDTLS_ERR_X509_FATAL_ERROR;
110+
}
111+
112+
ESP_LOGD(TAG, "%d certificates in bundle", s_crt_bundle.num_certs);
113+
114+
size_t name_len = 0;
115+
const uint8_t *crt_name;
116+
117+
bool crt_found = false;
118+
int start = 0;
119+
int end = s_crt_bundle.num_certs - 1;
120+
int middle = (end - start) / 2;
121+
122+
/* Look for the certificate using binary search on subject name */
123+
while (start <= end) {
124+
name_len = s_crt_bundle.crts[middle][0] << 8 | s_crt_bundle.crts[middle][1];
125+
crt_name = s_crt_bundle.crts[middle] + CRT_HEADER_OFFSET;
126+
127+
int cmp_res = memcmp(child->issuer_raw.p, crt_name, name_len );
128+
if (cmp_res == 0) {
129+
crt_found = true;
130+
break;
131+
} else if (cmp_res < 0) {
132+
end = middle - 1;
133+
} else {
134+
start = middle + 1;
135+
}
136+
middle = (start + end) / 2;
137+
}
138+
139+
int ret = MBEDTLS_ERR_X509_FATAL_ERROR;
140+
if (crt_found) {
141+
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);
143+
}
144+
145+
if (ret == 0) {
146+
ESP_LOGI(TAG, "Certificate validated");
147+
*flags = 0;
148+
return 0;
149+
}
150+
151+
ESP_LOGE(TAG, "Failed to verify certificate");
152+
return MBEDTLS_ERR_X509_FATAL_ERROR;
153+
}
154+
155+
156+
/* Initialize the bundle into an array so we can do binary search for certs,
157+
the bundle generated by the python utility is already presorted by subject name
158+
*/
159+
static esp_err_t esp_crt_bundle_init(const uint8_t *x509_bundle, size_t bundle_size)
160+
{
161+
if (bundle_size < BUNDLE_HEADER_OFFSET + CRT_HEADER_OFFSET) {
162+
ESP_LOGE(TAG, "Invalid certificate bundle");
163+
return ESP_ERR_INVALID_ARG;
164+
}
165+
166+
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;
172+
}
173+
174+
const uint8_t **crts = calloc(num_certs, sizeof(x509_bundle));
175+
if (crts == NULL) {
176+
ESP_LOGE(TAG, "Unable to allocate memory for bundle");
177+
return ESP_ERR_NO_MEM;
178+
}
179+
180+
const uint8_t *cur_crt;
181+
/* This is the maximum region that is allowed to access */
182+
const uint8_t *bundle_end = x509_bundle + bundle_size;
183+
cur_crt = x509_bundle + BUNDLE_HEADER_OFFSET;
184+
185+
for (int i = 0; i < num_certs; i++) {
186+
crts[i] = cur_crt;
187+
if (cur_crt + CRT_HEADER_OFFSET > bundle_end) {
188+
ESP_LOGE(TAG, "Invalid certificate bundle");
189+
free(crts);
190+
return ESP_ERR_INVALID_ARG;
191+
}
192+
size_t name_len = cur_crt[0] << 8 | cur_crt[1];
193+
size_t key_len = cur_crt[2] << 8 | cur_crt[3];
194+
cur_crt = cur_crt + CRT_HEADER_OFFSET + name_len + key_len;
195+
}
196+
197+
if (cur_crt > bundle_end) {
198+
ESP_LOGE(TAG, "Invalid certificate bundle");
199+
free(crts);
200+
return ESP_ERR_INVALID_ARG;
201+
}
202+
203+
/* The previous crt bundle is only updated when initialization of the
204+
* current crt_bundle is successful */
205+
/* Free previous crt_bundle */
206+
free(s_crt_bundle.crts);
207+
s_crt_bundle.num_certs = num_certs;
208+
s_crt_bundle.crts = crts;
209+
return ESP_OK;
210+
}
211+
212+
esp_err_t esp_crt_bundle_attach(void *conf)
213+
{
214+
esp_err_t ret = ESP_OK;
215+
// If no bundle has been set by the user then use the bundle embedded in the binary
216+
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);
218+
}
219+
220+
if (ret != ESP_OK) {
221+
ESP_LOGE(TAG, "Failed to attach bundle");
222+
return ret;
223+
}
224+
225+
if (conf) {
226+
/* point to a dummy certificate
227+
* This is only required so that the
228+
* cacert_ptr passes non-NULL check during handshake
229+
*/
230+
mbedtls_ssl_config *ssl_conf = (mbedtls_ssl_config *)conf;
231+
mbedtls_x509_crt_init(&s_dummy_crt);
232+
mbedtls_ssl_conf_ca_chain(ssl_conf, &s_dummy_crt, NULL);
233+
mbedtls_ssl_conf_verify(ssl_conf, esp_crt_verify_callback, NULL);
234+
}
235+
236+
return ret;
237+
}
238+
239+
void esp_crt_bundle_detach(mbedtls_ssl_config *conf)
240+
{
241+
free(s_crt_bundle.crts);
242+
s_crt_bundle.crts = NULL;
243+
if (conf) {
244+
mbedtls_ssl_conf_verify(conf, NULL, NULL);
245+
}
246+
}
247+
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);
251+
}

0 commit comments

Comments
 (0)