cwist
Modern C web framework with libttak runtime
Loading...
Searching...
No Matches
backend_mbedtls.c
Go to the documentation of this file.
1
28#include <openssl/ssl.h>
29#include <openssl/err.h>
30#include <openssl/evp.h>
31#include <openssl/hmac.h>
32#include <openssl/rand.h>
33#include <openssl/crypto.h>
34
36
37#include <mbedtls/ssl.h>
38#include <mbedtls/ssl_cache.h>
39#include <mbedtls/ssl_ticket.h>
40#include <mbedtls/net_sockets.h>
41#include <mbedtls/entropy.h>
42#include <mbedtls/ctr_drbg.h>
43#include <mbedtls/error.h>
44#include <mbedtls/md.h>
45#include <mbedtls/cipher.h>
46#include <mbedtls/x509_crt.h>
47#include <mbedtls/pk.h>
48#include <mbedtls/platform.h>
49#include <mbedtls/ssl_ciphersuites.h>
50
51#include <stdatomic.h>
52#include <stdint.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56#include <pthread.h>
57#include <unistd.h>
58
59/* --- Error "queue" -------------------------------------------------------- */
60
61static _Thread_local unsigned long cwist_mtls_last_err;
62
63/* Record an mbedTLS error code (negative) for ERR_get_error(). */
64static void cwist_mtls_set_err(int ret) {
65 cwist_mtls_last_err = (unsigned long)(unsigned int)(-ret);
66}
67
68unsigned long cwist_mtls_ERR_get_error(void) {
69 unsigned long e = cwist_mtls_last_err;
70 cwist_mtls_last_err = 0;
71 return e;
72}
73
74void cwist_mtls_ERR_error_string_n(unsigned long e, char *buf, size_t len) {
75 if (!buf || len == 0) return;
76 if (e == 0) {
77 snprintf(buf, len, "no error");
78 return;
79 }
80 mbedtls_strerror(-(int)e, buf, len);
81}
82
84 cwist_mtls_last_err = 0;
85}
86
87/* --- RNG (fork-aware CTR-DRBG) --------------------------------------------- */
88
89static mbedtls_entropy_context cwist_mtls_entropy;
90static mbedtls_ctr_drbg_context cwist_mtls_drbg;
91static pthread_mutex_t cwist_mtls_rng_lock = PTHREAD_MUTEX_INITIALIZER;
92static pid_t cwist_mtls_rng_pid;
93static int cwist_mtls_rng_ready;
94
95/* Seed (or, after fork, re-seed) the global DRBG. Caller holds the lock. */
96static int cwist_mtls_rng_init_locked(void) {
97 pid_t pid = getpid();
98 if (cwist_mtls_rng_ready && cwist_mtls_rng_pid == pid) return 0;
99
100 if (cwist_mtls_rng_ready) {
101 /* Forked worker: the inherited DRBG state would produce streams
102 * identical to the parent's, so reseed before generating anything. */
103 int ret = mbedtls_ctr_drbg_reseed(&cwist_mtls_drbg, NULL, 0);
104 if (ret != 0) {
105 cwist_mtls_set_err(ret);
106 return -1;
107 }
108 cwist_mtls_rng_pid = pid;
109 return 0;
110 }
111
112 mbedtls_entropy_init(&cwist_mtls_entropy);
113 mbedtls_ctr_drbg_init(&cwist_mtls_drbg);
114 int ret =
115 mbedtls_ctr_drbg_seed(&cwist_mtls_drbg, mbedtls_entropy_func, &cwist_mtls_entropy, NULL, 0);
116 if (ret != 0) {
117 cwist_mtls_set_err(ret);
118 mbedtls_ctr_drbg_free(&cwist_mtls_drbg);
119 mbedtls_entropy_free(&cwist_mtls_entropy);
120 return -1;
121 }
122 cwist_mtls_rng_ready = 1;
123 cwist_mtls_rng_pid = pid;
124 return 0;
125}
126
127int cwist_mtls_RAND_bytes(unsigned char *buf, int num) {
128 if (!buf || num < 0) return 0;
129 pthread_mutex_lock(&cwist_mtls_rng_lock);
130 int ok = cwist_mtls_rng_init_locked() == 0 &&
131 mbedtls_ctr_drbg_random(&cwist_mtls_drbg, buf, (size_t)num) == 0;
132 pthread_mutex_unlock(&cwist_mtls_rng_lock);
133 return ok ? 1 : 0;
134}
135
136/* f_rng callback for mbedtls_ssl_conf_rng / ticket setup. */
137static int cwist_mtls_rng_cb(void *p_rng, unsigned char *buf, size_t len) {
138 (void)p_rng;
139 if (len > (size_t)INT32_MAX) return -1;
140 return cwist_mtls_RAND_bytes(buf, (int)len) == 1 ? 0 : -1;
141}
142
143/* --- Secure memory helpers -------------------------------------------------- */
144
145void cwist_mtls_OPENSSL_cleanse(void *ptr, size_t len) {
146 mbedtls_platform_zeroize(ptr, len);
147}
148
149int cwist_mtls_CRYPTO_memcmp(const void *a, const void *b, size_t len) {
150 const volatile unsigned char *pa = (const volatile unsigned char *)a;
151 const volatile unsigned char *pb = (const volatile unsigned char *)b;
152 unsigned char diff = 0;
153 for (size_t i = 0; i < len; i++) diff |= pa[i] ^ pb[i];
154 return diff;
155}
156
157/* --- Digests / HMAC ---------------------------------------------------------- */
158
159struct cwist_mtls_evp_md {
161};
162
163static const struct cwist_mtls_evp_md cwist_mtls_md_sha256 = {MBEDTLS_MD_SHA256};
164
166 return &cwist_mtls_md_sha256;
167}
168
169unsigned char *cwist_mtls_HMAC(const EVP_MD *md, const void *key, int key_len,
170 const unsigned char *msg, size_t msg_len, unsigned char *out,
171 unsigned int *out_len) {
172 if (!md || !out) return NULL;
174 if (!info) return NULL;
175 int ret = mbedtls_md_hmac(info, (const unsigned char *)key, (size_t)key_len, msg, msg_len, out);
176 if (ret != 0) {
177 cwist_mtls_set_err(ret);
178 return NULL;
179 }
180 if (out_len) *out_len = mbedtls_md_get_size(info);
181 return out;
182}
183
184struct cwist_mtls_hmac_ctx {
186 int started;
187};
188
190 HMAC_CTX *ctx = (HMAC_CTX *)cwist_malloc(sizeof(*ctx));
191 if (ctx) memset(ctx, 0, sizeof(*ctx));
192 if (ctx) mbedtls_md_init(&ctx->md);
193 return ctx;
194}
195
197 if (!ctx) return;
198 mbedtls_md_free(&ctx->md);
199 cwist_free(ctx);
200}
201
202int cwist_mtls_HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md,
203 void *engine) {
204 (void)engine;
205 if (!ctx || !md) return 0;
206 mbedtls_md_free(&ctx->md);
207 mbedtls_md_init(&ctx->md);
208 ctx->started = 0;
210 if (!info) return 0;
211 if (mbedtls_md_setup(&ctx->md, info, 1) != 0) return 0;
212 if (mbedtls_md_hmac_starts(&ctx->md, (const unsigned char *)key, (size_t)key_len) != 0) {
213 return 0;
214 }
215 ctx->started = 1;
216 return 1;
217}
218
219int cwist_mtls_HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, size_t len) {
220 if (!ctx || !ctx->started) return 0;
221 return mbedtls_md_hmac_update(&ctx->md, data, len) == 0 ? 1 : 0;
222}
223
224int cwist_mtls_HMAC_Final(HMAC_CTX *ctx, unsigned char *out, unsigned int *out_len) {
225 if (!ctx || !ctx->started || !out) return 0;
226 if (mbedtls_md_hmac_finish(&ctx->md, out) != 0) return 0;
227 if (out_len) *out_len = mbedtls_md_get_size(mbedtls_md_info_from_ctx(&ctx->md));
228 ctx->started = 0;
229 return 1;
230}
231
232/* --- AES-256-CBC (EVP subset) ------------------------------------------------ */
233
234struct cwist_mtls_cipher {
236};
237
238static const struct cwist_mtls_cipher cwist_mtls_cipher_aes_256_cbc = {MBEDTLS_CIPHER_AES_256_CBC};
239
241 return &cwist_mtls_cipher_aes_256_cbc;
242}
243
244struct cwist_mtls_cipher_ctx {
246};
247
249 EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)cwist_malloc(sizeof(*ctx));
250 if (ctx) memset(ctx, 0, sizeof(*ctx));
251 if (ctx) mbedtls_cipher_init(&ctx->cipher);
252 return ctx;
253}
254
256 if (!ctx) return;
257 mbedtls_cipher_free(&ctx->cipher);
258 cwist_free(ctx);
259}
260
261static int cwist_mtls_cipher_init(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type,
262 const unsigned char *key, const unsigned char *iv,
264 if (!ctx || !type || !key || !iv) return 0;
265 mbedtls_cipher_free(&ctx->cipher);
266 mbedtls_cipher_init(&ctx->cipher);
268 if (!info) return 0;
269 /* PKCS#7 padding, matching the EVP default. */
270 if (mbedtls_cipher_setup(&ctx->cipher, info) != 0 ||
271 mbedtls_cipher_setkey(&ctx->cipher, key, 256, op) != 0 ||
273 mbedtls_cipher_set_iv(&ctx->cipher, iv, 16) != 0 ||
274 mbedtls_cipher_reset(&ctx->cipher) != 0) {
275 return 0;
276 }
277 return 1;
278}
279
280int cwist_mtls_EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, void *engine,
281 const unsigned char *key, const unsigned char *iv) {
282 (void)engine;
283 return cwist_mtls_cipher_init(ctx, type, key, iv, MBEDTLS_ENCRYPT);
284}
285
286int cwist_mtls_EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, void *engine,
287 const unsigned char *key, const unsigned char *iv) {
288 (void)engine;
289 return cwist_mtls_cipher_init(ctx, type, key, iv, MBEDTLS_DECRYPT);
290}
291
292int cwist_mtls_EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
293 const unsigned char *in, int inl) {
294 size_t olen = 0;
295 if (!ctx || !outl || inl < 0) return 0;
296 if (mbedtls_cipher_update(&ctx->cipher, in, (size_t)inl, out, &olen) != 0) return 0;
297 *outl = (int)olen;
298 return 1;
299}
300
301int cwist_mtls_EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl) {
302 size_t olen = 0;
303 if (!ctx || !outl) return 0;
304 if (mbedtls_cipher_finish(&ctx->cipher, out, &olen) != 0) return 0;
305 *outl = (int)olen;
306 return 1;
307}
308
309int cwist_mtls_EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
310 const unsigned char *in, int inl) {
311 return cwist_mtls_EVP_EncryptUpdate(ctx, out, outl, in, inl);
312}
313
314int cwist_mtls_EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl) {
315 return cwist_mtls_EVP_EncryptFinal_ex(ctx, out, outl);
316}
317
318/* --- ALPN ------------------------------------------------------------------- */
319
320int cwist_mtls_SSL_select_next_proto(unsigned char **out, unsigned char *outlen,
321 const unsigned char *server, unsigned int server_len,
322 const unsigned char *client, unsigned int client_len) {
323 /* Server-preference scan, same contract as OpenSSL. */
324 for (unsigned int i = 0; i < server_len;) {
325 unsigned int slen = server[i++];
326 if (i + slen > server_len) break;
327 for (unsigned int j = 0; j < client_len;) {
328 unsigned int clen = client[j++];
329 if (j + clen > client_len) return 0;
330 if (clen == slen && memcmp(server + i, client + j, slen) == 0) {
331 *out = (unsigned char *)(server + i);
332 *outlen = (unsigned char)slen;
334 }
335 j += clen;
336 }
337 i += slen;
338 }
339 return 0;
340}
341
342/* --- SSL_CTX ----------------------------------------------------------------- */
343
344struct cwist_mtls_method {
345 int is_server;
346};
347
348static const struct cwist_mtls_method cwist_mtls_server_method = {1};
349static const struct cwist_mtls_method cwist_mtls_client_method = {0};
350
352 return &cwist_mtls_server_method;
353}
354
356 return &cwist_mtls_client_method;
357}
358
359#define CWIST_MTLS_EX_DATA_MAX 8
360
361struct cwist_mtls_ctx {
363 mbedtls_x509_crt cert; /* own certificate chain (server) */
364 mbedtls_pk_context pkey; /* own private key (server) */
365 mbedtls_x509_crt ca_chain; /* trust store (client) */
367 mbedtls_ssl_ticket_context *ticket; /* armed on SSL_CTX_set_tlsext_ticket_key_cb */
368 int is_server;
369 int cert_loaded;
370 int key_loaded;
371 unsigned long options;
372 int min_version; /* MBEDTLS_SSL_VERSION_* or 0 */
373 long sess_cache_max; /* 0 = leave the mbedTLS default */
374 long timeout_sec; /* session/ticket lifetime, 0 = default */
375 /* ALPN: static list installed on the conf. Storage lives here because
376 * mbedtls_ssl_conf_alpn_protocols() does not copy the list. */
377 const char *alpn_list[3];
378 char alpn_names[2][16]; /* name storage for the client-side list */
379 int alpn_count;
380 /* Ciphersuites: OpenSSL-style names split by TLS version, merged on
381 * apply (mbedtls_ssl_conf_ciphersuites takes one unified list). */
382 int cs12[16];
383 size_t cs12_count;
384 int cs13[8];
385 size_t cs13_count;
386 int cs_applied[32];
387 void *ex_data[CWIST_MTLS_EX_DATA_MAX];
388 _Atomic int refs;
389};
390
391/* ex_data indexes, allocated lazily exactly like SSL_CTX_get_ex_new_index. */
392static _Atomic int cwist_mtls_ex_data_next;
393
395 if (!method) return NULL;
396 SSL_CTX *ctx = (SSL_CTX *)cwist_malloc(sizeof(*ctx));
397 if (ctx) memset(ctx, 0, sizeof(*ctx));
398 if (!ctx) return NULL;
399
400 ctx->is_server = method->is_server;
401 mbedtls_ssl_config_init(&ctx->conf);
402 mbedtls_x509_crt_init(&ctx->cert);
403 mbedtls_pk_init(&ctx->pkey);
404 mbedtls_x509_crt_init(&ctx->ca_chain);
405 mbedtls_ssl_cache_init(&ctx->cache);
406
408 &ctx->conf, ctx->is_server ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT,
410 mbedtls_ssl_cache_free(&ctx->cache);
411 mbedtls_x509_crt_free(&ctx->ca_chain);
412 mbedtls_pk_free(&ctx->pkey);
413 mbedtls_x509_crt_free(&ctx->cert);
414 mbedtls_ssl_config_free(&ctx->conf);
415 cwist_free(ctx);
416 return NULL;
417 }
418
419 mbedtls_ssl_conf_rng(&ctx->conf, cwist_mtls_rng_cb, NULL);
420 /* CWIST does not do client-certificate authentication. */
422 if (ctx->is_server) {
425#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
426 /* mbedTLS writes the TLS 1.3 NewSessionTicket after handshake
427 * wrap-up (a trailing write BoringSSL folds into its second flight).
428 * A client that closes right after its Finished - routine for the
429 * short-lived probes in the CWIST test suite - resets the socket and
430 * that trailing write then fails the whole handshake with
431 * ECONNRESET. Suppress server-side NST: TLS 1.3 ticket resumption
432 * is off, TLS 1.2 session-ID resumption via the server cache above
433 * keeps working. */
435#endif
436 }
437 atomic_init(&ctx->refs, 1);
438 return ctx;
439}
440
441/* Drop the last reference: free the mbedTLS contexts the conf points at. */
442static void cwist_mtls_ctx_destroy(SSL_CTX *ctx) {
443 mbedtls_ssl_config_free(&ctx->conf);
444 mbedtls_x509_crt_free(&ctx->cert);
445 mbedtls_pk_free(&ctx->pkey);
446 mbedtls_x509_crt_free(&ctx->ca_chain);
447 mbedtls_ssl_cache_free(&ctx->cache);
448 if (ctx->ticket) {
449 mbedtls_ssl_ticket_free(ctx->ticket);
450 cwist_free(ctx->ticket);
451 }
452 cwist_free(ctx);
453}
454
456 if (!ctx) return;
457 if (atomic_fetch_sub_explicit(&ctx->refs, 1, memory_order_acq_rel) == 1) {
458 cwist_mtls_ctx_destroy(ctx);
459 }
460}
461
463 if (!ctx) return 0;
464 if (version == TLS1_2_VERSION) {
465 ctx->min_version = MBEDTLS_SSL_VERSION_TLS1_2;
466 } else if (version == TLS1_3_VERSION) {
467 ctx->min_version = MBEDTLS_SSL_VERSION_TLS1_3;
468 } else {
469 return 0;
470 }
472 return 1;
473}
474
475long cwist_mtls_SSL_CTX_set_options(SSL_CTX *ctx, unsigned long options) {
476 if (!ctx) return 0;
477 ctx->options |= options;
478 if (options & SSL_OP_NO_TICKET) {
480 }
481 if (options & SSL_OP_NO_TLSv1_2 && ctx->min_version < MBEDTLS_SSL_VERSION_TLS1_3) {
482 ctx->min_version = MBEDTLS_SSL_VERSION_TLS1_3;
484 }
485 /* NO_COMPRESSION / NO_RENEGOTIATION / CIPHER_SERVER_PREFERENCE match the
486 * mbedTLS defaults (no compression support, renegotiation disabled,
487 * server-order ciphersuite pick), so they need no action. */
488 return (long)ctx->options;
489}
490
492 (void)mode; /* AUTO_RETRY is the only mode mbedTLS has. */
493 (void)ctx;
494 return SSL_MODE_AUTO_RETRY;
495}
496
497/* OpenSSL cipher name -> mbedTLS ciphersuite IANA id, for the fixed profile
498 * https.c applies. Unknown names are skipped by the caller. */
499static int cwist_mtls_cipher_id(const char *name, size_t len, int *is_tls13) {
500 struct entry {
501 const char *name;
502 int id;
503 int tls13;
504 };
505 static const struct entry table[] = {
506 {"ECDHE-ECDSA-AES128-GCM-SHA256", MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0},
507 {"ECDHE-RSA-AES128-GCM-SHA256", MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0},
508 {"ECDHE-ECDSA-AES256-GCM-SHA384", MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 0},
509 {"ECDHE-RSA-AES256-GCM-SHA384", MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 0},
510 {"ECDHE-ECDSA-CHACHA20-POLY1305", MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 0},
511 {"ECDHE-RSA-CHACHA20-POLY1305", MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 0},
512 {"TLS_AES_128_GCM_SHA256", MBEDTLS_TLS1_3_AES_128_GCM_SHA256, 1},
513 {"TLS_AES_256_GCM_SHA384", MBEDTLS_TLS1_3_AES_256_GCM_SHA384, 1},
514 {"TLS_CHACHA20_POLY1305_SHA256", MBEDTLS_TLS1_3_CHACHA20_POLY1305_SHA256, 1},
515 };
516 for (size_t i = 0; i < sizeof(table) / sizeof(table[0]); i++) {
517 if (strlen(table[i].name) == len && memcmp(table[i].name, name, len) == 0) {
518 *is_tls13 = table[i].tls13;
519 return table[i].id;
520 }
521 }
522 return -1;
523}
524
525/* Rebuild and install the unified ciphersuite list (TLS 1.3 first, then the
526 * TLS 1.2 picks, matching the server-preference order https.c requests). */
527static int cwist_mtls_apply_ciphersuites(SSL_CTX *ctx) {
528 size_t n = 0;
529 for (size_t i = 0; i < ctx->cs13_count && n < 30; i++) ctx->cs_applied[n++] = ctx->cs13[i];
530 for (size_t i = 0; i < ctx->cs12_count && n < 30; i++) ctx->cs_applied[n++] = ctx->cs12[i];
531 if (n == 0) return 0;
532 ctx->cs_applied[n] = 0;
533 mbedtls_ssl_conf_ciphersuites(&ctx->conf, ctx->cs_applied);
534 return 1;
535}
536
537static int cwist_mtls_set_cipher_list(SSL_CTX *ctx, const char *list, int want_tls13) {
538 if (!ctx || !list) return 0;
539 size_t recognized = 0;
540 const char *p = list;
541 while (*p) {
542 const char *colon = strchr(p, ':');
543 size_t len = colon ? (size_t)(colon - p) : strlen(p);
544 int is_tls13 = 0;
545 int id = cwist_mtls_cipher_id(p, len, &is_tls13);
546 if (id >= 0) {
547 if (is_tls13 && ctx->cs13_count < 8) {
548 ctx->cs13[ctx->cs13_count++] = id;
549 recognized++;
550 } else if (!is_tls13 && ctx->cs12_count < 16) {
551 ctx->cs12[ctx->cs12_count++] = id;
552 recognized++;
553 }
554 }
555 /* Unmapped names are ignored: OpenSSL would accept any name it
556 * knows, we only carry the ones CWIST's profiles use. */
557 if (!colon) break;
558 p = colon + 1;
559 }
560 if (recognized == 0) return 0; /* mirror OpenSSL's all-unknown failure */
561 return want_tls13 ? 1 : cwist_mtls_apply_ciphersuites(ctx);
562}
563
565 return cwist_mtls_set_cipher_list(ctx, list, 0);
566}
567
569 return cwist_mtls_set_cipher_list(ctx, list, 1) ? cwist_mtls_apply_ciphersuites(ctx) : 0;
570}
571
572/* Install cert+key on the conf once both are loaded. */
573static int cwist_mtls_maybe_conf_own_cert(SSL_CTX *ctx) {
574 if (!ctx->cert_loaded || !ctx->key_loaded) return 1;
575 int ret = mbedtls_ssl_conf_own_cert(&ctx->conf, &ctx->cert, &ctx->pkey);
576 if (ret != 0) {
577 cwist_mtls_set_err(ret);
578 return 0;
579 }
580 return 1;
581}
582
584 if (!ctx || !path) return 0;
585 mbedtls_x509_crt_free(&ctx->cert);
586 mbedtls_x509_crt_init(&ctx->cert);
587 int ret = mbedtls_x509_crt_parse_file(&ctx->cert, path);
588 if (ret != 0) {
589 cwist_mtls_set_err(ret);
590 return 0;
591 }
592 ctx->cert_loaded = 1;
593 return cwist_mtls_maybe_conf_own_cert(ctx);
594}
595
596int cwist_mtls_SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *path, int type) {
597 if (!ctx || !path || type != SSL_FILETYPE_PEM) return 0;
598 mbedtls_pk_free(&ctx->pkey);
599 mbedtls_pk_init(&ctx->pkey);
600 int ret = mbedtls_pk_parse_keyfile(&ctx->pkey, path, NULL, cwist_mtls_rng_cb, NULL);
601 if (ret != 0) {
602 cwist_mtls_set_err(ret);
603 return 0;
604 }
605 ctx->key_loaded = 1;
606 return cwist_mtls_maybe_conf_own_cert(ctx);
607}
608
609int cwist_mtls_SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *path, int type) {
610 (void)type; /* PEM only, same restriction as use_PrivateKey_file */
612}
613
615 if (!ctx || ctx->min_version == 0) return 0;
616 return ctx->min_version == MBEDTLS_SSL_VERSION_TLS1_3 ? TLS1_3_VERSION : TLS1_2_VERSION;
617}
618
620 if (!ctx || !ctx->cert_loaded || !ctx->key_loaded) return 0;
621 return mbedtls_pk_check_pair(&ctx->cert.pk, &ctx->pkey, cwist_mtls_rng_cb, NULL) == 0 ? 1 : 0;
622}
623
625 (void)ctx;
626 (void)mode; /* the server cache is always configured (see SSL_CTX_new) */
628}
629
630long cwist_mtls_SSL_CTX_sess_set_cache_size(SSL_CTX *ctx, unsigned long size) {
631 if (!ctx) return 0;
632 ctx->sess_cache_max = (long)size;
633 if (size > 0) mbedtls_ssl_cache_set_max_entries(&ctx->cache, (int)size);
634 return ctx->sess_cache_max;
635}
636
638 unsigned int sid_ctx_len) {
639 /* mbedTLS needs no session-id context to resume from its server cache. */
640 (void)ctx;
641 (void)sid_ctx;
643 return 1;
644}
645
647 if (!ctx) return 0;
648 ctx->timeout_sec = seconds;
649 mbedtls_ssl_cache_set_timeout(&ctx->cache, (int)seconds);
650 return seconds;
651}
652
654 int (*cb)(SSL *ssl, const unsigned char **out,
655 unsigned char *outlen, const unsigned char *in,
656 unsigned int inlen, void *arg),
657 void *arg) {
658 if (!ctx || !cb) return;
659
660 /* mbedTLS has no server ALPN callback; it picks the first conf-list
661 * protocol the client offered. CWIST's callback (https.c) is a pure
662 * function of the context's HTTP/2 flag, which is final by the time the
663 * callback is installed (init options / reload), so evaluate it once
664 * here against a synthetic offer of every TCP-TLS protocol CWIST
665 * supports and install the implied server-preference list statically.
666 * ssl is NULL: CWIST's callback never dereferences it. */
667 static const unsigned char offer[] = "\x02h2\x08http/1.1";
668 static char proto_h2[] = "h2";
669 static char proto_http11[] = "http/1.1";
670 const unsigned char *sel = NULL;
671 unsigned char sel_len = 0;
672 if (cb(NULL, &sel, &sel_len, offer, (unsigned int)sizeof(offer) - 1, arg) !=
674 !sel || sel_len == 0) {
675 return; /* NOACK: no ALPN configured, exactly the OpenSSL outcome */
676 }
677
678 int n = 0;
679 if (sel_len == 2 && memcmp(sel, "h2", 2) == 0) {
680 ctx->alpn_list[n++] = proto_h2;
681 ctx->alpn_list[n++] = proto_http11;
682 } else if (sel_len == 8 && memcmp(sel, "http/1.1", 8) == 0) {
683 ctx->alpn_list[n++] = proto_http11;
684 } else {
685 return; /* unknown protocol: leave ALPN off rather than guess */
686 }
687 ctx->alpn_list[n] = NULL;
688 ctx->alpn_count = n;
689 mbedtls_ssl_conf_alpn_protocols(&ctx->conf, ctx->alpn_list);
690}
691
692int cwist_mtls_SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char *protos,
693 unsigned int protos_len) {
694 /* Client side: parse the wire-format list into a NUL-terminated string
695 * array stored on the ctx (mbedTLS does not copy the list). */
696 if (!ctx || (!protos && protos_len > 0)) return -1;
697 ctx->alpn_count = 0;
698 ctx->alpn_list[0] = NULL;
699 if (protos_len == 0) {
701 return 0;
702 }
703
704 unsigned int i = 0;
705 int n = 0;
706 while (i < protos_len) {
707 unsigned int len = protos[i++];
708 if (i + len > protos_len || len == 0 || len >= sizeof(ctx->alpn_names[0]) || n >= 2) {
709 return -1;
710 }
711 memcpy(ctx->alpn_names[n], protos + i, len);
712 ctx->alpn_names[n][len] = '\0';
713 ctx->alpn_list[n] = ctx->alpn_names[n];
714 n++;
715 i += len;
716 }
717 ctx->alpn_list[n] = NULL;
718 ctx->alpn_count = n;
719 if (mbedtls_ssl_conf_alpn_protocols(&ctx->conf, ctx->alpn_list) != 0) {
720 return -1;
721 }
722 return 0;
723}
724
725/* Mirrors cwist_tls_ticket_key in src/net/http/https.c: the shared session
726 * ticket key https.c generates pre-fork and stores as SSL_CTX ex_data. */
727struct cwist_mtls_ticket_key {
728 unsigned char name[16];
729 unsigned char aes_key[32];
730 unsigned char hmac_key[32];
731};
732
734 int (*cb)(SSL *ssl, unsigned char *key_name,
735 unsigned char *iv, EVP_CIPHER_CTX *ectx,
736 HMAC_CTX *hctx, int enc)) {
737 (void)cb; /* the mbedTLS ticket module replaces the callback mechanism */
738 if (!ctx || !ctx->is_server) return;
739 if (ctx->options & SSL_OP_NO_TICKET) {
741 return;
742 }
743
744 /* The shared key is always installed as ex_data before this call (both
745 * the init and the reload path in https.c). Using it - rather than the
746 * random key mbedtls_ssl_ticket_setup() would mint - keeps tickets
747 * resumable across certificate hot reloads; all forked workers inherit
748 * the same material because the parent builds the context pre-fork. */
749 const struct cwist_mtls_ticket_key *key = NULL;
750 for (int i = 0; i < CWIST_MTLS_EX_DATA_MAX; i++) {
751 if (ctx->ex_data[i]) {
752 key = (const struct cwist_mtls_ticket_key *)ctx->ex_data[i];
753 break;
754 }
755 }
756 if (!key) return; /* no shared key: leave tickets unconfigured */
757
759 if (t) memset(t, 0, sizeof(*t));
760 if (!t) return;
762 uint32_t lifetime = ctx->timeout_sec > 0 ? (uint32_t)ctx->timeout_sec : 300;
763 int ret =
765 if (ret != 0) {
766 cwist_mtls_set_err(ret);
768 cwist_free(t);
769 return;
770 }
771
772 /* Re-key slot 0 deterministically: same key name and AES-256-GCM key on
773 * every worker and every reload, so a ticket issued anywhere decrypts
774 * everywhere (mirrors the BoringSSL STEK callback). */
775 mbedtls_cipher_free(&t->MBEDTLS_PRIVATE(keys)[0].MBEDTLS_PRIVATE(ctx));
776 mbedtls_cipher_init(&t->MBEDTLS_PRIVATE(keys)[0].MBEDTLS_PRIVATE(ctx));
777 ret = mbedtls_cipher_setup(&t->MBEDTLS_PRIVATE(keys)[0].MBEDTLS_PRIVATE(ctx),
779 if (ret == 0) {
780 ret = mbedtls_cipher_setkey(&t->MBEDTLS_PRIVATE(keys)[0].MBEDTLS_PRIVATE(ctx), key->aes_key,
781 256, MBEDTLS_ENCRYPT);
782 }
783 if (ret != 0) {
784 cwist_mtls_set_err(ret);
786 cwist_free(t);
787 return;
788 }
789 memcpy(t->MBEDTLS_PRIVATE(keys)[0].MBEDTLS_PRIVATE(name), key->name,
791 t->MBEDTLS_PRIVATE(keys)[0].MBEDTLS_PRIVATE(lifetime) = lifetime;
792 t->MBEDTLS_PRIVATE(active) = 0;
793
796 if (ctx->ticket) {
797 mbedtls_ssl_ticket_free(ctx->ticket);
798 cwist_free(ctx->ticket);
799 }
800 ctx->ticket = t;
801}
802
804 void *free_func) {
805 (void)argl;
806 (void)argp;
807 (void)new_func;
808 (void)dup_func;
810 int idx = atomic_fetch_add_explicit(&cwist_mtls_ex_data_next, 1, memory_order_relaxed);
811 return idx < CWIST_MTLS_EX_DATA_MAX ? idx : -1;
812}
813
814int cwist_mtls_SSL_CTX_set_ex_data(SSL_CTX *ctx, int idx, void *data) {
815 if (!ctx || idx < 0 || idx >= CWIST_MTLS_EX_DATA_MAX) return 0;
816 ctx->ex_data[idx] = data;
817 return 1;
818}
819
821 if (!ctx || idx < 0 || idx >= CWIST_MTLS_EX_DATA_MAX) return NULL;
822 return ctx->ex_data[idx];
823}
824
825void cwist_mtls_SSL_CTX_set_verify(SSL_CTX *ctx, int mode, void *callback) {
826 (void)callback;
827 if (!ctx) return;
830}
831
833 if (!ctx) return 0;
834 int loaded = 0;
835 const char *file = getenv("SSL_CERT_FILE");
836 if (!file || !*file) file = "/etc/ssl/certs/ca-certificates.crt";
837 if (mbedtls_x509_crt_parse_file(&ctx->ca_chain, file) >= 0) loaded = 1;
838 const char *dir = getenv("SSL_CERT_DIR");
839 if (!dir || !*dir) dir = "/etc/ssl/certs";
840 if (mbedtls_x509_crt_parse_path(&ctx->ca_chain, dir) >= 0) loaded = 1;
841 mbedtls_ssl_conf_ca_chain(&ctx->conf, &ctx->ca_chain, NULL);
842 (void)loaded; /* an empty trust store fails at verify time, not here */
843 return 1;
844}
845
847 /* Named-group configuration is not surfaced: mbedTLS 3.6 negotiates its
848 * compiled-in curves (x25519, secp256r1, ...), which covers everything
849 * CWIST's default list asks for except the BoringSSL-only hybrid PQC
850 * groups (handled in pqc_layer.c). */
851 (void)ctx;
852 (void)groups;
853 return 1;
854}
855
856/* --- SSL (per-connection) ---------------------------------------------------- */
857
858struct cwist_mtls_ssl {
860 /* Shallow copy of the ctx's config, taken at SSL_new: lets per-connection
861 * tweaks (client-side SSL_set_alpn_protos) work and insulates the
862 * connection from later conf mutations. All pointers in it refer to
863 * ctx-owned objects kept alive by the reference below. */
865 const char *alpn_list[3];
866 char alpn_names[2][16];
868 SSL_CTX *ctx; /* reference held for the connection's lifetime */
869 int last_err; /* SSL_ERROR_* from the last failing operation */
870 int fd;
871};
872
874 if (!ctx) return NULL;
875 SSL *s = (SSL *)cwist_malloc(sizeof(*s));
876 if (s) memset(s, 0, sizeof(*s));
877 if (!s) return NULL;
878 mbedtls_ssl_init(&s->ssl);
879 mbedtls_net_init(&s->net);
880 s->conf = ctx->conf;
881 if (mbedtls_ssl_setup(&s->ssl, &s->conf) != 0) {
882 mbedtls_net_free(&s->net);
883 mbedtls_ssl_free(&s->ssl);
884 cwist_free(s);
885 return NULL;
886 }
888 s->ctx = ctx;
889 s->last_err = SSL_ERROR_NONE;
890 s->fd = -1;
891 return s;
892}
893
895 if (!ssl) return;
896 SSL_CTX *ctx = ssl->ctx;
897 mbedtls_ssl_free(&ssl->ssl);
898 mbedtls_net_free(&ssl->net);
899 cwist_free(ssl);
900 if (ctx) cwist_mtls_SSL_CTX_free(ctx);
901}
902
903int cwist_mtls_SSL_set_fd(SSL *ssl, int fd) {
904 if (!ssl) return 0;
905 ssl->fd = fd;
906 ssl->net.fd = fd;
907 /* Non-blocking sockets surface as WANT_READ/WANT_WRITE through
908 * net_sockets' EAGAIN mapping, matching BoringSSL semantics. */
910 return 1;
911}
912
913/* Map one mbedtls_ssl_* return code to the OpenSSL (ret, SSL_get_error)
914 * convention: 1 on success, 0 on clean close, -1 otherwise. */
915static int cwist_mtls_map_result(SSL *ssl, int ret, int ok_value) {
916 if (ret == ok_value) {
917 ssl->last_err = SSL_ERROR_NONE;
918 return 1;
919 }
920 switch (ret) {
921 case MBEDTLS_ERR_SSL_WANT_READ: ssl->last_err = SSL_ERROR_WANT_READ; return -1;
922 case MBEDTLS_ERR_SSL_WANT_WRITE: ssl->last_err = SSL_ERROR_WANT_WRITE; return -1;
923 case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: ssl->last_err = SSL_ERROR_ZERO_RETURN; return 0;
924 default:
925 cwist_mtls_set_err(ret);
926 ssl->last_err = SSL_ERROR_SSL;
927 return -1;
928 }
929}
930
931static int cwist_mtls_handshake(SSL *ssl) {
932 return cwist_mtls_map_result(ssl, mbedtls_ssl_handshake(&ssl->ssl), 0);
933}
934
936 if (!ssl) return -1;
937 return cwist_mtls_handshake(ssl);
938}
939
941 if (!ssl) return -1;
942 return cwist_mtls_handshake(ssl);
943}
944
945int cwist_mtls_SSL_read(SSL *ssl, void *buf, int num) {
946 if (!ssl || !buf || num <= 0) return -1;
947 int ret;
948 do {
949 ret = mbedtls_ssl_read(&ssl->ssl, (unsigned char *)buf, (size_t)num);
950 /* TLS 1.3 post-handshake NewSessionTicket: consumed internally,
951 * retry the read instead of surfacing it (OpenSSL does the same). */
953 if (ret > 0) {
954 ssl->last_err = SSL_ERROR_NONE;
955 return ret;
956 }
958 ssl->last_err = SSL_ERROR_ZERO_RETURN;
959 return 0;
960 }
962 ssl->last_err = SSL_ERROR_WANT_READ;
963 return -1;
964 }
966 ssl->last_err = SSL_ERROR_WANT_WRITE;
967 return -1;
968 }
969 cwist_mtls_set_err(ret);
970 ssl->last_err = SSL_ERROR_SSL;
971 return -1;
972}
973
974int cwist_mtls_SSL_write(SSL *ssl, const void *buf, int num) {
975 if (!ssl || !buf || num < 0) return -1;
976 int ret = mbedtls_ssl_write(&ssl->ssl, (const unsigned char *)buf, (size_t)num);
977 if (ret > 0) {
978 ssl->last_err = SSL_ERROR_NONE;
979 return ret;
980 }
982 ssl->last_err = SSL_ERROR_WANT_READ;
983 return -1;
984 }
986 ssl->last_err = SSL_ERROR_WANT_WRITE;
987 return -1;
988 }
989 cwist_mtls_set_err(ret);
990 ssl->last_err = SSL_ERROR_SSL;
991 return -1;
992}
993
995 if (!ssl) return 0;
996 return (int)mbedtls_ssl_get_bytes_avail(&ssl->ssl);
997}
998
1000 if (!ssl) return 0;
1001 /* Best-effort close_notify, like the OpenSSL unidirectional shutdown. */
1002 (void)mbedtls_ssl_close_notify(&ssl->ssl);
1003 return 1;
1004}
1005
1006int cwist_mtls_SSL_get_error(const SSL *ssl, int ret) {
1007 (void)ret;
1008 if (!ssl) return SSL_ERROR_SSL;
1009 return ssl->last_err;
1010}
1011
1013 return ssl ? ssl->ctx : NULL;
1014}
1015
1017 /* mbedTLS exposes no public per-connection resumption flag; the
1018 * resumed-handshake counter stays 0 on this backend. */
1019 (void)ssl;
1020 return 0;
1021}
1022
1024 if (!ssl) return 0;
1025 const char *v = mbedtls_ssl_get_version(&ssl->ssl);
1026 if (v && strcmp(v, "TLSv1.3") == 0) return TLS1_3_VERSION;
1027 if (v && strcmp(v, "TLSv1.2") == 0) return TLS1_2_VERSION;
1028 return 0;
1029}
1030
1031const char *cwist_mtls_SSL_get_cipher_name(const SSL *ssl) {
1032 if (!ssl) return NULL;
1033 int id = mbedtls_ssl_get_ciphersuite_id_from_ssl(&ssl->ssl);
1034 /* Report OpenSSL-style names so the observability buckets in https.c
1035 * classify the same way as on the BoringSSL backend. */
1036 switch (id) {
1037 case MBEDTLS_TLS1_3_AES_128_GCM_SHA256: return "TLS_AES_128_GCM_SHA256";
1038 case MBEDTLS_TLS1_3_AES_256_GCM_SHA384: return "TLS_AES_256_GCM_SHA384";
1039 case MBEDTLS_TLS1_3_CHACHA20_POLY1305_SHA256: return "TLS_CHACHA20_POLY1305_SHA256";
1041 return "ECDHE-ECDSA-AES128-GCM-SHA256";
1042 case MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: return "ECDHE-RSA-AES128-GCM-SHA256";
1044 return "ECDHE-ECDSA-AES256-GCM-SHA384";
1045 case MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: return "ECDHE-RSA-AES256-GCM-SHA384";
1047 return "ECDHE-ECDSA-CHACHA20-POLY1305";
1049 return "ECDHE-RSA-CHACHA20-POLY1305";
1050 default: return mbedtls_ssl_get_ciphersuite(&ssl->ssl);
1051 }
1052}
1053
1054void cwist_mtls_SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data,
1055 unsigned int *len) {
1056 const char *p = ssl ? mbedtls_ssl_get_alpn_protocol(&ssl->ssl) : NULL;
1057 *data = (const unsigned char *)p;
1058 *len = p ? (unsigned int)strlen(p) : 0;
1059}
1060
1061int cwist_mtls_SSL_set_tlsext_host_name(SSL *ssl, const char *name) {
1062 if (!ssl || !name) return 0;
1063 return mbedtls_ssl_set_hostname(&ssl->ssl, name) == 0 ? 1 : 0;
1064}
1065
1066int cwist_mtls_SSL_set_alpn_protos(SSL *ssl, const unsigned char *protos, unsigned int protos_len) {
1067 /* Client-side per-connection ALPN (OpenSSL returns 0 on success). */
1068 if (!ssl || (!protos && protos_len > 0)) return -1;
1069 if (protos_len == 0) {
1071 return 0;
1072 }
1073 unsigned int i = 0;
1074 int n = 0;
1075 while (i < protos_len) {
1076 unsigned int len = protos[i++];
1077 if (i + len > protos_len || len == 0 || len >= sizeof(ssl->alpn_names[0]) || n >= 2) {
1078 return -1;
1079 }
1080 memcpy(ssl->alpn_names[n], protos + i, len);
1081 ssl->alpn_names[n][len] = '\0';
1082 ssl->alpn_list[n] = ssl->alpn_names[n];
1083 n++;
1084 i += len;
1085 }
1086 ssl->alpn_list[n] = NULL;
1087 return mbedtls_ssl_conf_alpn_protocols(&ssl->conf, ssl->alpn_list) == 0 ? 0 : -1;
1088}
Memory allocation wrappers backed by libttak.
void cwist_free(void *ptr)
Free memory obtained via cwist_alloc/cwist_strdup/etc.
Definition alloc.c:52
void * cwist_malloc(size_t size)
Allocate zeroed memory via the CWIST owner context.
Definition alloc.c:13
const SSL_METHOD * cwist_mtls_TLS_client_method(void)
int cwist_mtls_SSL_read(SSL *ssl, void *buf, int num)
void cwist_mtls_SSL_free(SSL *ssl)
int cwist_mtls_EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl)
int cwist_mtls_SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *path, int type)
int cwist_mtls_EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, void *engine, const unsigned char *key, const unsigned char *iv)
void cwist_mtls_SSL_CTX_set_tlsext_ticket_key_cb(SSL_CTX *ctx, int(*cb)(SSL *ssl, unsigned char *key_name, unsigned char *iv, EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx, int enc))
int cwist_mtls_SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *path)
void cwist_mtls_SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data, unsigned int *len)
int cwist_mtls_SSL_select_next_proto(unsigned char **out, unsigned char *outlen, const unsigned char *server, unsigned int server_len, const unsigned char *client, unsigned int client_len)
int cwist_mtls_SSL_CTX_check_private_key(const SSL_CTX *ctx)
void cwist_mtls_HMAC_CTX_free(HMAC_CTX *ctx)
int cwist_mtls_SSL_CTX_get_min_proto_version(const SSL_CTX *ctx)
int cwist_mtls_SSL_CTX_set_ciphersuites(SSL_CTX *ctx, const char *list)
void cwist_mtls_SSL_CTX_set_verify(SSL_CTX *ctx, int mode, void *callback)
#define CWIST_MTLS_EX_DATA_MAX
int cwist_mtls_SSL_set_fd(SSL *ssl, int fd)
int cwist_mtls_SSL_CTX_set_ex_data(SSL_CTX *ctx, int idx, void *data)
void cwist_mtls_OPENSSL_cleanse(void *ptr, size_t len)
int cwist_mtls_SSL_write(SSL *ssl, const void *buf, int num)
long cwist_mtls_SSL_CTX_set_mode(SSL_CTX *ctx, long mode)
HMAC_CTX * cwist_mtls_HMAC_CTX_new(void)
int cwist_mtls_SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *list)
int cwist_mtls_SSL_set_tlsext_host_name(SSL *ssl, const char *name)
const SSL_METHOD * cwist_mtls_TLS_server_method(void)
int cwist_mtls_SSL_CTX_set1_groups_list(SSL_CTX *ctx, const char *groups)
void cwist_mtls_EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx)
SSL_CTX * cwist_mtls_SSL_get_SSL_CTX(const SSL *ssl)
const char * cwist_mtls_SSL_get_cipher_name(const SSL *ssl)
unsigned char * cwist_mtls_HMAC(const EVP_MD *md, const void *key, int key_len, const unsigned char *msg, size_t msg_len, unsigned char *out, unsigned int *out_len)
void * cwist_mtls_SSL_CTX_get_ex_data(const SSL_CTX *ctx, int idx)
int cwist_mtls_SSL_CTX_set_min_proto_version(SSL_CTX *ctx, uint16_t version)
int cwist_mtls_EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
int cwist_mtls_SSL_version(const SSL *ssl)
int cwist_mtls_SSL_CTX_set_default_verify_paths(SSL_CTX *ctx)
EVP_CIPHER_CTX * cwist_mtls_EVP_CIPHER_CTX_new(void)
unsigned long cwist_mtls_ERR_get_error(void)
int cwist_mtls_SSL_CTX_get_ex_new_index(long argl, void *argp, void *new_func, void *dup_func, void *free_func)
SSL_CTX * cwist_mtls_SSL_CTX_new(const SSL_METHOD *method)
int cwist_mtls_SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *path, int type)
int cwist_mtls_SSL_get_error(const SSL *ssl, int ret)
int cwist_mtls_RAND_bytes(unsigned char *buf, int num)
long cwist_mtls_SSL_CTX_set_session_cache_mode(SSL_CTX *ctx, long mode)
int cwist_mtls_EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
void cwist_mtls_ERR_clear_error(void)
int cwist_mtls_EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, void *engine, const unsigned char *key, const unsigned char *iv)
const EVP_MD * cwist_mtls_EVP_sha256(void)
void cwist_mtls_SSL_CTX_free(SSL_CTX *ctx)
int cwist_mtls_HMAC_Final(HMAC_CTX *ctx, unsigned char *out, unsigned int *out_len)
int cwist_mtls_SSL_shutdown(SSL *ssl)
SSL * cwist_mtls_SSL_new(SSL_CTX *ctx)
long cwist_mtls_SSL_CTX_sess_set_cache_size(SSL_CTX *ctx, unsigned long size)
int cwist_mtls_SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char *protos, unsigned int protos_len)
long cwist_mtls_SSL_CTX_set_options(SSL_CTX *ctx, unsigned long options)
int cwist_mtls_SSL_CTX_set_session_id_context(SSL_CTX *ctx, const unsigned char *sid_ctx, unsigned int sid_ctx_len)
int cwist_mtls_HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md, void *engine)
int cwist_mtls_SSL_set_alpn_protos(SSL *ssl, const unsigned char *protos, unsigned int protos_len)
const EVP_CIPHER * cwist_mtls_EVP_aes_256_cbc(void)
int cwist_mtls_SSL_connect(SSL *ssl)
int cwist_mtls_SSL_session_reused(const SSL *ssl)
int cwist_mtls_SSL_pending(const SSL *ssl)
void cwist_mtls_ERR_error_string_n(unsigned long e, char *buf, size_t len)
int cwist_mtls_EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl)
int cwist_mtls_SSL_accept(SSL *ssl)
int cwist_mtls_HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, size_t len)
long cwist_mtls_SSL_CTX_set_timeout(SSL_CTX *ctx, long seconds)
int cwist_mtls_CRYPTO_memcmp(const void *a, const void *b, size_t len)
void cwist_mtls_SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx, int(*cb)(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg), void *arg)
mbedTLS TLS backend: OPENSSL_cleanse / CRYPTO_memcmp.
mbedTLS TLS backend: error queue subset.
mbedTLS TLS backend: EVP subset (HMAC digest tags, AES-256-CBC).
struct cwist_mtls_cipher EVP_CIPHER
Definition evp.h:20
struct cwist_mtls_cipher_ctx EVP_CIPHER_CTX
Definition evp.h:21
struct cwist_mtls_evp_md EVP_MD
Definition evp.h:19
mbedTLS TLS backend: HMAC subset (HMAC-SHA256, one-shot + streaming).
struct cwist_mtls_hmac_ctx HMAC_CTX
Definition hmac.h:19
size_t cap
Definition otel.c:56
mbedTLS TLS backend: RAND_bytes over mbedTLS CTR-DRBG.
mbedTLS TLS backend: OpenSSL-shaped seam over the CWIST TLS subset.
#define SSL_OP_NO_TICKET
Definition ssl.h:65
#define TLS1_3_VERSION
Definition ssl.h:49
struct cwist_mtls_ssl SSL
Definition ssl.h:44
#define SSL_ERROR_SSL
Definition ssl.h:53
#define SSL_MODE_AUTO_RETRY
Definition ssl.h:71
#define SSL_TLSEXT_ERR_OK
Definition ssl.h:84
#define OPENSSL_NPN_NEGOTIATED
Definition ssl.h:88
#define SSL_ERROR_WANT_READ
Definition ssl.h:54
#define SSL_VERIFY_PEER
Definition ssl.h:81
#define SSL_FILETYPE_PEM
Definition ssl.h:77
#define SSL_OP_NO_TLSv1_2
Definition ssl.h:68
#define TLS1_2_VERSION
Definition ssl.h:48
struct cwist_mtls_method SSL_METHOD
Definition ssl.h:45
#define SSL_SESS_CACHE_SERVER
Definition ssl.h:74
#define SSL_ERROR_ZERO_RETURN
Definition ssl.h:57
struct cwist_mtls_ctx SSL_CTX
Definition ssl.h:43
#define SSL_ERROR_NONE
Definition ssl.h:52
#define SSL_ERROR_WANT_WRITE
Definition ssl.h:55