Morse Micro IoT SDK  2.10.4
sslclient.c
Go to the documentation of this file.
1/*
2 * Copyright 2023 Morse Micro
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
153#include <string.h>
154#include "mmosal.h"
155#include "mmwlan.h"
156#include "mmconfig.h"
157#include "mmipal.h"
158#include "mbedtls/build_info.h"
159#include "mbedtls/platform.h"
160#include "mbedtls/net.h"
161#include "mbedtls/ssl.h"
162#include "mbedtls/entropy.h"
163#include "mbedtls/ctr_drbg.h"
164#include "mbedtls/debug.h"
165#include "mm_app_common.h"
166#include "default_certs.h"
167
169#define DEFAULT_PORT "443"
171#define DEFAULT_SERVER "www.google.com"
173#define GET_REQUEST "GET / HTTP/1.0\r\n\r\n"
174
176char buf[1408];
177
187void my_debug(void *ctx, int level, const char *file, int line, const char *str)
188{
189 ((void)level);
190 ((void)ctx);
191
192 printf("%s:%04d: %s", file, line, str);
193}
194
199void app_init(void)
200{
201 uint8_t *allocptr = NULL;
202
203 printf("\n\nMorse SSL Client Demo (Built " __DATE__ " " __TIME__ ")\n\n");
204
205 /* Initialize and connect to Wi-Fi, blocks till connected */
208
209 int ret = 0;
210 int len = 0;
211 size_t total = 0;
212 mbedtls_net_context server_fd;
213 const char *pers = "sslclient";
214
215 mbedtls_entropy_context entropy;
216 mbedtls_ctr_drbg_context ctr_drbg;
217 mbedtls_ssl_context ssl;
218 mbedtls_ssl_config conf;
219 mbedtls_x509_crt cacert;
220 mbedtls_x509_crt clicert;
221 mbedtls_pk_context pkey;
222
223 /*
224 * 0. Initialize and setup mbedtls
225 */
226 printf("Initialising MbedTLS...");
227 mbedtls_net_init(&server_fd);
228 mbedtls_ssl_init(&ssl);
229 mbedtls_ssl_config_init(&conf);
230
231 /* Uncomment the following lines to enable verbose debugging */
232 // mbedtls_ssl_conf_dbg(&conf, my_debug, NULL);
233 // mbedtls_debug_set_threshold(4);
234
235 mbedtls_x509_crt_init(&cacert);
236 mbedtls_x509_crt_init(&clicert);
237 mbedtls_pk_init(&pkey);
238 mbedtls_ctr_drbg_init(&ctr_drbg);
239 mbedtls_entropy_init(&entropy);
240
241 ret = mbedtls_ctr_drbg_seed(&ctr_drbg,
242 mbedtls_entropy_func,
243 &entropy,
244 (const unsigned char *)pers,
245 strlen(pers));
246 if (ret != 0)
247 {
248 printf(" failed %d in mbedtls_ctr_drbg_seed()\n\n", ret);
249 goto exit;
250 }
251 printf(" ok\n");
252
253 /*
254 * 1. Load & setup certificates
255 */
256 allocptr = (uint8_t *)DEFAULT_ROOT_CERT;
257 len = mmconfig_read_bytes("sslclient.rootca", NULL, 0, 0);
258 if (len > 0)
259 {
260 /* Looks like we have a valid certificate */
261 allocptr = (uint8_t *)mmosal_malloc(len + 1);
262 if (allocptr)
263 {
264 /* Now read the bytes in */
265 mmconfig_read_bytes("sslclient.rootca", allocptr, len, 0);
266 /* Add NULL terminator as MbedTLS expects this, we already allocated +1 bytes */
267 allocptr[len++] = 0;
268 }
269 else
270 {
271 printf("Failed to allocate memory for root certificate!\n\n");
272 goto exit;
273 }
274 }
275 else
276 {
277 len = sizeof(DEFAULT_ROOT_CERT);
278 }
279 printf("Loading the CA root certificate ...");
280 ret = mbedtls_x509_crt_parse(&cacert, allocptr, len);
281 if (ret < 0)
282 {
283 printf(" failed %d\n\n", ret);
284 goto exit;
285 }
286 printf(" ok\n");
287
288 allocptr = (uint8_t *)DEFAULT_CLIENT_CERT;
289 len = mmconfig_read_bytes("sslclient.clientcert", NULL, 0, 0);
290 if (len > 0)
291 {
292 /* Looks like we have a valid certificate */
293 allocptr = (uint8_t *)mmosal_malloc(len + 1);
294 if (allocptr)
295 {
296 /* Now read the bytes in */
297 mmconfig_read_bytes("sslclient.clientcert", allocptr, len, 0);
298 /* Add NULL terminator as MbedTLS expects this, we already allocated +1 bytes */
299 allocptr[len++] = 0;
300 }
301 else
302 {
303 printf("Failed to allocate memory for client certificate!\n\n");
304 goto exit;
305 }
306 }
307 else
308 {
309 len = sizeof(DEFAULT_CLIENT_CERT);
310 }
311 printf("Loading the client cert...");
312 ret = mbedtls_x509_crt_parse(&clicert, allocptr, len);
313 if (ret != 0)
314 {
315 printf(" failed %d\n\n", ret);
316 goto exit;
317 }
318 printf(" ok\n");
319
320 allocptr = (uint8_t *)DEFAULT_CLIENT_KEY;
321 len = mmconfig_read_bytes("sslclient.clientkey", NULL, 0, 0);
322 if (len > 0)
323 {
324 /* Looks like we have a valid certificate */
325 allocptr = (uint8_t *)mmosal_malloc(len + 1);
326 if (allocptr)
327 {
328 /* Now read the bytes in */
329 mmconfig_read_bytes("sslclient.clientkey", allocptr, len, 0);
330 /* Add NULL terminator as MbedTLS expects this, we already allocated +1 bytes */
331 allocptr[len++] = 0;
332 }
333 else
334 {
335 printf("Failed to allocate memory for client key!\n\n");
336 goto exit;
337 }
338 }
339 else
340 {
341 len = sizeof(DEFAULT_CLIENT_KEY);
342 }
343 printf("Loading the client key...");
344 ret = mbedtls_pk_parse_key(&pkey, allocptr, len, NULL, 0, mbedtls_ctr_drbg_random, &ctr_drbg);
345 if (ret != 0)
346 {
347 printf(" failed %d\n\n", ret);
348 goto exit;
349 }
350 printf(" ok\n");
351
352 printf("Setting up client certs/key...");
353 if ((ret = mbedtls_ssl_conf_own_cert(&conf, &clicert, &pkey)) != 0)
354 {
355 printf(" failed %d\n\n", ret);
356 goto exit;
357 }
358 printf(" ok\n");
359
360 /*
361 * 2. Setup SSL
362 */
363 printf("Setting up SSL...");
364 ret = mbedtls_ssl_config_defaults(&conf,
365 MBEDTLS_SSL_IS_CLIENT,
366 MBEDTLS_SSL_TRANSPORT_STREAM,
367 MBEDTLS_SSL_PRESET_DEFAULT);
368 if (ret != 0)
369 {
370 printf(" failed %d in mbedtls_ssl_config_defaults()\n\n", ret);
371 goto exit;
372 }
373 mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
374 mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
375 mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
376 ret = mbedtls_ssl_setup(&ssl, &conf);
377 if (ret != 0)
378 {
379 printf(" failed %d in mbedtls_ssl_setup()\n\n", ret);
380 goto exit;
381 }
382
383 static char sslclient_server[64];
384 strncpy(sslclient_server, DEFAULT_SERVER, sizeof(sslclient_server));
385 (void)mmconfig_read_string("sslclient.server", sslclient_server, sizeof(sslclient_server));
386 if ((ret = mbedtls_ssl_set_hostname(&ssl, sslclient_server)) != 0)
387 {
388 printf(" failed %d\n\n", ret);
389 goto exit;
390 }
391 printf(" ok\n");
392
393 /*
394 * 3. Start the connection
395 */
396 /* First parse the URL to extract the server, port and resource */
397 static char sslclient_port[8];
398 strncpy(sslclient_port, DEFAULT_PORT, sizeof(sslclient_port));
399 (void)mmconfig_read_string("sslclient.port", sslclient_port, sizeof(sslclient_port));
400
401 printf("Connecting to %s:%s...", sslclient_server, sslclient_port);
402 fflush(stdout);
403 ret = mbedtls_net_connect(&server_fd, sslclient_server, sslclient_port, MBEDTLS_NET_PROTO_TCP);
404 if (ret != 0)
405 {
406 printf(" failed %d\n\n", ret);
407 goto exit;
408 }
409 printf(" ok\n");
410
411 mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, NULL, mbedtls_net_recv_timeout);
412
413 /*
414 * 4. Handshake
415 */
416 printf("Performing the SSL/TLS handshake...");
417 ret = mbedtls_ssl_handshake(&ssl);
418 if (ret != 0)
419 {
420 printf(" failed %d\n\n", ret);
421 goto exit;
422 }
423 printf(" ok\n");
424
425 /*
426 * 5. Verify the server certificate
427 */
428 printf("Verifying peer X.509 certificate...");
429 ret = mbedtls_ssl_get_verify_result(&ssl);
430 if (ret != 0)
431 {
432 /* In real life, we probably want to bail out when ret != 0 */
433 printf(" failed %d, did you set the time?\n\n", ret);
434 }
435 else
436 {
437 printf(" ok\n");
438 }
439
440 /*
441 * 6. Write the GET request
442 */
443 printf("Write to server:");
444 ret = mbedtls_ssl_write(&ssl, (const unsigned char *)GET_REQUEST, sizeof(GET_REQUEST) - 1);
445 if (ret <= 0)
446 {
447 // mbedtls_ssl_write failed
448 printf(" failed %d\n\n", ret);
449 goto exit;
450 }
451 printf(" %d bytes written\n\n%s", ret, GET_REQUEST);
452
453 /*
454 * 7. Read the HTTP response
455 */
456 printf("Reading response from server:\n");
457 memset(buf, 0, sizeof(buf));
458 ret = mbedtls_ssl_read(&ssl, (unsigned char *)buf, sizeof(buf) - 1);
459
460 if (ret > 0)
461 {
462 total = ret;
463 printf("Printing headers only:\n\n");
464
465 /* Search for blank line signifying end of headers */
466 char *end_headers = strstr(buf, "\n\n");
467 if (end_headers)
468 {
469 /* terminate the string at end of headers */
470 *end_headers = 0;
471 }
472 end_headers = strstr(buf, "\r\n\r\n");
473 if (end_headers)
474 {
475 /* terminate the string at end of headers */
476 *end_headers = 0;
477 }
478
479 /* Print headers */
480 puts(buf);
481
482 /* Read the rest */
483 while (1)
484 {
485 ret = mbedtls_ssl_read(&ssl, (unsigned char *)buf, sizeof(buf));
486
487 if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE)
488 {
489 continue;
490 }
491
492 if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
493 {
494 break;
495 }
496
497 if (ret < 0)
498 {
499 printf(" failed with error code %d\n\n", ret);
500 break;
501 }
502
503 if (ret == 0)
504 {
505 /* No more data to read */
506 break;
507 }
508
509 total += ret;
510 }
511 }
512
513 if (total > 0)
514 {
515 printf("\nSuccess! %u bytes read in total.\n", total);
516 }
517 else
518 {
519 printf("\nFailed to read response from server!\n");
520 }
521
522 /*
523 * 8. Close the connection
524 */
525 mbedtls_ssl_close_notify(&ssl);
526
527exit:
528 mbedtls_net_free(&server_fd);
529
530 mbedtls_ssl_free(&ssl);
531 mbedtls_ssl_config_free(&conf);
532 mbedtls_ctr_drbg_free(&ctr_drbg);
533 mbedtls_entropy_free(&entropy);
534}
int mmconfig_read_string(const char *key, char *buffer, int bufsize)
Returns the persistent store string value identified by the key.
int mmconfig_read_bytes(const char *key, void *buffer, uint32_t buffsize, uint32_t offset)
Returns the persistent store data identified by the key.
#define mmosal_malloc(size)
Allocate memory of the given size and return a pointer to it (malloc).
Definition: mmosal.h:138
Morse Micro application helper routines for initializing/de-initializing the Wireless LAN interface a...
void app_wlan_init(void)
Initializes the WLAN interface (and dependencies) using settings specified in the config store.
void app_wlan_start(void)
Starts the WLAN interface and connects to Wi-Fi using settings specified in the config store.
#define DEFAULT_PORT
HTTPS port number to connect to.
Definition: sslclient.c:169
void my_debug(void *ctx, int level, const char *file, int line, const char *str)
Optional mbedtls debug callback handler.
Definition: sslclient.c:187
#define DEFAULT_SERVER
HTTPS server to connect to.
Definition: sslclient.c:171
#define GET_REQUEST
HTTPS get request string.
Definition: sslclient.c:173
char buf[1408]
Statically allocated buffer for HTTP GET request, just under 1 packet size.
Definition: sslclient.c:176
void app_init(void)
Main entry point to the application.
Definition: sslclient.c:199