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