1 /* SSL server using plain mbedTLS sockets
2  *
3  * Adapted from the ssl_server example in mbedtls.
4  *
5  * Original Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
6  * Additions Copyright (C) Copyright 2019 Espressif Systems (Shanghai) PTE LTD, Apache 2.0 License.
7  *
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *     http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21 #include "esp_err.h"
22 #include "esp_log.h"
23 
24 #include "freertos/FreeRTOS.h"
25 #include "freertos/task.h"
26 #include "freertos/semphr.h"
27 
28 #include "mbedtls/entropy.h"
29 #include "mbedtls/ctr_drbg.h"
30 #include "mbedtls/certs.h"
31 #include "mbedtls/x509.h"
32 #include "mbedtls/ssl.h"
33 #include "mbedtls/net_sockets.h"
34 #include "mbedtls/error.h"
35 #include "mbedtls/debug.h"
36 
37 #include "esp_crt_bundle.h"
38 
39 #include "unity.h"
40 #include "test_utils.h"
41 
42 #define SERVER_ADDRESS "localhost"
43 #define SERVER_PORT "4433"
44 
45 extern const uint8_t server_cert_chain_pem_start[] asm("_binary_server_cert_chain_pem_start");
46 extern const uint8_t server_cert_chain_pem_end[]   asm("_binary_server_cert_chain_pem_end");
47 
48 extern const uint8_t server_pk_start[] asm("_binary_prvtkey_pem_start");
49 extern const uint8_t server_pk_end[]   asm("_binary_prvtkey_pem_end");
50 
51 extern const uint8_t server_cert_bundle_start[] asm("_binary_server_cert_bundle_start");
52 extern const uint8_t server_cert_bundle_end[] asm("_binary_server_cert_bundle_end");
53 
54 extern const uint8_t bad_md_crt_pem_start[] asm("_binary_bad_md_crt_pem_start");
55 extern const uint8_t bad_md_crt_pem_end[]   asm("_binary_bad_md_crt_pem_end");
56 
57 extern const uint8_t wrong_sig_crt_pem_start[] asm("_binary_wrong_sig_crt_esp32_com_pem_start");
58 extern const uint8_t wrong_sig_crt_pem_end[]   asm("_binary_wrong_sig_crt_esp32_com_pem_end");
59 
60 extern const uint8_t correct_sig_crt_pem_start[] asm("_binary_correct_sig_crt_esp32_com_pem_start");
61 extern const uint8_t correct_sig_crt_pem_end[]   asm("_binary_correct_sig_crt_esp32_com_pem_end");
62 
63 typedef struct {
64     mbedtls_ssl_context ssl;
65     mbedtls_net_context listen_fd;
66     mbedtls_net_context client_fd;
67 
68     mbedtls_entropy_context entropy;
69     mbedtls_ctr_drbg_context ctr_drbg;
70 
71     mbedtls_ssl_config conf;
72     mbedtls_x509_crt cert;
73     mbedtls_pk_context pkey;
74 
75 } mbedtls_endpoint_t;
76 
77 typedef enum {
78     ESP_CRT_VALIDATE_UNKNOWN,
79     ESP_CRT_VALIDATE_OK,
80     ESP_CRT_VALIDATE_FAIL,
81 }esp_crt_validate_res_t;
82 
83 int esp_crt_verify_callback(void *buf, mbedtls_x509_crt *crt, int data, uint32_t *flags);
84 
85 #if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3)
86 // TODO ESP32-S3 IDF-1878
87 
88 static const char *TAG = "cert_bundle_test";
89 
90 static volatile bool exit_flag;
91 
92 esp_err_t endpoint_teardown(mbedtls_endpoint_t *endpoint);
93 
server_setup(mbedtls_endpoint_t * server)94 esp_err_t server_setup(mbedtls_endpoint_t *server)
95 {
96     int ret;
97     mbedtls_ssl_config_init( &server->conf );
98     mbedtls_net_init( &server->listen_fd );
99     mbedtls_net_init( &server->client_fd );
100     mbedtls_ssl_init( &server->ssl );
101     mbedtls_x509_crt_init( &server->cert );
102     mbedtls_pk_init( &server->pkey );
103     mbedtls_entropy_init( &server->entropy );
104     mbedtls_ctr_drbg_init( &server->ctr_drbg );
105 
106     ESP_LOGI(TAG, "Loading the server cert and key");
107     ret = mbedtls_x509_crt_parse( &server->cert, server_cert_chain_pem_start,
108                                   server_cert_chain_pem_end - server_cert_chain_pem_start);
109 
110     if ( ret != 0 ) {
111         ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned %d", ret );
112         return ESP_FAIL;
113     }
114 
115     ret =  mbedtls_pk_parse_key( &server->pkey, (const unsigned char *)server_pk_start,
116                                  server_pk_end - server_pk_start, NULL, 0 );
117     if ( ret != 0 ) {
118         ESP_LOGE(TAG, "mbedtls_pk_parse_key returned %d", ret );
119         return ESP_FAIL;
120     }
121 
122     ESP_LOGI(TAG, "Bind on https://%s:%s/", SERVER_ADDRESS, SERVER_PORT );
123     if ( ( ret = mbedtls_net_bind( &server->listen_fd, NULL, SERVER_PORT, MBEDTLS_NET_PROTO_TCP ) ) != 0 ) {
124         ESP_LOGE(TAG, "mbedtls_net_bind returned %d", ret );
125         return ESP_FAIL;
126     }
127     mbedtls_net_set_nonblock(&server->listen_fd);
128 
129     ESP_LOGI(TAG, "Seeding the random number generator");
130     if ( ( ret = mbedtls_ctr_drbg_seed( &server->ctr_drbg, mbedtls_entropy_func, &server->entropy,
131                                         NULL, 0) ) != 0 ) {
132         ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned %d", ret );
133         return ESP_FAIL;
134     }
135 
136     ESP_LOGI(TAG, "Setting up the SSL data");
137     if ( ( ret = mbedtls_ssl_config_defaults( &server->conf,
138                  MBEDTLS_SSL_IS_SERVER,
139                  MBEDTLS_SSL_TRANSPORT_STREAM,
140                  MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 ) {
141         ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned %d", ret );
142         return ESP_FAIL;
143     }
144 
145     mbedtls_ssl_conf_rng( &server->conf, mbedtls_ctr_drbg_random, &server->ctr_drbg );
146 
147     if (( ret = mbedtls_ssl_conf_own_cert( &server->conf, &server->cert, &server->pkey ) ) != 0 ) {
148         ESP_LOGE(TAG, "mbedtls_ssl_conf_own_cert returned %d", ret );
149         return ESP_FAIL;
150     }
151 
152     if (( ret = mbedtls_ssl_setup( &server->ssl, &server->conf ) ) != 0 ) {
153         ESP_LOGE(TAG, "mbedtls_ssl_setup returned %d", ret );
154         return ESP_FAIL;
155     }
156     return ESP_OK;
157 }
158 
server_task(void * pvParameters)159 void server_task(void *pvParameters)
160 {
161     int ret;
162     mbedtls_endpoint_t server;
163     xSemaphoreHandle *sema = (xSemaphoreHandle *) pvParameters;
164 
165 
166     if (server_setup(&server) != ESP_OK) {
167         ESP_LOGE(TAG, "SSL server setup failed");
168         goto exit;
169     }
170 
171     /* Signal that server is up and hence client task can start now */
172     xSemaphoreGive(*sema);
173 
174     bool connected = false;
175     while (!exit_flag) {
176 
177         ret = mbedtls_net_accept( &server.listen_fd, &server.client_fd, NULL, 0, NULL );
178 
179         if (ret == 0) {
180             connected = true;
181         }
182 
183         if (connected) {
184             mbedtls_ssl_set_bio( &server.ssl, &server.client_fd, mbedtls_net_send, mbedtls_net_recv, NULL );
185             ret = mbedtls_ssl_handshake( &server.ssl );
186             mbedtls_ssl_session_reset(&server.ssl);
187             connected = false;
188         }
189 
190         vTaskDelay(20 / portTICK_PERIOD_MS);
191     }
192     ESP_LOGE(TAG, "Server shutdown");
193 exit:
194     endpoint_teardown(&server);
195     xSemaphoreGive(*sema);
196     vTaskDelete(NULL);
197 }
198 
199 
endpoint_teardown(mbedtls_endpoint_t * endpoint)200 esp_err_t endpoint_teardown(mbedtls_endpoint_t *endpoint)
201 {
202     mbedtls_net_free( &endpoint->client_fd );
203     mbedtls_net_free( &endpoint->listen_fd );
204 
205     mbedtls_x509_crt_free( &endpoint->cert );
206     mbedtls_pk_free( &endpoint->pkey );
207     mbedtls_ssl_free( &endpoint->ssl );
208     mbedtls_ssl_config_free( &endpoint->conf );
209 
210     mbedtls_ctr_drbg_free( &endpoint->ctr_drbg );
211     mbedtls_entropy_free( &endpoint->entropy );
212 
213     return ESP_OK;
214 }
215 
client_setup(mbedtls_endpoint_t * client)216 esp_err_t client_setup(mbedtls_endpoint_t *client)
217 {
218     int ret;
219     mbedtls_ssl_config_init( &client->conf );
220     mbedtls_net_init( &client->client_fd );
221     mbedtls_ssl_init( &client->ssl );
222     mbedtls_x509_crt_init( &client->cert );
223     mbedtls_pk_init( &client->pkey );
224     mbedtls_entropy_init( &client->entropy );
225     mbedtls_ctr_drbg_init( &client->ctr_drbg );
226 
227     ESP_LOGI(TAG, "Seeding the random number generator");
228     if ((ret = mbedtls_ctr_drbg_seed(&client->ctr_drbg, mbedtls_entropy_func, &client->entropy,
229                                      NULL, 0)) != 0) {
230         ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned %d", ret);
231         return ESP_FAIL;
232     }
233 
234     ESP_LOGI(TAG, "Setting hostname for TLS session...");
235     /* Hostname set here should match CN in server certificate */
236     if ((ret = mbedtls_ssl_set_hostname(&client->ssl, SERVER_ADDRESS)) != 0) {
237         ESP_LOGE(TAG, "mbedtls_ssl_set_hostname returned -0x%x", -ret);
238         return ESP_FAIL;
239     }
240 
241     ESP_LOGI(TAG, "Setting up the SSL/TLS structure...");
242     if ((ret = mbedtls_ssl_config_defaults(&client->conf,
243                                            MBEDTLS_SSL_IS_CLIENT,
244                                            MBEDTLS_SSL_TRANSPORT_STREAM,
245                                            MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
246         ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned %d", ret);
247         return ESP_FAIL;
248     }
249     mbedtls_ssl_conf_rng(&client->conf, mbedtls_ctr_drbg_random, &client->ctr_drbg);
250 
251     if ((ret = mbedtls_ssl_setup(&client->ssl, &client->conf)) != 0) {
252         ESP_LOGE(TAG, "mbedtls_ssl_setup returned -0x%x\n\n", -ret);
253         return ESP_FAIL;
254     }
255 
256     return ESP_OK;
257 }
258 
client_task(const uint8_t * bundle,esp_crt_validate_res_t * res)259 int client_task(const uint8_t *bundle, esp_crt_validate_res_t *res)
260 {
261     int ret = ESP_FAIL;
262 
263     mbedtls_endpoint_t client;
264 
265     *res = ESP_CRT_VALIDATE_UNKNOWN;
266 
267     if (client_setup(&client) != ESP_OK) {
268         ESP_LOGE(TAG, "SSL client setup failed");
269         goto exit;
270     }
271 
272     esp_crt_bundle_attach(&client.conf);
273     if (bundle) {
274         /* Set a bundle different from the menuconfig bundle */
275         esp_crt_bundle_set(bundle);
276     }
277 
278     ESP_LOGI(TAG, "Connecting to %s:%s...", SERVER_ADDRESS, SERVER_PORT);
279     if ((ret = mbedtls_net_connect(&client.client_fd, SERVER_ADDRESS, SERVER_PORT, MBEDTLS_NET_PROTO_TCP)) != 0) {
280         ESP_LOGE(TAG, "mbedtls_net_connect returned -%x", -ret);
281         goto exit;
282     }
283 
284     ESP_LOGI(TAG, "Connected.");
285     mbedtls_ssl_set_bio(&client.ssl, &client.client_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
286 
287     ESP_LOGI(TAG, "Performing the SSL/TLS handshake with bundle that is missing the server root certificate");
288     while ( ( ret = mbedtls_ssl_handshake( &client.ssl ) ) != 0 ) {
289         if ( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) {
290             printf( "mbedtls_ssl_handshake failed with -0x%x\n", -ret );
291             break;
292         }
293     }
294 
295     ESP_LOGI(TAG, "Verifying peer X.509 certificate for bundle ...");
296     ret  = mbedtls_ssl_get_verify_result(&client.ssl);
297 
298     *res = (ret == 0) ? ESP_CRT_VALIDATE_OK : ESP_CRT_VALIDATE_FAIL;
299 
300 
301     // Reset session before new connection
302     mbedtls_ssl_close_notify(&client.ssl);
303     mbedtls_ssl_session_reset(&client.ssl);
304     mbedtls_net_free( &client.client_fd);
305 
306 
307 exit:
308     mbedtls_ssl_close_notify(&client.ssl);
309     mbedtls_ssl_session_reset(&client.ssl);
310     esp_crt_bundle_detach(&client.conf);
311     endpoint_teardown(&client);
312 
313     return ret;
314 }
315 
316 
317 TEST_CASE("custom certificate bundle", "[mbedtls]")
318 {
319    esp_crt_validate_res_t validate_res;
320 
321    test_case_uses_tcpip();
322 
323    xSemaphoreHandle signal_sem = xSemaphoreCreateBinary();
324    TEST_ASSERT_NOT_NULL(signal_sem);
325 
326    exit_flag = false;
327    xTaskCreate(server_task, "server task", 8192, &signal_sem, 10, NULL);
328 
329    // Wait for the server to start up
330    if (!xSemaphoreTake(signal_sem, 10000 / portTICK_PERIOD_MS)) {
331        TEST_FAIL_MESSAGE("signal_sem not released, server start failed");
332    }
333 
334    /* Test with default crt bundle that doesnt contain the ca crt */
335    client_task(NULL, &validate_res);
336    TEST_ASSERT(validate_res == ESP_CRT_VALIDATE_FAIL);
337 
338    /* Test with bundle that does contain the CA crt */
339    client_task(server_cert_bundle_start, &validate_res);
340    TEST_ASSERT(validate_res == ESP_CRT_VALIDATE_OK);
341 
342    exit_flag = true;
343 
344    if (!xSemaphoreTake(signal_sem, 10000 / portTICK_PERIOD_MS)) {
345        TEST_FAIL_MESSAGE("signal_sem not released, server exit failed");
346    }
347 
348    vSemaphoreDelete(signal_sem);
349 }
350 
351 #endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3)
352 
353 TEST_CASE("custom certificate bundle - weak hash", "[mbedtls]")
354 {
355     /* A weak signature hash on the trusted certificate should not stop
356        us from verifying the chain, since we already trust it a weak signature hash is
357        not a security issue */
358 
359     mbedtls_x509_crt crt;
360     uint32_t flags = 0;
361 
362     esp_crt_bundle_attach(NULL);
363 
364     mbedtls_x509_crt_init( &crt );
365     mbedtls_x509_crt_parse(&crt, bad_md_crt_pem_start, bad_md_crt_pem_end - bad_md_crt_pem_start);
366     TEST_ASSERT(mbedtls_x509_crt_verify(&crt, NULL, NULL, NULL, &flags, esp_crt_verify_callback, NULL) == 0);
367 
368     mbedtls_x509_crt_free(&crt);
369 
370     esp_crt_bundle_detach(NULL);
371 }
372 
373 TEST_CASE("custom certificate bundle - wrong signature", "[mbedtls]")
374 {
375     /* Check that the bundle will not verify a valid certificate from trusted root where the signature is wrong */
376 
377     mbedtls_x509_crt crt;
378     uint32_t flags = 0;
379 
380     esp_crt_bundle_attach(NULL);
381 
382     mbedtls_x509_crt_init( &crt );
383     /* esp32.com cert chain where 1 byte in the signature is changed */
384     printf("Testing certificate with wrong signature\n");
385     mbedtls_x509_crt_parse(&crt, wrong_sig_crt_pem_start, wrong_sig_crt_pem_end - wrong_sig_crt_pem_start);
386     TEST_ASSERT(mbedtls_x509_crt_verify(&crt, NULL, NULL, NULL, &flags, esp_crt_verify_callback, NULL) != 0);
387     mbedtls_x509_crt_free(&crt);
388 
389     mbedtls_x509_crt_init( &crt );
390     /* the correct esp32.com cert chain*/
391     printf("Testing certificate with correct signature\n");
392     mbedtls_x509_crt_parse(&crt, correct_sig_crt_pem_start, correct_sig_crt_pem_end - correct_sig_crt_pem_start);
393     TEST_ASSERT(mbedtls_x509_crt_verify(&crt, NULL, NULL, NULL, &flags, esp_crt_verify_callback, NULL) == 0);
394     mbedtls_x509_crt_free(&crt);
395 
396     esp_crt_bundle_detach(NULL);
397 }
398