From a3592cbe4fcf212a1657642839c9dac93cd63ba4 Mon Sep 17 00:00:00 2001 From: Andy Green Date: Sun, 17 Oct 2021 06:20:58 +0100 Subject: [PATCH] adns: api-test: add synthetic result parsing Add some exports so the api test can inject results into the parser for live queries, suppressing asking the server but otherwise following the flow. Provide two new suspect responses for injection and parsing in ctest. Add a --cos option to minimal-http-client to force a close after the connection has started the async dns. --- include/libwebsockets/lws-async-dns.h | 19 ++- lib/core-net/adopt.c | 2 +- lib/core-net/client/connect2.c | 2 +- lib/system/async-dns/async-dns-parse.c | 1 + lib/system/async-dns/async-dns.c | 40 ++++- lib/system/async-dns/private-lib-async-dns.h | 6 +- .../api-tests/api-test-async-dns/main.c | 151 +++++++++++++++++- .../minimal-http-client/minimal-http-client.c | 8 +- 8 files changed, 212 insertions(+), 17 deletions(-) diff --git a/include/libwebsockets/lws-async-dns.h b/include/libwebsockets/lws-async-dns.h index dc8b417da..ee021b74e 100644 --- a/include/libwebsockets/lws-async-dns.h +++ b/include/libwebsockets/lws-async-dns.h @@ -40,11 +40,17 @@ typedef enum { LADNS_RET_CONTINUING } lws_async_dns_retcode_t; +#define LWS_ADNS_SYNTHETIC 0x10000 /* don't send, synthetic response will + * be injected for testing */ + struct addrinfo; typedef struct lws * (*lws_async_dns_cb_t)(struct lws *wsi, const char *ads, const struct addrinfo *result, int n, void *opaque); +struct lws_adns_q; +struct lws_async_dns; + /** * lws_async_dns_query() - perform a dns lookup using async dns * @@ -54,6 +60,7 @@ typedef struct lws * (*lws_async_dns_cb_t)(struct lws *wsi, const char *ads, * \param qtype: type of query (A, AAAA etc) * \param cb: query completion callback * \param wsi: wsi if the query is related to one + * \param pq: NULL, or pointer to lws_adns_q query (used for testing) * * Starts an asynchronous DNS lookup, on completion the \p cb callback will * be called. @@ -68,7 +75,7 @@ typedef struct lws * (*lws_async_dns_cb_t)(struct lws *wsi, const char *ads, LWS_VISIBLE LWS_EXTERN lws_async_dns_retcode_t lws_async_dns_query(struct lws_context *context, int tsi, const char *name, adns_query_type_t qtype, lws_async_dns_cb_t cb, - struct lws *wsi, void *opaque); + struct lws *wsi, void *opaque, struct lws_adns_q **pq); /** * lws_async_dns_freeaddrinfo() - decrement refcount on cached addrinfo results @@ -83,4 +90,14 @@ lws_async_dns_query(struct lws_context *context, int tsi, const char *name, LWS_VISIBLE LWS_EXTERN void lws_async_dns_freeaddrinfo(const struct addrinfo **ai); +/* only needed for testing */ + +LWS_VISIBLE LWS_EXTERN uint16_t +lws_adns_get_tid(struct lws_adns_q *q); +LWS_VISIBLE LWS_EXTERN struct lws_async_dns * +lws_adns_get_async_dns(struct lws_adns_q *q); + +LWS_VISIBLE LWS_EXTERN void +lws_adns_parse_udp(struct lws_async_dns *dns, const uint8_t *pkt, size_t len); + #endif diff --git a/lib/core-net/adopt.c b/lib/core-net/adopt.c index 212adc4d9..fe305293e 100644 --- a/lib/core-net/adopt.c +++ b/lib/core-net/adopt.c @@ -878,7 +878,7 @@ lws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port, n = lws_async_dns_query(vhost->context, 0, ads, LWS_ADNS_RECORD_A, lws_create_adopt_udp2, wsi, - (void *)ifname); + (void *)ifname, NULL); // lwsl_notice("%s: dns query returned %d\n", __func__, n); if (n == LADNS_RET_FAILED) { lwsl_err("%s: async dns failed\n", __func__); diff --git a/lib/core-net/client/connect2.c b/lib/core-net/client/connect2.c index 0ccb3cb55..3712b4244 100644 --- a/lib/core-net/client/connect2.c +++ b/lib/core-net/client/connect2.c @@ -365,7 +365,7 @@ solo: else n = lws_async_dns_query(wsi->a.context, wsi->tsi, adsin, LWS_ADNS_RECORD_A, lws_client_connect_3_connect, - wsi, NULL); + wsi, NULL, NULL); if (n == LADNS_RET_FAILED_WSI_CLOSED) return NULL; diff --git a/lib/system/async-dns/async-dns-parse.c b/lib/system/async-dns/async-dns-parse.c index 31c7610be..985d2a0a5 100644 --- a/lib/system/async-dns/async-dns-parse.c +++ b/lib/system/async-dns/async-dns-parse.c @@ -405,6 +405,7 @@ skip: q->sent[1] = 0; #endif q->sent[0] = 0; + q->is_synthetic = 0; q->recursion++; if (q->recursion == DNS_RECURSION_LIMIT) { lwsl_err("%s: recursion overflow\n", __func__); diff --git a/lib/system/async-dns/async-dns.c b/lib/system/async-dns/async-dns.c index e722214f1..70a83b670 100644 --- a/lib/system/async-dns/async-dns.c +++ b/lib/system/async-dns/async-dns.c @@ -314,6 +314,7 @@ callback_async_dns(struct lws *wsi, enum lws_callback_reasons reason, list); if (//lws_dll2_is_detached(&q->sul.list) && + !q->is_synthetic && (!q->asked || q->responded != q->asked)) lws_async_dns_writeable(wsi, q); } lws_end_foreach_dll_safe(d, d1); @@ -563,6 +564,11 @@ lws_async_dns_deinit(lws_async_dns_t *dns) } } +void +lws_async_dns_detach_query_wsi(struct lws *wsi) +{ + +} static int cancel(struct lws_dll2 *d, void *user) @@ -574,6 +580,14 @@ cancel(struct lws_dll2 *d, void *user) struct lws *w = lws_container_of(d3, struct lws, adns); if (user == w) { + /* + * This is an ongoing query that our wsi was involved + * in... detach it from the query, and if nothing left + * interested in the query, destroy it. + * + * Since the wsi can only be running one query at a time + * currently, we can bail if we got a hit. + */ lws_dll2_remove(d3); if (!q->wsi_adns.count) lws_adns_q_destroy(q); @@ -584,6 +598,11 @@ cancel(struct lws_dll2 *d, void *user) return 0; } +/* + * Let's go through all ongoing async dns queries, detaching wsi from any it + * is involved in, and destroying the query if that was the only consumer. + */ + void lws_async_dns_cancel(struct lws *wsi) { @@ -639,6 +658,19 @@ lws_async_dns_get_new_tid(struct lws_context *context, lws_adns_q_t *q) return -1; } + +uint16_t +lws_adns_get_tid(struct lws_adns_q *q) +{ + return LADNS_MOST_RECENT_TID(q); +} + +struct lws_async_dns * +lws_adns_get_async_dns(struct lws_adns_q *q) +{ + return q->dns; +} + struct temp_q { lws_adns_q_t tq; char name[48]; @@ -647,7 +679,7 @@ struct temp_q { lws_async_dns_retcode_t lws_async_dns_query(struct lws_context *context, int tsi, const char *name, adns_query_type_t qtype, lws_async_dns_cb_t cb, - struct lws *wsi, void *opaque) + struct lws *wsi, void *opaque, struct lws_adns_q **pq) { lws_async_dns_t *dns = &context->async_dns; size_t nlen = strlen(name); @@ -845,6 +877,8 @@ lws_async_dns_query(struct lws_context *context, int tsi, const char *name, lws_dll2_add_head(&wsi->adns, &q->wsi_adns); q->qtype = (uint16_t)qtype; + if (qtype & LWS_ADNS_SYNTHETIC) + q->is_synthetic = 1; if (lws_async_dns_get_new_tid(context, q)) { lwsl_cx_err(context, "tid fail"); @@ -852,6 +886,10 @@ lws_async_dns_query(struct lws_context *context, int tsi, const char *name, } LADNS_MOST_RECENT_TID(q) &= 0xfffe; + + if (pq) + *pq = q; + q->context = context; q->tsi = (uint8_t)tsi; q->opaque = opaque; diff --git a/lib/system/async-dns/private-lib-async-dns.h b/lib/system/async-dns/private-lib-async-dns.h index f213448ab..30defce51 100644 --- a/lib/system/async-dns/private-lib-async-dns.h +++ b/lib/system/async-dns/private-lib-async-dns.h @@ -53,7 +53,7 @@ typedef struct lws_adns_cache { * these objects are used while a query is ongoing... */ -typedef struct { +typedef struct lws_adns_q { lws_sorted_usec_list_t sul; /* per-query write retry timer */ lws_sorted_usec_list_t write_sul; /* fail if unable to write by this time */ lws_dll2_t list; @@ -88,6 +88,7 @@ typedef struct { uint8_t go_nogo; uint8_t is_retry:1; + uint8_t is_synthetic:1; /* test will deliver canned */ /* name overallocated here */ } lws_adns_q_t; @@ -121,9 +122,6 @@ lws_async_dns_complete(lws_adns_q_t *q, lws_adns_cache_t *c); lws_adns_cache_t * lws_adns_get_cache(lws_async_dns_t *dns, const char *name); -void -lws_adns_parse_udp(lws_async_dns_t *dns, const uint8_t *pkt, size_t len); - lws_adns_q_t * lws_adns_get_query(lws_async_dns_t *dns, adns_query_type_t qtype, lws_dll2_owner_t *owner, uint16_t tid, const char *name); diff --git a/minimal-examples-lowlevel/api-tests/api-test-async-dns/main.c b/minimal-examples-lowlevel/api-tests/api-test-async-dns/main.c index 4af79d329..ff61e07f0 100644 --- a/minimal-examples-lowlevel/api-tests/api-test-async-dns/main.c +++ b/minimal-examples-lowlevel/api-tests/api-test-async-dns/main.c @@ -12,7 +12,7 @@ #include #include -static int interrupted, dtest, ok, fail, _exp = 26; +static int interrupted, dtest, ok, fail, _exp = 33; struct lws_context *context; /* @@ -67,12 +67,17 @@ static const struct ipparser_tests { { "1.2.3.4", 4, "1.2.3.4", 7, { 1, 2, 3, 4 } }, }; +#define TEST_FLAG_NOCHECK_RESULT_IP 0x100000 + static const struct async_dns_tests { const char *dns_name; int recordtype; int addrlen; uint8_t ads[16]; } adt[] = { + { "warmcat.com", LWS_ADNS_RECORD_A, 4, + { 46, 105, 127, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } }, + /* test coming from cache */ { "warmcat.com", LWS_ADNS_RECORD_A, 4, { 46, 105, 127, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } }, { "libwebsockets.org", LWS_ADNS_RECORD_A, 4, @@ -93,17 +98,97 @@ static const struct async_dns_tests { { 0x20, 0x01, 0x41, 0xd0, 0x00, 0x02, 0xee, 0x93, 0, 0, 0, 0, 0, 0, 0, 1, } }, #endif + { "c.msn.com", TEST_FLAG_NOCHECK_RESULT_IP | + LWS_ADNS_SYNTHETIC | LWS_ADNS_RECORD_A, 4, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } }, + { "assets.msn.com", TEST_FLAG_NOCHECK_RESULT_IP | + LWS_ADNS_SYNTHETIC | LWS_ADNS_RECORD_A, 4, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } }, + { "e28578.d.akamaiedge.net", TEST_FLAG_NOCHECK_RESULT_IP | + LWS_ADNS_SYNTHETIC | LWS_ADNS_RECORD_A, 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } }, + { "a-0003.a-msedge.net", TEST_FLAG_NOCHECK_RESULT_IP | + LWS_ADNS_SYNTHETIC | LWS_ADNS_RECORD_A, 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } }, + { "c-msn-com-europe-vip.trafficmanager.net", TEST_FLAG_NOCHECK_RESULT_IP | + LWS_ADNS_SYNTHETIC | LWS_ADNS_RECORD_A, 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } }, + { "c-msn-com-europe-vip.trafficmanager.net", TEST_FLAG_NOCHECK_RESULT_IP | + LWS_ADNS_SYNTHETIC | LWS_ADNS_RECORD_A, 0, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } }, }; -static lws_sorted_usec_list_t sul; +static uint8_t canned_c_msn_com[] = { + 0x12, 0x34, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, + 0x00, 0x01, 0x00, 0x00, 0x01, 0x63, 0x03, 0x6D, + 0x73, 0x6E, 0x03, 0x63, 0x6F, 0x6D, 0x00, 0x00, + 0x1C, 0x00, 0x01, 0xC0, 0x0C, 0x00, 0x05, 0x00, + 0x01, 0x00, 0x00, 0x54, 0x5E, 0x00, 0x24, 0x0F, + 0x63, 0x2D, 0x6D, 0x73, 0x6E, 0x2D, 0x63, 0x6F, + 0x6D, 0x2D, 0x6E, 0x73, 0x61, 0x74, 0x63, 0x0E, + 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x6D, + 0x61, 0x6E, 0x61, 0x67, 0x65, 0x72, 0x03, 0x6E, + 0x65, 0x74, 0x00, 0xC0, 0x27, 0x00, 0x05, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x17, 0x14, + 0x63, 0x2D, 0x6D, 0x73, 0x6E, 0x2D, 0x63, 0x6F, + 0x6D, 0x2D, 0x65, 0x75, 0x72, 0x6F, 0x70, 0x65, + 0x2D, 0x76, 0x69, 0x70, 0xC0, 0x37, 0xC0, 0x37, + 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1C, + 0x00, 0x2E, 0x03, 0x74, 0x6D, 0x31, 0x06, 0x64, + 0x6E, 0x73, 0x2D, 0x74, 0x6D, 0xC0, 0x12, 0x0A, + 0x68, 0x6F, 0x73, 0x74, 0x6D, 0x61, 0x73, 0x74, + 0x65, 0x72, 0xC0, 0x37, 0x77, 0x64, 0x96, 0x60, + 0x00, 0x00, 0x03, 0x84, 0x00, 0x00, 0x01, 0x2C, + 0x00, 0x24, 0xEA, 0x00, 0x00, 0x00, 0x00, 0x1E, +}, canned_assets_msn_com[] = { + 219,29,129,128,0,1,0,2,0,1,0,0,6,97,115,115,101,116,115,3,109,115, + 110,3,99,111,109,0,0,28,0,1,192,12,0,5,0,1,0,0,81,199,0,28,6,97,115, + 115,101,116,115,3,109,115,110,3,99,111,109,7,101,100,103,101,107,101, + 121,3,110,101,116,0,192,44,0,5,0,1,0,0,0,235,0,22,6,101,50,56,53,55, + 56,1,100,10,97,107,97,109,97,105,101,100,103,101,192,67,192,91,0,6, + 0,1,0,0,1,79,0,46,3,110,48,100,192,93,10,104,111,115,116,109,97,115, + 116,101,114,6,97,107,97,109,97,105,192,23,97,106,246,231,0,0,3,232,0, + 0,3,232,0,0,3,232,0,0,7,8, +}, canned_e28578_d_akamaiedge_net[] = { + 20,191,129,128,0,1,0,0,0,1,0,0,6,101,50,56,53,55,56,1,100,10,97,107,97, + 109,97,105,101,100,103,101,3,110,101,116,0,0,28,0,1,192,19,0,6,0,1,0,0, + 1,17,0,49,3,110,48,100,192,21,10,104,111,115,116,109,97,115,116,101,114, + 6,97,107,97,109,97,105,3,99,111,109,0,97,107,217,31,0,0,3,232,0,0,3,232, + 0,0,3,232,0,0,7,8 +}, canned_a_0003_a_msedge_net[] = { + 126,215,129,128,0,1,0,0,0,1,0,0,6,97,45,48,48,48,51,8,97,45,109,115,101, + 100,103,101,3,110,101,116,0,0,28,0,1,192,19,0,6,0,1,0,0,0,172,0,48,3, + 110,115,49,192,19,6,109,115,110,104,115,116,9,109,105,99,114,111,115, + 111,102,116,3,99,111,109,0,120,43,34,229,0,0,7,8,0,0,3,132,0,36,234,0, + 0,0,0,240 +}, canned_c_msn_com_europe_vip_trafficmanager_net[] = { + 73,87,129,128,0,1,0,0,0,1,0,0,20,99,45,109,115,110,45,99,111,109,45,101, + 117,114,111,112,101,45,118,105,112,14,116,114,97,102,102,105,99,109,97, + 110,97,103,101,114,3,110,101,116,0,0,28,0,1,192,33,0,6,0,1,0,0,0,30,0, + 49,3,116,109,49,6,100,110,115,45,116,109,3,99,111,109,0,10,104,111,115, + 116,109,97,115,116,101,114,192,33,7,11,234,133,0,0,3,132,0,0,1,44,0,36, + 234,0,0,0,0,30, +}; + +static lws_sorted_usec_list_t sul, sul_timeout; struct lws * cb1(struct lws *wsi_unused, const char *ads, const struct addrinfo *a, int n, void *opaque); +static int first = 1; + +static void +timeout_cb(lws_sorted_usec_list_t *sul) +{ + interrupted = 1; + lws_cancel_service(context); +} + static void next_test_cb(lws_sorted_usec_list_t *sul) { + struct lws_adns_q *q; int m; lwsl_notice("%s: querying %s\n", __func__, adt[dtest].dns_name); @@ -111,11 +196,58 @@ next_test_cb(lws_sorted_usec_list_t *sul) m = lws_async_dns_query(context, 0, adt[dtest].dns_name, (adns_query_type_t)adt[dtest].recordtype, cb1, NULL, - context); + context, &q); if (m != LADNS_RET_CONTINUING && m != LADNS_RET_FOUND && m != LADNS_RET_FAILED_WSI_CLOSED) { lwsl_err("%s: adns 1: %s failed: %d\n", __func__, adt[dtest].dns_name, m); interrupted = 1; } + + if (adt[dtest].recordtype & LWS_ADNS_SYNTHETIC) { + + lwsl_notice("%s: injecting result\n", __func__); + + if (!strcmp(adt[dtest].dns_name, "c.msn.com")) { + canned_c_msn_com[0] = (uint8_t)(lws_adns_get_tid(q) >> 8); + canned_c_msn_com[1] = (uint8_t)lws_adns_get_tid(q); + lws_adns_parse_udp(lws_adns_get_async_dns(q), + canned_c_msn_com, + sizeof(canned_c_msn_com)); + } + + if (!strcmp(adt[dtest].dns_name, "assets.msn.com")) { + canned_assets_msn_com[0] = (uint8_t)(lws_adns_get_tid(q) >> 8); + canned_assets_msn_com[1] = (uint8_t)lws_adns_get_tid(q); + lws_adns_parse_udp(lws_adns_get_async_dns(q), + canned_assets_msn_com, + sizeof(canned_assets_msn_com)); + } + + if (!strcmp(adt[dtest].dns_name, "e28578.d.akamaiedge.net")) { + canned_e28578_d_akamaiedge_net[0] = (uint8_t)(lws_adns_get_tid(q) >> 8); + canned_e28578_d_akamaiedge_net[1] = (uint8_t)lws_adns_get_tid(q); + lws_adns_parse_udp(lws_adns_get_async_dns(q), + canned_e28578_d_akamaiedge_net, + sizeof(canned_e28578_d_akamaiedge_net)); + } + if (!strcmp(adt[dtest].dns_name, "a-0003.a-msedge.net")) { + canned_a_0003_a_msedge_net[0] = (uint8_t)(lws_adns_get_tid(q) >> 8); + canned_a_0003_a_msedge_net[1] = (uint8_t)lws_adns_get_tid(q); + lws_adns_parse_udp(lws_adns_get_async_dns(q), + canned_a_0003_a_msedge_net, + sizeof(canned_a_0003_a_msedge_net)); + } + if (first && + !strcmp(adt[dtest].dns_name, "c-msn-com-europe-vip.trafficmanager.net")) { + first = 0; + canned_c_msn_com_europe_vip_trafficmanager_net[0] = + (uint8_t)(lws_adns_get_tid(q) >> 8); + canned_c_msn_com_europe_vip_trafficmanager_net[1] = + (uint8_t)lws_adns_get_tid(q); + lws_adns_parse_udp(lws_adns_get_async_dns(q), + canned_c_msn_com_europe_vip_trafficmanager_net, + sizeof(canned_c_msn_com_europe_vip_trafficmanager_net)); + } + } } struct lws * @@ -167,8 +299,9 @@ cb1(struct lws *wsi_unused, const char *ads, const struct addrinfo *a, int n, goto again; #endif } - if (alen == adt[dtest - 1].addrlen && - !memcmp(adt[dtest - 1].ads, addr, (unsigned int)alen)) { + if ((adt[dtest - 1].recordtype & TEST_FLAG_NOCHECK_RESULT_IP) || + (alen == adt[dtest - 1].addrlen && + !memcmp(adt[dtest - 1].ads, addr, (unsigned int)alen))) { ok++; goto next; } @@ -190,9 +323,10 @@ again: next: lws_async_dns_freeaddrinfo(&a); - if (dtest == (int)LWS_ARRAY_SIZE(adt)) + if (dtest == (int)LWS_ARRAY_SIZE(adt)) { interrupted = 1; - else + lws_cancel_service(context); + } else lws_sul_schedule(context, 0, &sul, next_test_cb, 1); return NULL; @@ -225,7 +359,7 @@ sul_retry_l(struct lws_sorted_usec_list *sul) m = lws_async_dns_query(context, 0, "warmcat.com", (adns_query_type_t)LWS_ADNS_RECORD_A, - cb_loop, NULL, context); + cb_loop, NULL, context, NULL); switch (m) { case LADNS_RET_FAILED_WSI_CLOSED: lwsl_warn("%s: LADNS_RET_FAILED_WSI_CLOSED " @@ -352,6 +486,7 @@ main(int argc, const char **argv) /* kick off the async dns tests */ lws_sul_schedule(context, 0, &sul, next_test_cb, 1); + lws_sul_schedule(context, 0, &sul_timeout, timeout_cb, 45 * LWS_USEC_PER_SEC); evloop: /* the usual lws event loop */ diff --git a/minimal-examples-lowlevel/http-client/minimal-http-client/minimal-http-client.c b/minimal-examples-lowlevel/http-client/minimal-http-client/minimal-http-client.c index f151356f3..ac9aa32fb 100644 --- a/minimal-examples-lowlevel/http-client/minimal-http-client/minimal-http-client.c +++ b/minimal-examples-lowlevel/http-client/minimal-http-client/minimal-http-client.c @@ -16,7 +16,7 @@ #include #include -static int interrupted, bad = 1, status, conmon; +static int interrupted, bad = 1, status, conmon, close_after_start; #if defined(LWS_WITH_HTTP2) static int long_poll; #endif @@ -332,6 +332,9 @@ system_notify_cb(lws_state_manager_t *mgr, lws_state_notify_link_t *link, return 1; } + if (close_after_start) + lws_wsi_close(client_wsi, LWS_TO_KILL_SYNC); + return 0; } @@ -380,6 +383,9 @@ int main(int argc, const char **argv) */ info.fd_limit_per_thread = 1 + 1 + 1; + if (lws_cmdline_option(argc, argv, "--cos")) + close_after_start = 1; + #if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL) /* * OpenSSL uses the system trust store. mbedTLS has to be told which