blob: 0b2947daf9b7ec150b1b54a3d5875eb9adbe739e [file] [log] [blame]
Roshan Pius3a1667e2018-07-03 15:17:14 -07001/*
2 * SSL/TLS interface functions for wolfSSL TLS case
3 * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "includes.h"
10
11#include "common.h"
12#include "crypto.h"
13#include "crypto/sha1.h"
14#include "crypto/sha256.h"
15#include "tls.h"
16
17/* wolfSSL includes */
18#include <wolfssl/options.h>
19#include <wolfssl/ssl.h>
20#include <wolfssl/error-ssl.h>
21#include <wolfssl/wolfcrypt/asn.h>
Hai Shalom899fcc72020-10-19 14:38:18 -070022#include <wolfssl/openssl/x509v3.h>
Roshan Pius3a1667e2018-07-03 15:17:14 -070023
24#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
25#define HAVE_AESGCM
26#include <wolfssl/wolfcrypt/aes.h>
27#endif
28
Sunil Ravia04bd252022-05-02 22:54:18 -070029#ifdef CONFIG_FIPS
30#include <wolfssl/wolfcrypt/fips_test.h>
31#endif /* CONFIG_FIPS */
32
Roshan Pius3a1667e2018-07-03 15:17:14 -070033#if !defined(CONFIG_FIPS) && \
34 (defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || \
35 defined(EAP_SERVER_FAST))
36#define WOLFSSL_NEED_EAP_FAST_PRF
37#endif
38
39#define SECRET_LEN 48
40#define RAN_LEN 32
41#define SESSION_TICKET_LEN 256
42
43static int tls_ref_count = 0;
44
45static int tls_ex_idx_session = 0;
46
47
48/* tls input data for wolfSSL Read Callback */
49struct tls_in_data {
50 const struct wpabuf *in_data;
51 size_t consumed; /* how many bytes have we used already */
52};
53
54/* tls output data for wolfSSL Write Callback */
55struct tls_out_data {
56 struct wpabuf *out_data;
57};
58
59struct tls_context {
60 void (*event_cb)(void *ctx, enum tls_event ev,
61 union tls_event_data *data);
62 void *cb_ctx;
63 int cert_in_cb;
64 char *ocsp_stapling_response;
Sunil Ravia04bd252022-05-02 22:54:18 -070065 unsigned int tls_session_lifetime;
Roshan Pius3a1667e2018-07-03 15:17:14 -070066};
67
68static struct tls_context *tls_global = NULL;
69
70/* wolfssl tls_connection */
71struct tls_connection {
72 struct tls_context *context;
73 WOLFSSL *ssl;
74 int read_alerts;
75 int write_alerts;
76 int failed;
77 struct tls_in_data input;
78 struct tls_out_data output;
79 char *subject_match;
80 char *alt_subject_match;
81 char *suffix_match;
82 char *domain_match;
83
84 u8 srv_cert_hash[32];
85
86 unsigned char client_random[RAN_LEN];
87 unsigned char server_random[RAN_LEN];
88 unsigned int flags;
89#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
90 tls_session_ticket_cb session_ticket_cb;
91 void *session_ticket_cb_ctx;
92 byte session_ticket[SESSION_TICKET_LEN];
93#endif
94 unsigned int ca_cert_verify:1;
95 unsigned int cert_probe:1;
96 unsigned int server_cert_only:1;
97 unsigned int success_data:1;
98
99 WOLFSSL_X509 *peer_cert;
100 WOLFSSL_X509 *peer_issuer;
101 WOLFSSL_X509 *peer_issuer_issuer;
Sunil Ravia04bd252022-05-02 22:54:18 -0700102 char *peer_subject; /* peer subject info for authenticated peer */
Roshan Pius3a1667e2018-07-03 15:17:14 -0700103};
104
105
106static struct tls_context * tls_context_new(const struct tls_config *conf)
107{
108 struct tls_context *context = os_zalloc(sizeof(*context));
109
110 if (!context)
111 return NULL;
112
113 if (conf) {
114 context->event_cb = conf->event_cb;
115 context->cb_ctx = conf->cb_ctx;
116 context->cert_in_cb = conf->cert_in_cb;
117 }
118
119 return context;
120}
121
122
123static void wolfssl_reset_in_data(struct tls_in_data *in,
124 const struct wpabuf *buf)
125{
126 /* old one not owned by us so don't free */
127 in->in_data = buf;
128 in->consumed = 0;
129}
130
131
132static void wolfssl_reset_out_data(struct tls_out_data *out)
133{
134 /* old one not owned by us so don't free */
135 out->out_data = wpabuf_alloc_copy("", 0);
136}
137
138
139/* wolfSSL I/O Receive CallBack */
140static int wolfssl_receive_cb(WOLFSSL *ssl, char *buf, int sz, void *ctx)
141{
142 size_t get = sz;
143 struct tls_in_data *data = ctx;
144
145 if (!data)
146 return -1;
147
148 if (get > (wpabuf_len(data->in_data) - data->consumed))
149 get = wpabuf_len(data->in_data) - data->consumed;
150
Hai Shalomc3565922019-10-28 11:58:20 -0700151 os_memcpy(buf, wpabuf_head_u8(data->in_data) + data->consumed, get);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700152 data->consumed += get;
153
154 if (get == 0)
155 return -2; /* WANT_READ */
156
157 return (int) get;
158}
159
160
161/* wolfSSL I/O Send CallBack */
162static int wolfssl_send_cb(WOLFSSL *ssl, char *buf, int sz, void *ctx)
163{
164 struct wpabuf *tmp;
165 struct tls_out_data *data = ctx;
166
167 if (!data)
168 return -1;
169
170 wpa_printf(MSG_DEBUG, "SSL: adding %d bytes", sz);
171
172 tmp = wpabuf_alloc_copy(buf, sz);
173 if (!tmp)
174 return -1;
175 data->out_data = wpabuf_concat(data->out_data, tmp);
176 if (!data->out_data)
177 return -1;
178
179 return sz;
180}
181
182
183static void remove_session_cb(WOLFSSL_CTX *ctx, WOLFSSL_SESSION *sess)
184{
185 struct wpabuf *buf;
186
187 buf = wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
188 if (!buf)
189 return;
190 wpa_printf(MSG_DEBUG,
191 "wolfSSL: Free application session data %p (sess %p)",
192 buf, sess);
193 wpabuf_free(buf);
194
195 wolfSSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL);
196}
197
198
Sunil Ravia04bd252022-05-02 22:54:18 -0700199#if defined(CONFIG_FIPS) && defined(HAVE_FIPS)
200static void wcFipsCb(int ok, int err, const char *hash)
201{
202 wpa_printf(MSG_INFO,
203 "wolfFIPS: wolfCrypt Fips error callback, ok = %d, err = %d",
204 ok, err);
205 wpa_printf(MSG_INFO, "wolfFIPS: message = %s", wc_GetErrorString(err));
206 wpa_printf(MSG_INFO, "wolfFIPS: hash = %s", hash);
207 if (err == IN_CORE_FIPS_E) {
208 wpa_printf(MSG_ERROR,
209 "wolfFIPS: In core integrity hash check failure, copy above hash");
210 wpa_printf(MSG_ERROR, "wolfFIPS: into verifyCore[] in fips_test.c and rebuild");
211 }
212}
213#endif /* CONFIG_FIPS && HAVE_FIPS */
214
215
216#ifdef DEBUG_WOLFSSL
217static void wolfSSL_logging_cb(const int log_level,
218 const char * const log_message)
219{
220 (void) log_level;
221 wpa_printf(MSG_DEBUG, "wolfSSL log:%s", log_message);
222}
223#endif /* DEBUG_WOLFSSL */
224
225
Roshan Pius3a1667e2018-07-03 15:17:14 -0700226void * tls_init(const struct tls_config *conf)
227{
228 WOLFSSL_CTX *ssl_ctx;
229 struct tls_context *context;
230 const char *ciphers;
231
232#ifdef DEBUG_WOLFSSL
Sunil Ravia04bd252022-05-02 22:54:18 -0700233 wolfSSL_SetLoggingCb(wolfSSL_logging_cb);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700234 wolfSSL_Debugging_ON();
235#endif /* DEBUG_WOLFSSL */
236
237 context = tls_context_new(conf);
238 if (!context)
239 return NULL;
240
241 if (tls_ref_count == 0) {
242 tls_global = context;
243
244 if (wolfSSL_Init() < 0)
245 return NULL;
Sunil Ravia04bd252022-05-02 22:54:18 -0700246#if defined(CONFIG_FIPS) && defined(HAVE_FIPS)
247 wolfCrypt_SetCb_fips(wcFipsCb);
248#endif /* CONFIG_FIPS && HAVE_FIPS */
Roshan Pius3a1667e2018-07-03 15:17:14 -0700249 }
250
251 tls_ref_count++;
252
253 /* start as client */
254 ssl_ctx = wolfSSL_CTX_new(wolfSSLv23_client_method());
255 if (!ssl_ctx) {
256 tls_ref_count--;
257 if (context != tls_global)
258 os_free(context);
259 if (tls_ref_count == 0) {
260 os_free(tls_global);
261 tls_global = NULL;
262 }
263 }
264 wolfSSL_SetIORecv(ssl_ctx, wolfssl_receive_cb);
265 wolfSSL_SetIOSend(ssl_ctx, wolfssl_send_cb);
Sunil Ravia04bd252022-05-02 22:54:18 -0700266 context->tls_session_lifetime = conf->tls_session_lifetime;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700267 wolfSSL_CTX_set_ex_data(ssl_ctx, 0, context);
268
269 if (conf->tls_session_lifetime > 0) {
Sunil Ravia04bd252022-05-02 22:54:18 -0700270 wolfSSL_CTX_set_session_id_context(ssl_ctx,
271 (const unsigned char *)
272 "hostapd", 7);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700273 wolfSSL_CTX_set_quiet_shutdown(ssl_ctx, 1);
274 wolfSSL_CTX_set_session_cache_mode(ssl_ctx,
Sunil Ravia04bd252022-05-02 22:54:18 -0700275 WOLFSSL_SESS_CACHE_SERVER);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700276 wolfSSL_CTX_set_timeout(ssl_ctx, conf->tls_session_lifetime);
277 wolfSSL_CTX_sess_set_remove_cb(ssl_ctx, remove_session_cb);
278 } else {
279 wolfSSL_CTX_set_session_cache_mode(ssl_ctx,
Sunil Ravia04bd252022-05-02 22:54:18 -0700280 WOLFSSL_SESS_CACHE_OFF);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700281 }
282
283 if (conf && conf->openssl_ciphers)
284 ciphers = conf->openssl_ciphers;
285 else
286 ciphers = "ALL";
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000287 wpa_printf(MSG_DEBUG, "wolfSSL: cipher suites: %s", ciphers);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700288 if (wolfSSL_CTX_set_cipher_list(ssl_ctx, ciphers) != 1) {
289 wpa_printf(MSG_ERROR,
290 "wolfSSL: Failed to set cipher string '%s'",
291 ciphers);
292 tls_deinit(ssl_ctx);
293 return NULL;
294 }
295
296 return ssl_ctx;
297}
298
299
300void tls_deinit(void *ssl_ctx)
301{
302 struct tls_context *context = wolfSSL_CTX_get_ex_data(ssl_ctx, 0);
303
304 if (context != tls_global)
305 os_free(context);
306
307 wolfSSL_CTX_free((WOLFSSL_CTX *) ssl_ctx);
308
309 tls_ref_count--;
310 if (tls_ref_count == 0) {
311 wolfSSL_Cleanup();
312 os_free(tls_global);
313 tls_global = NULL;
314 }
315}
316
317
318int tls_get_errors(void *tls_ctx)
319{
320#ifdef DEBUG_WOLFSSL
321#if 0
322 unsigned long err;
323
324 err = wolfSSL_ERR_peek_last_error_line(NULL, NULL);
325 if (err != 0) {
326 wpa_printf(MSG_INFO, "TLS - SSL error: %s",
327 wolfSSL_ERR_error_string(err, NULL));
328 return 1;
329 }
330#endif
331#endif /* DEBUG_WOLFSSL */
332 return 0;
333}
334
335
336struct tls_connection * tls_connection_init(void *tls_ctx)
337{
338 WOLFSSL_CTX *ssl_ctx = tls_ctx;
339 struct tls_connection *conn;
340
341 wpa_printf(MSG_DEBUG, "SSL: connection init");
342
343 conn = os_zalloc(sizeof(*conn));
344 if (!conn)
345 return NULL;
346 conn->ssl = wolfSSL_new(ssl_ctx);
347 if (!conn->ssl) {
348 os_free(conn);
349 return NULL;
350 }
351
352 wolfSSL_SetIOReadCtx(conn->ssl, &conn->input);
353 wolfSSL_SetIOWriteCtx(conn->ssl, &conn->output);
354 wolfSSL_set_ex_data(conn->ssl, 0, conn);
355 conn->context = wolfSSL_CTX_get_ex_data(ssl_ctx, 0);
356
357 /* Need randoms post-hanshake for EAP-FAST, export key and deriving
358 * session ID in EAP methods. */
359 wolfSSL_KeepArrays(conn->ssl);
360 wolfSSL_KeepHandshakeResources(conn->ssl);
361 wolfSSL_UseClientSuites(conn->ssl);
362
363 return conn;
364}
365
366
367void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
368{
369 if (!conn)
370 return;
371
372 wpa_printf(MSG_DEBUG, "SSL: connection deinit");
373
374 /* parts */
375 wolfSSL_free(conn->ssl);
376 os_free(conn->subject_match);
377 os_free(conn->alt_subject_match);
378 os_free(conn->suffix_match);
379 os_free(conn->domain_match);
Sunil Ravia04bd252022-05-02 22:54:18 -0700380 os_free(conn->peer_subject);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700381
382 /* self */
383 os_free(conn);
384}
385
386
387int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
388{
389 return conn ? wolfSSL_is_init_finished(conn->ssl) : 0;
390}
391
392
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800393char * tls_connection_peer_serial_num(void *tls_ctx,
394 struct tls_connection *conn)
395{
396 /* TODO */
397 return NULL;
398}
399
400
Roshan Pius3a1667e2018-07-03 15:17:14 -0700401int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
402{
403 WOLFSSL_SESSION *session;
404
405 if (!conn)
406 return -1;
407
408 wpa_printf(MSG_DEBUG, "SSL: connection shutdown");
409
410 /* Set quiet as OpenSSL does */
411 wolfSSL_set_quiet_shutdown(conn->ssl, 1);
412 wolfSSL_shutdown(conn->ssl);
413
Sunil Ravia04bd252022-05-02 22:54:18 -0700414 session = wolfSSL_get1_session(conn->ssl);
415 if (wolfSSL_clear(conn->ssl) != 1) {
416 wolfSSL_SESSION_free(session);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700417 return -1;
Sunil Ravia04bd252022-05-02 22:54:18 -0700418 }
Roshan Pius3a1667e2018-07-03 15:17:14 -0700419 wolfSSL_set_session(conn->ssl, session);
Sunil Ravia04bd252022-05-02 22:54:18 -0700420 wolfSSL_SESSION_free(session);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700421
422 return 0;
423}
424
425
426static int tls_connection_set_subject_match(struct tls_connection *conn,
427 const char *subject_match,
428 const char *alt_subject_match,
429 const char *suffix_match,
430 const char *domain_match)
431{
432 os_free(conn->subject_match);
433 conn->subject_match = NULL;
434 if (subject_match) {
435 conn->subject_match = os_strdup(subject_match);
436 if (!conn->subject_match)
437 return -1;
438 }
439
440 os_free(conn->alt_subject_match);
441 conn->alt_subject_match = NULL;
442 if (alt_subject_match) {
443 conn->alt_subject_match = os_strdup(alt_subject_match);
444 if (!conn->alt_subject_match)
445 return -1;
446 }
447
448 os_free(conn->suffix_match);
449 conn->suffix_match = NULL;
450 if (suffix_match) {
451 conn->suffix_match = os_strdup(suffix_match);
452 if (!conn->suffix_match)
453 return -1;
454 }
455
456 os_free(conn->domain_match);
457 conn->domain_match = NULL;
458 if (domain_match) {
459 conn->domain_match = os_strdup(domain_match);
460 if (!conn->domain_match)
461 return -1;
462 }
463
464 return 0;
465}
466
467
Roshan Pius3a1667e2018-07-03 15:17:14 -0700468static int tls_connection_client_cert(struct tls_connection *conn,
469 const char *client_cert,
470 const u8 *client_cert_blob,
471 size_t blob_len)
472{
473 if (!client_cert && !client_cert_blob)
474 return 0;
475
476 if (client_cert_blob) {
477 if (wolfSSL_use_certificate_chain_buffer_format(
478 conn->ssl, client_cert_blob, blob_len,
Hai Shalom60840252021-02-19 19:02:11 -0800479 SSL_FILETYPE_ASN1) != SSL_SUCCESS) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700480 wpa_printf(MSG_INFO,
481 "SSL: use client cert DER blob failed");
Sunil Ravia04bd252022-05-02 22:54:18 -0700482 if (wolfSSL_use_certificate_chain_buffer_format(
483 conn->ssl, client_cert_blob, blob_len,
484 SSL_FILETYPE_PEM) != SSL_SUCCESS) {
485 wpa_printf(MSG_INFO,
486 "SSL: use client cert PEM blob failed");
487 return -1;
488 }
Roshan Pius3a1667e2018-07-03 15:17:14 -0700489 }
490 wpa_printf(MSG_DEBUG, "SSL: use client cert blob OK");
491 return 0;
492 }
493
494 if (client_cert) {
Hai Shalom60840252021-02-19 19:02:11 -0800495 if (wolfSSL_use_certificate_chain_file(
496 conn->ssl, client_cert) != SSL_SUCCESS) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700497 wpa_printf(MSG_INFO,
498 "SSL: use client cert PEM file failed");
499 if (wolfSSL_use_certificate_chain_file_format(
500 conn->ssl, client_cert,
Hai Shalom60840252021-02-19 19:02:11 -0800501 SSL_FILETYPE_ASN1) != SSL_SUCCESS) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700502 wpa_printf(MSG_INFO,
503 "SSL: use client cert DER file failed");
504 return -1;
505 }
506 }
507 wpa_printf(MSG_DEBUG, "SSL: use client cert file OK");
508 return 0;
509 }
510
511 return 0;
512}
513
514
515static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
516{
517 if (!password)
518 return 0;
519 os_strlcpy(buf, (char *) password, size);
520 return os_strlen(buf);
521}
522
523
524static int tls_connection_private_key(void *tls_ctx,
525 struct tls_connection *conn,
526 const char *private_key,
527 const char *private_key_passwd,
528 const u8 *private_key_blob,
529 size_t blob_len)
530{
531 WOLFSSL_CTX *ctx = tls_ctx;
532 char *passwd = NULL;
533 int ok = 0;
534
535 if (!private_key && !private_key_blob)
536 return 0;
537
538 if (private_key_passwd) {
539 passwd = os_strdup(private_key_passwd);
540 if (!passwd)
541 return -1;
542 }
543
544 wolfSSL_CTX_set_default_passwd_cb(ctx, tls_passwd_cb);
545 wolfSSL_CTX_set_default_passwd_cb_userdata(ctx, passwd);
546
547 if (private_key_blob) {
548 if (wolfSSL_use_PrivateKey_buffer(conn->ssl,
549 private_key_blob, blob_len,
Sunil Ravia04bd252022-05-02 22:54:18 -0700550 SSL_FILETYPE_ASN1) !=
551 SSL_SUCCESS) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700552 wpa_printf(MSG_INFO,
553 "SSL: use private DER blob failed");
Sunil Ravia04bd252022-05-02 22:54:18 -0700554 if (wolfSSL_use_PrivateKey_buffer(
555 conn->ssl,
556 private_key_blob, blob_len,
557 SSL_FILETYPE_PEM) != SSL_SUCCESS) {
558 wpa_printf(MSG_INFO,
559 "SSL: use private PEM blob failed");
560 } else {
561 ok = 1;
562 }
Roshan Pius3a1667e2018-07-03 15:17:14 -0700563 } else {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700564 ok = 1;
565 }
Sunil Ravia04bd252022-05-02 22:54:18 -0700566 if (ok)
567 wpa_printf(MSG_DEBUG, "SSL: use private key blob OK");
Roshan Pius3a1667e2018-07-03 15:17:14 -0700568 }
569
570 if (!ok && private_key) {
571 if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key,
Sunil Ravia04bd252022-05-02 22:54:18 -0700572 SSL_FILETYPE_PEM) !=
573 SSL_SUCCESS) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700574 wpa_printf(MSG_INFO,
575 "SSL: use private key PEM file failed");
576 if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key,
Sunil Ravia04bd252022-05-02 22:54:18 -0700577 SSL_FILETYPE_ASN1) !=
578 SSL_SUCCESS) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700579 wpa_printf(MSG_INFO,
580 "SSL: use private key DER file failed");
581 } else {
582 ok = 1;
583 }
584 } else {
585 ok = 1;
586 }
587
588 if (ok)
589 wpa_printf(MSG_DEBUG, "SSL: use private key file OK");
590 }
591
592 wolfSSL_CTX_set_default_passwd_cb(ctx, NULL);
593 os_free(passwd);
594
595 if (!ok)
596 return -1;
597
598 return 0;
599}
600
601
602static int tls_match_alt_subject_component(WOLFSSL_X509 *cert, int type,
603 const char *value, size_t len)
604{
Hai Shalom899fcc72020-10-19 14:38:18 -0700605 WOLFSSL_GENERAL_NAME *gen;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700606 void *ext;
607 int found = 0;
608 int i;
609
610 ext = wolfSSL_X509_get_ext_d2i(cert, ALT_NAMES_OID, NULL, NULL);
611
612 for (i = 0; ext && i < wolfSSL_sk_num(ext); i++) {
613 gen = wolfSSL_sk_value(ext, i);
Hai Shalom899fcc72020-10-19 14:38:18 -0700614 if (!gen || gen->type != type)
Roshan Pius3a1667e2018-07-03 15:17:14 -0700615 continue;
Hai Shalom899fcc72020-10-19 14:38:18 -0700616 if ((size_t) wolfSSL_ASN1_STRING_length(gen->d.ia5) == len &&
617 os_memcmp(value, wolfSSL_ASN1_STRING_data(gen->d.ia5),
618 len) == 0)
Roshan Pius3a1667e2018-07-03 15:17:14 -0700619 found++;
620 }
621
Hai Shalom899fcc72020-10-19 14:38:18 -0700622 wolfSSL_sk_GENERAL_NAME_free(ext);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700623
624 return found;
625}
626
627
628static int tls_match_alt_subject(WOLFSSL_X509 *cert, const char *match)
629{
630 int type;
631 const char *pos, *end;
632 size_t len;
633
634 pos = match;
635 do {
636 if (os_strncmp(pos, "EMAIL:", 6) == 0) {
637 type = GEN_EMAIL;
638 pos += 6;
639 } else if (os_strncmp(pos, "DNS:", 4) == 0) {
640 type = GEN_DNS;
641 pos += 4;
642 } else if (os_strncmp(pos, "URI:", 4) == 0) {
643 type = GEN_URI;
644 pos += 4;
645 } else {
646 wpa_printf(MSG_INFO,
647 "TLS: Invalid altSubjectName match '%s'",
648 pos);
649 return 0;
650 }
651 end = os_strchr(pos, ';');
652 while (end) {
653 if (os_strncmp(end + 1, "EMAIL:", 6) == 0 ||
654 os_strncmp(end + 1, "DNS:", 4) == 0 ||
655 os_strncmp(end + 1, "URI:", 4) == 0)
656 break;
657 end = os_strchr(end + 1, ';');
658 }
659 if (end)
660 len = end - pos;
661 else
662 len = os_strlen(pos);
663 if (tls_match_alt_subject_component(cert, type, pos, len) > 0)
664 return 1;
665 pos = end + 1;
666 } while (end);
667
668 return 0;
669}
670
671
672static int domain_suffix_match(const char *val, size_t len, const char *match,
Hai Shalom021b0b52019-04-10 11:17:58 -0700673 size_t match_len, int full)
Roshan Pius3a1667e2018-07-03 15:17:14 -0700674{
Hai Shalom021b0b52019-04-10 11:17:58 -0700675 size_t i;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700676
677 /* Check for embedded nuls that could mess up suffix matching */
678 for (i = 0; i < len; i++) {
679 if (val[i] == '\0') {
680 wpa_printf(MSG_DEBUG,
681 "TLS: Embedded null in a string - reject");
682 return 0;
683 }
684 }
685
Roshan Pius3a1667e2018-07-03 15:17:14 -0700686 if (match_len > len || (full && match_len != len))
687 return 0;
688
689 if (os_strncasecmp(val + len - match_len, match, match_len) != 0)
690 return 0; /* no match */
691
692 if (match_len == len)
693 return 1; /* exact match */
694
695 if (val[len - match_len - 1] == '.')
696 return 1; /* full label match completes suffix match */
697
698 wpa_printf(MSG_DEBUG, "TLS: Reject due to incomplete label match");
699 return 0;
700}
701
702
Hai Shalom021b0b52019-04-10 11:17:58 -0700703static int tls_match_suffix_helper(WOLFSSL_X509 *cert, const char *match,
704 size_t match_len, int full)
Roshan Pius3a1667e2018-07-03 15:17:14 -0700705{
Hai Shalom899fcc72020-10-19 14:38:18 -0700706 WOLFSSL_GENERAL_NAME *gen;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700707 void *ext;
708 int i;
709 int j;
710 int dns_name = 0;
711 WOLFSSL_X509_NAME *name;
712
713 wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s",
714 full ? "" : "suffix ", match);
715
716 ext = wolfSSL_X509_get_ext_d2i(cert, ALT_NAMES_OID, NULL, NULL);
717
718 for (j = 0; ext && j < wolfSSL_sk_num(ext); j++) {
719 gen = wolfSSL_sk_value(ext, j);
Hai Shalom899fcc72020-10-19 14:38:18 -0700720 if (!gen || gen->type != ASN_DNS_TYPE)
Roshan Pius3a1667e2018-07-03 15:17:14 -0700721 continue;
722 dns_name++;
723 wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate dNSName",
Hai Shalom899fcc72020-10-19 14:38:18 -0700724 wolfSSL_ASN1_STRING_data(gen->d.ia5),
725 wolfSSL_ASN1_STRING_length(gen->d.ia5));
726 if (domain_suffix_match(
727 (const char *) wolfSSL_ASN1_STRING_data(gen->d.ia5),
728 wolfSSL_ASN1_STRING_length(gen->d.ia5), match,
729 match_len, full) == 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700730 wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
731 full ? "Match" : "Suffix match");
732 wolfSSL_sk_ASN1_OBJECT_free(ext);
733 return 1;
734 }
735 }
Hai Shalom899fcc72020-10-19 14:38:18 -0700736 wolfSSL_sk_GENERAL_NAME_free(ext);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700737
738 if (dns_name) {
739 wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched");
740 return 0;
741 }
742
743 name = wolfSSL_X509_get_subject_name(cert);
744 i = -1;
745 for (;;) {
746 WOLFSSL_X509_NAME_ENTRY *e;
747 WOLFSSL_ASN1_STRING *cn;
748
Sunil Ravia04bd252022-05-02 22:54:18 -0700749 i = wolfSSL_X509_NAME_get_index_by_NID(name, NID_commonName, i);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700750 if (i == -1)
751 break;
752 e = wolfSSL_X509_NAME_get_entry(name, i);
753 if (!e)
754 continue;
755 cn = wolfSSL_X509_NAME_ENTRY_get_data(e);
756 if (!cn)
757 continue;
758 wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName",
759 cn->data, cn->length);
Hai Shalom021b0b52019-04-10 11:17:58 -0700760 if (domain_suffix_match(cn->data, cn->length,
761 match, match_len, full) == 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700762 wpa_printf(MSG_DEBUG, "TLS: %s in commonName found",
763 full ? "Match" : "Suffix match");
764 return 1;
765 }
766 }
767
768 wpa_printf(MSG_DEBUG, "TLS: No CommonName %smatch found",
769 full ? "" : "suffix ");
770 return 0;
771}
772
773
Hai Shalom021b0b52019-04-10 11:17:58 -0700774static int tls_match_suffix(WOLFSSL_X509 *cert, const char *match, int full)
775{
776 const char *token, *last = NULL;
777
778 /* Process each match alternative separately until a match is found */
779 while ((token = cstr_token(match, ";", &last))) {
780 if (tls_match_suffix_helper(cert, token, last - token, full))
781 return 1;
782 }
783
784 return 0;
785}
786
787
Roshan Pius3a1667e2018-07-03 15:17:14 -0700788static enum tls_fail_reason wolfssl_tls_fail_reason(int err)
789{
790 switch (err) {
791 case X509_V_ERR_CERT_REVOKED:
792 return TLS_FAIL_REVOKED;
793 case ASN_BEFORE_DATE_E:
794 case X509_V_ERR_CERT_NOT_YET_VALID:
795 case X509_V_ERR_CRL_NOT_YET_VALID:
796 return TLS_FAIL_NOT_YET_VALID;
797 case ASN_AFTER_DATE_E:
798 case X509_V_ERR_CERT_HAS_EXPIRED:
799 case X509_V_ERR_CRL_HAS_EXPIRED:
800 return TLS_FAIL_EXPIRED;
801 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
802 case X509_V_ERR_UNABLE_TO_GET_CRL:
803 case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
804 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
805 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
806 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
807 case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
808 case X509_V_ERR_CERT_CHAIN_TOO_LONG:
809 case X509_V_ERR_PATH_LENGTH_EXCEEDED:
810 case X509_V_ERR_INVALID_CA:
811 return TLS_FAIL_UNTRUSTED;
812 case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
813 case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
814 case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
815 case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
816 case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
817 case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
818 case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
819 case X509_V_ERR_CERT_UNTRUSTED:
820 case X509_V_ERR_CERT_REJECTED:
821 return TLS_FAIL_BAD_CERTIFICATE;
822 default:
823 return TLS_FAIL_UNSPECIFIED;
824 }
825}
826
827
828static const char * wolfssl_tls_err_string(int err, const char *err_str)
829{
830 switch (err) {
831 case ASN_BEFORE_DATE_E:
832 return "certificate is not yet valid";
833 case ASN_AFTER_DATE_E:
834 return "certificate has expired";
835 default:
836 return err_str;
837 }
838}
839
840
841static struct wpabuf * get_x509_cert(WOLFSSL_X509 *cert)
842{
843 struct wpabuf *buf = NULL;
844 const u8 *data;
845 int cert_len;
846
847 data = wolfSSL_X509_get_der(cert, &cert_len);
848 if (!data)
849 buf = wpabuf_alloc_copy(data, cert_len);
850
851 return buf;
852}
853
854
855static void wolfssl_tls_fail_event(struct tls_connection *conn,
856 WOLFSSL_X509 *err_cert, int err, int depth,
857 const char *subject, const char *err_str,
858 enum tls_fail_reason reason)
859{
860 union tls_event_data ev;
861 struct wpabuf *cert = NULL;
862 struct tls_context *context = conn->context;
863
864 if (!context->event_cb)
865 return;
866
867 cert = get_x509_cert(err_cert);
868 os_memset(&ev, 0, sizeof(ev));
869 ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ?
870 reason : wolfssl_tls_fail_reason(err);
871 ev.cert_fail.depth = depth;
872 ev.cert_fail.subject = subject;
873 ev.cert_fail.reason_txt = wolfssl_tls_err_string(err, err_str);
874 ev.cert_fail.cert = cert;
875 context->event_cb(context->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
876 wpabuf_free(cert);
877}
878
879
880static void wolfssl_tls_cert_event(struct tls_connection *conn,
881 WOLFSSL_X509 *err_cert, int depth,
882 const char *subject)
883{
884 struct wpabuf *cert = NULL;
885 union tls_event_data ev;
886 struct tls_context *context = conn->context;
887 char *alt_subject[TLS_MAX_ALT_SUBJECT];
888 int alt, num_alt_subject = 0;
Hai Shalom899fcc72020-10-19 14:38:18 -0700889 WOLFSSL_GENERAL_NAME *gen;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700890 void *ext;
891 int i;
892#ifdef CONFIG_SHA256
893 u8 hash[32];
894#endif /* CONFIG_SHA256 */
895
896 if (!context->event_cb)
897 return;
898
899 os_memset(&ev, 0, sizeof(ev));
900 if (conn->cert_probe || (conn->flags & TLS_CONN_EXT_CERT_CHECK) ||
901 context->cert_in_cb) {
902 cert = get_x509_cert(err_cert);
903 ev.peer_cert.cert = cert;
904 }
905
906#ifdef CONFIG_SHA256
907 if (cert) {
908 const u8 *addr[1];
909 size_t len[1];
910
911 addr[0] = wpabuf_head(cert);
912 len[0] = wpabuf_len(cert);
913 if (sha256_vector(1, addr, len, hash) == 0) {
914 ev.peer_cert.hash = hash;
915 ev.peer_cert.hash_len = sizeof(hash);
916 }
917 }
918#endif /* CONFIG_SHA256 */
919
920 ev.peer_cert.depth = depth;
921 ev.peer_cert.subject = subject;
922
923 ext = wolfSSL_X509_get_ext_d2i(err_cert, ALT_NAMES_OID, NULL, NULL);
924 for (i = 0; ext && i < wolfSSL_sk_num(ext); i++) {
925 char *pos;
926
927 if (num_alt_subject == TLS_MAX_ALT_SUBJECT)
928 break;
929 gen = wolfSSL_sk_value((void *) ext, i);
Hai Shalom899fcc72020-10-19 14:38:18 -0700930 if (!gen ||
931 (gen->type != GEN_EMAIL &&
932 gen->type != GEN_DNS &&
933 gen->type != GEN_URI))
Roshan Pius3a1667e2018-07-03 15:17:14 -0700934 continue;
935
Hai Shalom899fcc72020-10-19 14:38:18 -0700936 pos = os_malloc(10 + wolfSSL_ASN1_STRING_length(gen->d.ia5) +
937 1);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700938 if (!pos)
939 break;
940 alt_subject[num_alt_subject++] = pos;
941
942 switch (gen->type) {
943 case GEN_EMAIL:
944 os_memcpy(pos, "EMAIL:", 6);
945 pos += 6;
946 break;
947 case GEN_DNS:
948 os_memcpy(pos, "DNS:", 4);
949 pos += 4;
950 break;
951 case GEN_URI:
952 os_memcpy(pos, "URI:", 4);
953 pos += 4;
954 break;
955 }
956
Hai Shalom899fcc72020-10-19 14:38:18 -0700957 os_memcpy(pos, wolfSSL_ASN1_STRING_data(gen->d.ia5),
958 wolfSSL_ASN1_STRING_length(gen->d.ia5));
959 pos += wolfSSL_ASN1_STRING_length(gen->d.ia5);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700960 *pos = '\0';
961 }
Hai Shalom899fcc72020-10-19 14:38:18 -0700962 wolfSSL_sk_GENERAL_NAME_free(ext);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700963
964 for (alt = 0; alt < num_alt_subject; alt++)
965 ev.peer_cert.altsubject[alt] = alt_subject[alt];
966 ev.peer_cert.num_altsubject = num_alt_subject;
967
968 context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
969 wpabuf_free(cert);
970 for (alt = 0; alt < num_alt_subject; alt++)
971 os_free(alt_subject[alt]);
972}
973
974
975static int tls_verify_cb(int preverify_ok, WOLFSSL_X509_STORE_CTX *x509_ctx)
976{
977 char buf[256];
978 WOLFSSL_X509 *err_cert;
979 int err, depth;
980 WOLFSSL *ssl;
981 struct tls_connection *conn;
982 struct tls_context *context;
983 char *match, *altmatch, *suffix_match, *domain_match;
984 const char *err_str;
985
986 err_cert = wolfSSL_X509_STORE_CTX_get_current_cert(x509_ctx);
987 if (!err_cert) {
988 wpa_printf(MSG_DEBUG, "wolfSSL: No Cert");
989 return 0;
990 }
991
992 err = wolfSSL_X509_STORE_CTX_get_error(x509_ctx);
993 depth = wolfSSL_X509_STORE_CTX_get_error_depth(x509_ctx);
994 ssl = wolfSSL_X509_STORE_CTX_get_ex_data(
995 x509_ctx, wolfSSL_get_ex_data_X509_STORE_CTX_idx());
996 wolfSSL_X509_NAME_oneline(wolfSSL_X509_get_subject_name(err_cert), buf,
997 sizeof(buf));
998
999 conn = wolfSSL_get_ex_data(ssl, 0);
1000 if (!conn) {
1001 wpa_printf(MSG_DEBUG, "wolfSSL: No ex_data");
1002 return 0;
1003 }
1004
1005 if (depth == 0)
1006 conn->peer_cert = err_cert;
1007 else if (depth == 1)
1008 conn->peer_issuer = err_cert;
1009 else if (depth == 2)
1010 conn->peer_issuer_issuer = err_cert;
1011
1012 context = conn->context;
1013 match = conn->subject_match;
1014 altmatch = conn->alt_subject_match;
1015 suffix_match = conn->suffix_match;
1016 domain_match = conn->domain_match;
1017
1018 if (!preverify_ok && !conn->ca_cert_verify)
1019 preverify_ok = 1;
1020 if (!preverify_ok && depth > 0 && conn->server_cert_only)
1021 preverify_ok = 1;
1022 if (!preverify_ok && (conn->flags & TLS_CONN_DISABLE_TIME_CHECKS) &&
1023 (err == X509_V_ERR_CERT_HAS_EXPIRED ||
1024 err == ASN_AFTER_DATE_E || err == ASN_BEFORE_DATE_E ||
1025 err == X509_V_ERR_CERT_NOT_YET_VALID)) {
1026 wpa_printf(MSG_DEBUG,
1027 "wolfSSL: Ignore certificate validity time mismatch");
1028 preverify_ok = 1;
1029 }
1030
1031 err_str = wolfSSL_X509_verify_cert_error_string(err);
1032
1033#ifdef CONFIG_SHA256
1034 /*
1035 * Do not require preverify_ok so we can explicity allow otherwise
1036 * invalid pinned server certificates.
1037 */
1038 if (depth == 0 && conn->server_cert_only) {
1039 struct wpabuf *cert;
1040
1041 cert = get_x509_cert(err_cert);
1042 if (!cert) {
1043 wpa_printf(MSG_DEBUG,
1044 "wolfSSL: Could not fetch server certificate data");
1045 preverify_ok = 0;
1046 } else {
1047 u8 hash[32];
1048 const u8 *addr[1];
1049 size_t len[1];
1050
1051 addr[0] = wpabuf_head(cert);
1052 len[0] = wpabuf_len(cert);
1053 if (sha256_vector(1, addr, len, hash) < 0 ||
1054 os_memcmp(conn->srv_cert_hash, hash, 32) != 0) {
1055 err_str = "Server certificate mismatch";
1056 err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
1057 preverify_ok = 0;
1058 } else if (!preverify_ok) {
1059 /*
1060 * Certificate matches pinned certificate, allow
1061 * regardless of other problems.
1062 */
1063 wpa_printf(MSG_DEBUG,
1064 "wolfSSL: Ignore validation issues for a pinned server certificate");
1065 preverify_ok = 1;
1066 }
1067 wpabuf_free(cert);
1068 }
1069 }
1070#endif /* CONFIG_SHA256 */
1071
1072 if (!preverify_ok) {
1073 wpa_printf(MSG_WARNING,
1074 "TLS: Certificate verification failed, error %d (%s) depth %d for '%s'",
1075 err, err_str, depth, buf);
1076 wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
1077 err_str, TLS_FAIL_UNSPECIFIED);
1078 return preverify_ok;
1079 }
1080
1081 wpa_printf(MSG_DEBUG,
1082 "TLS: %s - preverify_ok=%d err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
1083 __func__, preverify_ok, err, err_str,
1084 conn->ca_cert_verify, depth, buf);
1085 if (depth == 0 && match && os_strstr(buf, match) == NULL) {
1086 wpa_printf(MSG_WARNING,
1087 "TLS: Subject '%s' did not match with '%s'",
1088 buf, match);
1089 preverify_ok = 0;
1090 wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
1091 "Subject mismatch",
1092 TLS_FAIL_SUBJECT_MISMATCH);
1093 } else if (depth == 0 && altmatch &&
1094 !tls_match_alt_subject(err_cert, altmatch)) {
1095 wpa_printf(MSG_WARNING,
1096 "TLS: altSubjectName match '%s' not found",
1097 altmatch);
1098 preverify_ok = 0;
1099 wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
1100 "AltSubject mismatch",
1101 TLS_FAIL_ALTSUBJECT_MISMATCH);
1102 } else if (depth == 0 && suffix_match &&
1103 !tls_match_suffix(err_cert, suffix_match, 0)) {
1104 wpa_printf(MSG_WARNING,
1105 "TLS: Domain suffix match '%s' not found",
1106 suffix_match);
1107 preverify_ok = 0;
1108 wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
1109 "Domain suffix mismatch",
1110 TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
1111 } else if (depth == 0 && domain_match &&
1112 !tls_match_suffix(err_cert, domain_match, 1)) {
1113 wpa_printf(MSG_WARNING, "TLS: Domain match '%s' not found",
1114 domain_match);
1115 preverify_ok = 0;
1116 wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
1117 "Domain mismatch",
1118 TLS_FAIL_DOMAIN_MISMATCH);
1119 } else {
1120 wolfssl_tls_cert_event(conn, err_cert, depth, buf);
1121 }
1122
1123 if (conn->cert_probe && preverify_ok && depth == 0) {
1124 wpa_printf(MSG_DEBUG,
1125 "wolfSSL: Reject server certificate on probe-only run");
1126 preverify_ok = 0;
1127 wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
1128 "Server certificate chain probe",
1129 TLS_FAIL_SERVER_CHAIN_PROBE);
1130 }
1131
1132#ifdef HAVE_OCSP_WOLFSSL
1133 if (depth == 0 && (conn->flags & TLS_CONN_REQUEST_OCSP) &&
1134 preverify_ok) {
1135 enum ocsp_result res;
1136
1137 res = check_ocsp_resp(conn->ssl_ctx, conn->ssl, err_cert,
1138 conn->peer_issuer,
1139 conn->peer_issuer_issuer);
1140 if (res == OCSP_REVOKED) {
1141 preverify_ok = 0;
1142 wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
1143 "certificate revoked",
1144 TLS_FAIL_REVOKED);
1145 if (err == X509_V_OK)
1146 X509_STORE_CTX_set_error(
1147 x509_ctx, X509_V_ERR_CERT_REVOKED);
1148 } else if (res != OCSP_GOOD &&
1149 (conn->flags & TLS_CONN_REQUIRE_OCSP)) {
1150 preverify_ok = 0;
1151 wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
1152 "bad certificate status response",
1153 TLS_FAIL_UNSPECIFIED);
1154 }
1155 }
1156#endif /* HAVE_OCSP_WOLFSSL */
1157 if (depth == 0 && preverify_ok && context->event_cb != NULL)
1158 context->event_cb(context->cb_ctx,
1159 TLS_CERT_CHAIN_SUCCESS, NULL);
1160
Sunil Ravia04bd252022-05-02 22:54:18 -07001161 if (depth == 0 && preverify_ok) {
1162 os_free(conn->peer_subject);
1163 conn->peer_subject = os_strdup(buf);
1164 }
1165
Roshan Pius3a1667e2018-07-03 15:17:14 -07001166 return preverify_ok;
1167}
1168
1169
1170static int tls_connection_ca_cert(void *tls_ctx, struct tls_connection *conn,
1171 const char *ca_cert,
1172 const u8 *ca_cert_blob, size_t blob_len,
1173 const char *ca_path)
1174{
1175 WOLFSSL_CTX *ctx = tls_ctx;
1176
1177 wolfSSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
1178 conn->ca_cert_verify = 1;
1179
1180 if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) {
1181 wpa_printf(MSG_DEBUG,
1182 "wolfSSL: Probe for server certificate chain");
1183 conn->cert_probe = 1;
1184 conn->ca_cert_verify = 0;
1185 return 0;
1186 }
1187
1188 if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) {
1189#ifdef CONFIG_SHA256
1190 const char *pos = ca_cert + 7;
1191
1192 if (os_strncmp(pos, "server/sha256/", 14) != 0) {
1193 wpa_printf(MSG_DEBUG,
1194 "wolfSSL: Unsupported ca_cert hash value '%s'",
1195 ca_cert);
1196 return -1;
1197 }
1198 pos += 14;
1199 if (os_strlen(pos) != 32 * 2) {
1200 wpa_printf(MSG_DEBUG,
1201 "wolfSSL: Unexpected SHA256 hash length in ca_cert '%s'",
1202 ca_cert);
1203 return -1;
1204 }
1205 if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) {
1206 wpa_printf(MSG_DEBUG,
1207 "wolfSSL: Invalid SHA256 hash value in ca_cert '%s'",
1208 ca_cert);
1209 return -1;
1210 }
1211 conn->server_cert_only = 1;
1212 wpa_printf(MSG_DEBUG,
1213 "wolfSSL: Checking only server certificate match");
1214 return 0;
1215#else /* CONFIG_SHA256 */
1216 wpa_printf(MSG_INFO,
1217 "No SHA256 included in the build - cannot validate server certificate hash");
1218 return -1;
1219#endif /* CONFIG_SHA256 */
1220 }
1221
1222 if (ca_cert_blob) {
1223 if (wolfSSL_CTX_load_verify_buffer(ctx, ca_cert_blob, blob_len,
1224 SSL_FILETYPE_ASN1) !=
1225 SSL_SUCCESS) {
Sunil Ravia04bd252022-05-02 22:54:18 -07001226 wpa_printf(MSG_INFO, "SSL: failed to load DER CA blob");
1227 if (wolfSSL_CTX_load_verify_buffer(
1228 ctx, ca_cert_blob, blob_len,
1229 SSL_FILETYPE_PEM) != SSL_SUCCESS) {
1230 wpa_printf(MSG_INFO,
1231 "SSL: failed to load PEM CA blob");
1232 return -1;
1233 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001234 }
1235 wpa_printf(MSG_DEBUG, "SSL: use CA cert blob OK");
1236 return 0;
1237 }
1238
1239 if (ca_cert || ca_path) {
1240 WOLFSSL_X509_STORE *cm = wolfSSL_X509_STORE_new();
1241
1242 if (!cm) {
1243 wpa_printf(MSG_INFO,
1244 "SSL: failed to create certificate store");
1245 return -1;
1246 }
1247 wolfSSL_CTX_set_cert_store(ctx, cm);
1248
1249 if (wolfSSL_CTX_load_verify_locations(ctx, ca_cert, ca_path) !=
1250 SSL_SUCCESS) {
1251 wpa_printf(MSG_INFO,
1252 "SSL: failed to load ca_cert as PEM");
1253
1254 if (!ca_cert)
1255 return -1;
1256
1257 if (wolfSSL_CTX_der_load_verify_locations(
1258 ctx, ca_cert, SSL_FILETYPE_ASN1) !=
1259 SSL_SUCCESS) {
1260 wpa_printf(MSG_INFO,
1261 "SSL: failed to load ca_cert as DER");
1262 return -1;
1263 }
1264 }
1265 return 0;
1266 }
1267
1268 conn->ca_cert_verify = 0;
1269 return 0;
1270}
1271
1272
1273static void tls_set_conn_flags(WOLFSSL *ssl, unsigned int flags)
1274{
1275#ifdef HAVE_SESSION_TICKET
Roshan Pius3a1667e2018-07-03 15:17:14 -07001276 if (!(flags & TLS_CONN_DISABLE_SESSION_TICKET))
1277 wolfSSL_UseSessionTicket(ssl);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001278#endif /* HAVE_SESSION_TICKET */
1279
1280 if (flags & TLS_CONN_DISABLE_TLSv1_0)
1281 wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1);
1282 if (flags & TLS_CONN_DISABLE_TLSv1_1)
1283 wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
1284 if (flags & TLS_CONN_DISABLE_TLSv1_2)
1285 wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_2);
Sunil Ravia04bd252022-05-02 22:54:18 -07001286 if (flags & TLS_CONN_DISABLE_TLSv1_3)
1287 wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_3);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001288}
1289
1290
1291int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
1292 const struct tls_connection_params *params)
1293{
1294 wpa_printf(MSG_DEBUG, "SSL: set params");
1295
1296 if (tls_connection_set_subject_match(conn, params->subject_match,
1297 params->altsubject_match,
1298 params->suffix_match,
1299 params->domain_match) < 0) {
1300 wpa_printf(MSG_INFO, "Error setting subject match");
1301 return -1;
1302 }
1303
1304 if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
1305 params->ca_cert_blob,
1306 params->ca_cert_blob_len,
1307 params->ca_path) < 0) {
1308 wpa_printf(MSG_INFO, "Error setting CA cert");
1309 return -1;
1310 }
1311
1312 if (tls_connection_client_cert(conn, params->client_cert,
1313 params->client_cert_blob,
1314 params->client_cert_blob_len) < 0) {
1315 wpa_printf(MSG_INFO, "Error setting client cert");
1316 return -1;
1317 }
1318
1319 if (tls_connection_private_key(tls_ctx, conn, params->private_key,
1320 params->private_key_passwd,
1321 params->private_key_blob,
1322 params->private_key_blob_len) < 0) {
1323 wpa_printf(MSG_INFO, "Error setting private key");
1324 return -1;
1325 }
1326
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001327 wpa_printf(MSG_DEBUG, "wolfSSL: cipher suites: %s",
1328 params->openssl_ciphers ? params->openssl_ciphers : "N/A");
Roshan Pius3a1667e2018-07-03 15:17:14 -07001329 if (params->openssl_ciphers &&
1330 wolfSSL_set_cipher_list(conn->ssl, params->openssl_ciphers) != 1) {
1331 wpa_printf(MSG_INFO,
1332 "wolfSSL: Failed to set cipher string '%s'",
1333 params->openssl_ciphers);
1334 return -1;
1335 }
1336
1337 tls_set_conn_flags(conn->ssl, params->flags);
1338
1339#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
1340 if (params->flags & TLS_CONN_REQUEST_OCSP) {
1341 if (wolfSSL_UseOCSPStapling(conn->ssl, WOLFSSL_CSR_OCSP,
1342 WOLFSSL_CSR_OCSP_USE_NONCE) !=
1343 SSL_SUCCESS)
1344 return -1;
Sunil Ravia04bd252022-05-02 22:54:18 -07001345 if (wolfSSL_EnableOCSPStapling(conn->ssl) != SSL_SUCCESS)
1346 return -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001347 }
1348#endif /* HAVE_CERTIFICATE_STATUS_REQUEST */
1349#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
1350 if (params->flags & TLS_CONN_REQUEST_OCSP) {
1351 if (wolfSSL_UseOCSPStaplingV2(conn->ssl,
1352 WOLFSSL_CSR2_OCSP_MULTI, 0) !=
1353 SSL_SUCCESS)
1354 return -1;
Sunil Ravia04bd252022-05-02 22:54:18 -07001355 if (wolfSSL_EnableOCSPStapling(conn->ssl) != SSL_SUCCESS)
1356 return -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001357 }
1358#endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */
1359#if !defined(HAVE_CERTIFICATE_STATUS_REQUEST) && \
1360 !defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
1361#ifdef HAVE_OCSP
1362 if (params->flags & TLS_CONN_REQUEST_OCSP)
1363 wolfSSL_CTX_EnableOCSP(ctx, 0);
1364#else /* HAVE_OCSP */
1365 if (params->flags & TLS_CONN_REQUIRE_OCSP) {
1366 wpa_printf(MSG_INFO,
1367 "wolfSSL: No OCSP support included - reject configuration");
1368 return -1;
1369 }
1370 if (params->flags & TLS_CONN_REQUEST_OCSP) {
1371 wpa_printf(MSG_DEBUG,
1372 "wolfSSL: No OCSP support included - allow optional OCSP case to continue");
1373 }
1374#endif /* HAVE_OCSP */
1375#endif /* !HAVE_CERTIFICATE_STATUS_REQUEST &&
1376 * !HAVE_CERTIFICATE_STATUS_REQUEST_V2 */
1377
1378 conn->flags = params->flags;
1379
1380 return 0;
1381}
1382
1383
1384static int tls_global_ca_cert(void *ssl_ctx, const char *ca_cert)
1385{
1386 WOLFSSL_CTX *ctx = ssl_ctx;
1387
1388 if (ca_cert) {
1389 if (wolfSSL_CTX_load_verify_locations(ctx, ca_cert, NULL) != 1)
1390 {
1391 wpa_printf(MSG_WARNING,
1392 "Failed to load root certificates");
1393 return -1;
1394 }
1395
1396 wpa_printf(MSG_DEBUG,
1397 "TLS: Trusted root certificate(s) loaded");
1398 }
1399
1400 return 0;
1401}
1402
1403
1404static int tls_global_client_cert(void *ssl_ctx, const char *client_cert)
1405{
1406 WOLFSSL_CTX *ctx = ssl_ctx;
1407
1408 if (!client_cert)
1409 return 0;
1410
1411 if (wolfSSL_CTX_use_certificate_chain_file_format(ctx, client_cert,
1412 SSL_FILETYPE_ASN1) !=
1413 SSL_SUCCESS &&
1414 wolfSSL_CTX_use_certificate_chain_file(ctx, client_cert) !=
1415 SSL_SUCCESS) {
1416 wpa_printf(MSG_INFO, "Failed to load client certificate");
1417 return -1;
1418 }
1419
1420 wpa_printf(MSG_DEBUG, "SSL: Loaded global client certificate: %s",
1421 client_cert);
1422
1423 return 0;
1424}
1425
1426
1427static int tls_global_private_key(void *ssl_ctx, const char *private_key,
1428 const char *private_key_passwd)
1429{
1430 WOLFSSL_CTX *ctx = ssl_ctx;
1431 char *passwd = NULL;
1432 int ret = 0;
1433
1434 if (!private_key)
1435 return 0;
1436
1437 if (private_key_passwd) {
1438 passwd = os_strdup(private_key_passwd);
1439 if (!passwd)
1440 return -1;
1441 }
1442
1443 wolfSSL_CTX_set_default_passwd_cb(ctx, tls_passwd_cb);
1444 wolfSSL_CTX_set_default_passwd_cb_userdata(ctx, passwd);
1445
1446 if (wolfSSL_CTX_use_PrivateKey_file(ctx, private_key,
1447 SSL_FILETYPE_ASN1) != 1 &&
1448 wolfSSL_CTX_use_PrivateKey_file(ctx, private_key,
1449 SSL_FILETYPE_PEM) != 1) {
1450 wpa_printf(MSG_INFO, "Failed to load private key");
1451 ret = -1;
1452 }
1453
1454 wpa_printf(MSG_DEBUG, "SSL: Loaded global private key");
1455
1456 os_free(passwd);
1457 wolfSSL_CTX_set_default_passwd_cb(ctx, NULL);
1458
1459 return ret;
1460}
1461
1462
Sunil Ravia04bd252022-05-02 22:54:18 -07001463static int tls_global_dh(void *ssl_ctx, const char *dh_file)
Roshan Pius3a1667e2018-07-03 15:17:14 -07001464{
1465 WOLFSSL_CTX *ctx = ssl_ctx;
1466
Roshan Pius3a1667e2018-07-03 15:17:14 -07001467 if (dh_file) {
1468 if (wolfSSL_CTX_SetTmpDH_file(ctx, dh_file, SSL_FILETYPE_PEM) <
1469 0) {
1470 wpa_printf(MSG_INFO,
1471 "SSL: global use DH PEM file failed");
1472 if (wolfSSL_CTX_SetTmpDH_file(ctx, dh_file,
1473 SSL_FILETYPE_ASN1) < 0) {
1474 wpa_printf(MSG_INFO,
1475 "SSL: global use DH DER file failed");
1476 return -1;
1477 }
1478 }
1479 wpa_printf(MSG_DEBUG, "SSL: global use DH file OK");
1480 return 0;
1481 }
1482
1483 return 0;
1484}
1485
1486
1487#ifdef HAVE_OCSP
1488
1489int ocsp_status_cb(void *unused, const char *url, int url_sz,
1490 unsigned char *request, int request_sz,
1491 unsigned char **response)
1492{
1493 size_t len;
1494
1495 (void) unused;
1496
1497 if (!url) {
1498 wpa_printf(MSG_DEBUG,
1499 "wolfSSL: OCSP status callback - no response configured");
1500 *response = NULL;
1501 return 0;
1502 }
1503
1504 *response = (unsigned char *) os_readfile(url, &len);
1505 if (!*response) {
1506 wpa_printf(MSG_DEBUG,
1507 "wolfSSL: OCSP status callback - could not read response file");
1508 return -1;
1509 }
1510 wpa_printf(MSG_DEBUG,
1511 "wolfSSL: OCSP status callback - send cached response");
1512 return len;
1513}
1514
1515
1516void ocsp_resp_free_cb(void *ocsp_stapling_response, unsigned char *response)
1517{
1518 os_free(response);
1519}
1520
1521#endif /* HAVE_OCSP */
1522
1523
1524int tls_global_set_params(void *tls_ctx,
1525 const struct tls_connection_params *params)
1526{
1527 wpa_printf(MSG_DEBUG, "SSL: global set params");
1528
Hai Shalom021b0b52019-04-10 11:17:58 -07001529 if (params->check_cert_subject)
1530 return -1; /* not yet supported */
1531
Roshan Pius3a1667e2018-07-03 15:17:14 -07001532 if (tls_global_ca_cert(tls_ctx, params->ca_cert) < 0) {
1533 wpa_printf(MSG_INFO, "SSL: Failed to load ca cert file '%s'",
1534 params->ca_cert);
1535 return -1;
1536 }
1537
1538 if (tls_global_client_cert(tls_ctx, params->client_cert) < 0) {
1539 wpa_printf(MSG_INFO,
1540 "SSL: Failed to load client cert file '%s'",
1541 params->client_cert);
1542 return -1;
1543 }
1544
1545 if (tls_global_private_key(tls_ctx, params->private_key,
1546 params->private_key_passwd) < 0) {
1547 wpa_printf(MSG_INFO,
1548 "SSL: Failed to load private key file '%s'",
1549 params->private_key);
1550 return -1;
1551 }
1552
Sunil Ravia04bd252022-05-02 22:54:18 -07001553 if (tls_global_dh(tls_ctx, params->dh_file) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001554 wpa_printf(MSG_INFO, "SSL: Failed to load DH file '%s'",
1555 params->dh_file);
1556 return -1;
1557 }
1558
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001559 wpa_printf(MSG_DEBUG, "wolfSSL: cipher suites: %s",
1560 params->openssl_ciphers ? params->openssl_ciphers : "N/A");
Roshan Pius3a1667e2018-07-03 15:17:14 -07001561 if (params->openssl_ciphers &&
1562 wolfSSL_CTX_set_cipher_list(tls_ctx,
1563 params->openssl_ciphers) != 1) {
1564 wpa_printf(MSG_INFO,
1565 "wolfSSL: Failed to set cipher string '%s'",
1566 params->openssl_ciphers);
1567 return -1;
1568 }
1569
Hai Shalom74f70d42019-02-11 14:42:39 -08001570 if (params->openssl_ecdh_curves) {
1571 wpa_printf(MSG_INFO,
1572 "wolfSSL: openssl_ecdh_curves not supported");
1573 return -1;
1574 }
1575
Roshan Pius3a1667e2018-07-03 15:17:14 -07001576#ifdef HAVE_SESSION_TICKET
1577 /* Session ticket is off by default - can't disable once on. */
1578 if (!(params->flags & TLS_CONN_DISABLE_SESSION_TICKET))
1579 wolfSSL_CTX_UseSessionTicket(tls_ctx);
1580#endif /* HAVE_SESSION_TICKET */
1581
1582#ifdef HAVE_OCSP
1583 if (params->ocsp_stapling_response) {
1584 wolfSSL_CTX_SetOCSP_OverrideURL(tls_ctx,
1585 params->ocsp_stapling_response);
1586 wolfSSL_CTX_SetOCSP_Cb(tls_ctx, ocsp_status_cb,
1587 ocsp_resp_free_cb, NULL);
1588 }
1589#endif /* HAVE_OCSP */
1590
1591 return 0;
1592}
1593
1594
Hai Shalom74f70d42019-02-11 14:42:39 -08001595int tls_global_set_verify(void *tls_ctx, int check_crl, int strict)
Roshan Pius3a1667e2018-07-03 15:17:14 -07001596{
1597 wpa_printf(MSG_DEBUG, "SSL: global set verify: %d", check_crl);
1598
1599 if (check_crl) {
1600 /* Hack to Enable CRLs. */
1601 wolfSSL_CTX_LoadCRLBuffer(tls_ctx, NULL, 0, SSL_FILETYPE_PEM);
1602 }
1603
1604 return 0;
1605}
1606
1607
1608int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
1609 int verify_peer, unsigned int flags,
1610 const u8 *session_ctx, size_t session_ctx_len)
1611{
Sunil Ravia04bd252022-05-02 22:54:18 -07001612 static int counter = 0;
1613 struct tls_context *context;
1614
Roshan Pius3a1667e2018-07-03 15:17:14 -07001615 if (!conn)
1616 return -1;
1617
1618 wpa_printf(MSG_DEBUG, "SSL: set verify: %d", verify_peer);
1619
1620 if (verify_peer) {
1621 conn->ca_cert_verify = 1;
1622 wolfSSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
1623 SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
1624 tls_verify_cb);
1625 } else {
1626 conn->ca_cert_verify = 0;
1627 wolfSSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
1628 }
1629
1630 wolfSSL_set_accept_state(conn->ssl);
1631
Sunil Ravia04bd252022-05-02 22:54:18 -07001632 context = wolfSSL_CTX_get_ex_data((WOLFSSL_CTX *) ssl_ctx, 0);
1633 if (context && context->tls_session_lifetime == 0) {
1634 /*
1635 * Set session id context to a unique value to make sure
1636 * session resumption cannot be used either through session
1637 * caching or TLS ticket extension.
1638 */
1639 counter++;
1640 wolfSSL_set_session_id_context(conn->ssl,
1641 (const unsigned char *) &counter,
1642 sizeof(counter));
1643 } else {
1644 wolfSSL_set_session_id_context(conn->ssl, session_ctx,
1645 session_ctx_len);
1646 }
1647
Roshan Pius3a1667e2018-07-03 15:17:14 -07001648 /* TODO: do we need to fake a session like OpenSSL does here? */
1649
1650 return 0;
1651}
1652
1653
1654static struct wpabuf * wolfssl_handshake(struct tls_connection *conn,
1655 const struct wpabuf *in_data,
1656 int server)
1657{
1658 int res;
1659
1660 wolfssl_reset_out_data(&conn->output);
1661
1662 /* Initiate TLS handshake or continue the existing handshake */
1663 if (server) {
1664 wolfSSL_set_accept_state(conn->ssl);
1665 res = wolfSSL_accept(conn->ssl);
1666 wpa_printf(MSG_DEBUG, "SSL: wolfSSL_accept: %d", res);
1667 } else {
1668 wolfSSL_set_connect_state(conn->ssl);
1669 res = wolfSSL_connect(conn->ssl);
1670 wpa_printf(MSG_DEBUG, "SSL: wolfSSL_connect: %d", res);
1671 }
1672
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001673 if (res != WOLFSSL_SUCCESS) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001674 int err = wolfSSL_get_error(conn->ssl, res);
1675
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001676 if (err == WOLFSSL_ERROR_NONE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001677 wpa_printf(MSG_DEBUG,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001678 "SSL: %s - WOLFSSL_ERROR_NONE (%d)",
1679 server ? "wolfSSL_accept" :
1680 "wolfSSL_connect", res);
1681 } else if (err == WOLFSSL_ERROR_WANT_READ) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001682 wpa_printf(MSG_DEBUG,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001683 "SSL: %s - want more data",
1684 server ? "wolfSSL_accept" :
1685 "wolfSSL_connect");
1686 } else if (err == WOLFSSL_ERROR_WANT_WRITE) {
1687 wpa_printf(MSG_DEBUG,
1688 "SSL: %s - want to write",
1689 server ? "wolfSSL_accept" :
1690 "wolfSSL_connect");
Roshan Pius3a1667e2018-07-03 15:17:14 -07001691 } else {
1692 char msg[80];
1693
1694 wpa_printf(MSG_DEBUG,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001695 "SSL: %s - failed %s",
1696 server ? "wolfSSL_accept" :
1697 "wolfSSL_connect",
Roshan Pius3a1667e2018-07-03 15:17:14 -07001698 wolfSSL_ERR_error_string(err, msg));
1699 conn->failed++;
1700 }
1701 }
1702
1703 return conn->output.out_data;
1704}
1705
1706
1707static struct wpabuf * wolfssl_get_appl_data(struct tls_connection *conn,
1708 size_t max_len)
1709{
1710 int res;
1711 struct wpabuf *appl_data = wpabuf_alloc(max_len + 100);
1712
1713 if (!appl_data)
1714 return NULL;
1715
1716 res = wolfSSL_read(conn->ssl, wpabuf_mhead(appl_data),
1717 wpabuf_size(appl_data));
1718 if (res < 0) {
1719 int err = wolfSSL_get_error(conn->ssl, res);
1720
1721 if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
1722 wpa_printf(MSG_DEBUG,
1723 "SSL: No Application Data included");
1724 } else {
1725 char msg[80];
1726
1727 wpa_printf(MSG_DEBUG,
1728 "Failed to read possible Application Data %s",
1729 wolfSSL_ERR_error_string(err, msg));
1730 }
1731
1732 wpabuf_free(appl_data);
1733 return NULL;
1734 }
1735
1736 wpabuf_put(appl_data, res);
1737 wpa_hexdump_buf_key(MSG_MSGDUMP,
1738 "SSL: Application Data in Finished message",
1739 appl_data);
1740 return appl_data;
1741}
1742
1743
1744static struct wpabuf *
1745wolfssl_connection_handshake(struct tls_connection *conn,
1746 const struct wpabuf *in_data,
1747 struct wpabuf **appl_data, int server)
1748{
1749 struct wpabuf *out_data;
1750
1751 wolfssl_reset_in_data(&conn->input, in_data);
1752
1753 if (appl_data)
1754 *appl_data = NULL;
1755
1756 out_data = wolfssl_handshake(conn, in_data, server);
1757 if (!out_data)
1758 return NULL;
1759
1760 if (wolfSSL_is_init_finished(conn->ssl)) {
1761 wpa_printf(MSG_DEBUG,
1762 "wolfSSL: Handshake finished - resumed=%d",
1763 tls_connection_resumed(NULL, conn));
1764 if (appl_data && in_data)
1765 *appl_data = wolfssl_get_appl_data(conn,
1766 wpabuf_len(in_data));
1767 }
1768
1769 return out_data;
1770}
1771
1772
1773struct wpabuf * tls_connection_handshake(void *tls_ctx,
1774 struct tls_connection *conn,
1775 const struct wpabuf *in_data,
1776 struct wpabuf **appl_data)
1777{
1778 return wolfssl_connection_handshake(conn, in_data, appl_data, 0);
1779}
1780
1781
1782struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
1783 struct tls_connection *conn,
1784 const struct wpabuf *in_data,
1785 struct wpabuf **appl_data)
1786{
1787 return wolfssl_connection_handshake(conn, in_data, appl_data, 1);
1788}
1789
1790
1791struct wpabuf * tls_connection_encrypt(void *tls_ctx,
1792 struct tls_connection *conn,
1793 const struct wpabuf *in_data)
1794{
1795 int res;
1796
1797 if (!conn)
1798 return NULL;
1799
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001800 wpa_printf(MSG_DEBUG, "SSL: encrypt: %zu bytes", wpabuf_len(in_data));
Roshan Pius3a1667e2018-07-03 15:17:14 -07001801
1802 wolfssl_reset_out_data(&conn->output);
1803
1804 res = wolfSSL_write(conn->ssl, wpabuf_head(in_data),
1805 wpabuf_len(in_data));
1806 if (res < 0) {
1807 int err = wolfSSL_get_error(conn->ssl, res);
1808 char msg[80];
1809
1810 wpa_printf(MSG_INFO, "Encryption failed - SSL_write: %s",
1811 wolfSSL_ERR_error_string(err, msg));
1812 return NULL;
1813 }
1814
1815 return conn->output.out_data;
1816}
1817
1818
1819struct wpabuf * tls_connection_decrypt(void *tls_ctx,
1820 struct tls_connection *conn,
1821 const struct wpabuf *in_data)
1822{
1823 int res;
1824 struct wpabuf *buf;
1825
1826 if (!conn)
1827 return NULL;
1828
1829 wpa_printf(MSG_DEBUG, "SSL: decrypt");
1830
1831 wolfssl_reset_in_data(&conn->input, in_data);
1832
1833 /* Read decrypted data for further processing */
1834 /*
1835 * Even though we try to disable TLS compression, it is possible that
1836 * this cannot be done with all TLS libraries. Add extra buffer space
1837 * to handle the possibility of the decrypted data being longer than
1838 * input data.
1839 */
1840 buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
1841 if (!buf)
1842 return NULL;
1843 res = wolfSSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf));
1844 if (res < 0) {
1845 wpa_printf(MSG_INFO, "Decryption failed - SSL_read");
1846 wpabuf_free(buf);
1847 return NULL;
1848 }
1849 wpabuf_put(buf, res);
1850
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001851 wpa_printf(MSG_DEBUG, "SSL: decrypt: %zu bytes", wpabuf_len(buf));
Roshan Pius3a1667e2018-07-03 15:17:14 -07001852
1853 return buf;
1854}
1855
1856
1857int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
1858{
1859 return conn ? wolfSSL_session_reused(conn->ssl) : 0;
1860}
1861
1862
1863int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
1864 u8 *ciphers)
1865{
1866 char buf[128], *pos, *end;
1867 u8 *c;
1868 int ret;
1869
1870 if (!conn || !conn->ssl || !ciphers)
1871 return -1;
1872
1873 buf[0] = '\0';
1874 pos = buf;
1875 end = pos + sizeof(buf);
1876
1877 c = ciphers;
1878 while (*c != TLS_CIPHER_NONE) {
1879 const char *suite;
1880
1881 switch (*c) {
1882 case TLS_CIPHER_RC4_SHA:
1883 suite = "RC4-SHA";
1884 break;
1885 case TLS_CIPHER_AES128_SHA:
1886 suite = "AES128-SHA";
1887 break;
1888 case TLS_CIPHER_RSA_DHE_AES128_SHA:
1889 suite = "DHE-RSA-AES128-SHA";
1890 break;
1891 case TLS_CIPHER_ANON_DH_AES128_SHA:
1892 suite = "ADH-AES128-SHA";
1893 break;
1894 case TLS_CIPHER_RSA_DHE_AES256_SHA:
1895 suite = "DHE-RSA-AES256-SHA";
1896 break;
1897 case TLS_CIPHER_AES256_SHA:
1898 suite = "AES256-SHA";
1899 break;
1900 default:
1901 wpa_printf(MSG_DEBUG,
1902 "TLS: Unsupported cipher selection: %d", *c);
1903 return -1;
1904 }
1905 ret = os_snprintf(pos, end - pos, ":%s", suite);
1906 if (os_snprintf_error(end - pos, ret))
1907 break;
1908 pos += ret;
1909
1910 c++;
1911 }
1912
1913 wpa_printf(MSG_DEBUG, "wolfSSL: cipher suites: %s", buf + 1);
1914
1915 if (wolfSSL_set_cipher_list(conn->ssl, buf + 1) != 1) {
1916 wpa_printf(MSG_DEBUG, "Cipher suite configuration failed");
1917 return -1;
1918 }
1919
1920 return 0;
1921}
1922
1923
1924int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
1925 char *buf, size_t buflen)
1926{
1927 WOLFSSL_CIPHER *cipher;
1928 const char *name;
1929
1930 if (!conn || !conn->ssl)
1931 return -1;
1932
1933 cipher = wolfSSL_get_current_cipher(conn->ssl);
1934 if (!cipher)
1935 return -1;
1936
1937 name = wolfSSL_CIPHER_get_name(cipher);
1938 if (!name)
1939 return -1;
1940
1941 if (os_strcmp(name, "SSL_RSA_WITH_RC4_128_SHA") == 0)
1942 os_strlcpy(buf, "RC4-SHA", buflen);
1943 else if (os_strcmp(name, "TLS_RSA_WITH_AES_128_CBC_SHA") == 0)
1944 os_strlcpy(buf, "AES128-SHA", buflen);
1945 else if (os_strcmp(name, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA") == 0)
1946 os_strlcpy(buf, "DHE-RSA-AES128-SHA", buflen);
1947 else if (os_strcmp(name, "TLS_DH_anon_WITH_AES_128_CBC_SHA") == 0)
1948 os_strlcpy(buf, "ADH-AES128-SHA", buflen);
1949 else if (os_strcmp(name, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA") == 0)
1950 os_strlcpy(buf, "DHE-RSA-AES256-SHA", buflen);
1951 else if (os_strcmp(name, "TLS_RSA_WITH_AES_256_CBC_SHA") == 0)
1952 os_strlcpy(buf, "AES256-SHA", buflen);
1953 else
1954 os_strlcpy(buf, name, buflen);
1955
1956 return 0;
1957}
1958
1959
1960int tls_connection_enable_workaround(void *tls_ctx,
1961 struct tls_connection *conn)
1962{
1963 /* no empty fragments in wolfSSL for now */
1964 return 0;
1965}
1966
1967
1968int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
1969{
1970 if (!conn)
1971 return -1;
1972
1973 return conn->failed;
1974}
1975
1976
1977int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
1978{
1979 if (!conn)
1980 return -1;
1981
1982 /* TODO: this is not incremented anywhere */
1983 return conn->read_alerts;
1984}
1985
1986
1987int tls_connection_get_write_alerts(void *tls_ctx,
1988 struct tls_connection *conn)
1989{
1990 if (!conn)
1991 return -1;
1992
1993 /* TODO: this is not incremented anywhere */
1994 return conn->write_alerts;
1995}
1996
1997
1998
1999int tls_get_library_version(char *buf, size_t buf_len)
2000{
2001 return os_snprintf(buf, buf_len, "wolfSSL build=%s run=%s",
2002 WOLFSSL_VERSION, wolfSSL_lib_version());
2003}
2004
2005int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
2006 char *buf, size_t buflen)
2007{
2008 const char *name;
2009
2010 if (!conn || !conn->ssl)
2011 return -1;
2012
2013 name = wolfSSL_get_version(conn->ssl);
2014 if (!name)
2015 return -1;
2016
2017 os_strlcpy(buf, name, buflen);
2018 return 0;
2019}
2020
2021
2022int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
2023 struct tls_random *keys)
2024{
2025 WOLFSSL *ssl;
2026
2027 if (!conn || !keys)
2028 return -1;
2029 ssl = conn->ssl;
2030 if (!ssl)
2031 return -1;
2032
2033 os_memset(keys, 0, sizeof(*keys));
2034 keys->client_random = conn->client_random;
2035 keys->client_random_len = wolfSSL_get_client_random(
2036 ssl, conn->client_random, sizeof(conn->client_random));
2037 keys->server_random = conn->server_random;
2038 keys->server_random_len = wolfSSL_get_server_random(
2039 ssl, conn->server_random, sizeof(conn->server_random));
2040
2041 return 0;
2042}
2043
2044
2045int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
Hai Shalom021b0b52019-04-10 11:17:58 -07002046 const char *label, const u8 *context,
2047 size_t context_len, u8 *out, size_t out_len)
Roshan Pius3a1667e2018-07-03 15:17:14 -07002048{
Sunil Ravia04bd252022-05-02 22:54:18 -07002049 if (!conn)
Hai Shalom021b0b52019-04-10 11:17:58 -07002050 return -1;
Sunil Ravia04bd252022-05-02 22:54:18 -07002051#if LIBWOLFSSL_VERSION_HEX >= 0x04007000
2052 if (wolfSSL_export_keying_material(conn->ssl, out, out_len,
2053 label, os_strlen(label),
2054 context, context_len,
2055 context != NULL) != WOLFSSL_SUCCESS)
Roshan Pius3a1667e2018-07-03 15:17:14 -07002056 return -1;
2057 return 0;
Sunil Ravia04bd252022-05-02 22:54:18 -07002058#else
2059 if (context ||
2060 wolfSSL_make_eap_keys(conn->ssl, out, out_len, label) != 0)
2061 return -1;
2062#endif
2063 return 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002064}
2065
2066
2067#define SEED_LEN (RAN_LEN + RAN_LEN)
2068
2069int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
2070 u8 *out, size_t out_len)
2071{
2072 byte seed[SEED_LEN];
2073 int ret = -1;
2074 WOLFSSL *ssl;
2075 byte *tmp_out;
2076 byte *_out;
2077 int skip = 0;
2078 byte *master_key;
2079 unsigned int master_key_len;
2080 byte *server_random;
2081 unsigned int server_len;
2082 byte *client_random;
2083 unsigned int client_len;
2084
2085 if (!conn || !conn->ssl)
2086 return -1;
2087 ssl = conn->ssl;
2088
2089 skip = 2 * (wolfSSL_GetKeySize(ssl) + wolfSSL_GetHmacSize(ssl) +
2090 wolfSSL_GetIVSize(ssl));
2091
2092 tmp_out = os_malloc(skip + out_len);
2093 if (!tmp_out)
2094 return -1;
2095 _out = tmp_out;
2096
2097 wolfSSL_get_keys(ssl, &master_key, &master_key_len, &server_random,
2098 &server_len, &client_random, &client_len);
2099 os_memcpy(seed, server_random, RAN_LEN);
2100 os_memcpy(seed + RAN_LEN, client_random, RAN_LEN);
2101
2102 if (wolfSSL_GetVersion(ssl) == WOLFSSL_TLSV1_2) {
2103 tls_prf_sha256(master_key, master_key_len,
2104 "key expansion", seed, sizeof(seed),
2105 _out, skip + out_len);
2106 ret = 0;
2107 } else {
Sunil Ravia04bd252022-05-02 22:54:18 -07002108#ifdef CONFIG_FIPS
2109 wpa_printf(MSG_ERROR,
2110 "wolfSSL: Can't use sha1_md5 in FIPS build");
2111 ret = -1;
2112#else /* CONFIG_FIPS */
Roshan Pius3a1667e2018-07-03 15:17:14 -07002113 ret = tls_prf_sha1_md5(master_key, master_key_len,
2114 "key expansion", seed, sizeof(seed),
2115 _out, skip + out_len);
Sunil Ravia04bd252022-05-02 22:54:18 -07002116#endif /* CONFIG_FIPS */
Roshan Pius3a1667e2018-07-03 15:17:14 -07002117 }
2118
Hai Shalom81f62d82019-07-22 12:10:00 -07002119 forced_memzero(master_key, master_key_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002120 if (ret == 0)
2121 os_memcpy(out, _out + skip, out_len);
2122 bin_clear_free(tmp_out, skip + out_len);
2123
2124 return ret;
2125}
2126
2127
2128#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
2129
2130int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
2131 int ext_type, const u8 *data,
2132 size_t data_len)
2133{
2134 (void) ssl_ctx;
2135
2136 if (!conn || !conn->ssl || ext_type != 35)
2137 return -1;
2138
2139 if (wolfSSL_set_SessionTicket(conn->ssl, data,
2140 (unsigned int) data_len) != 1)
2141 return -1;
2142
2143 return 0;
2144}
2145
2146
2147static int tls_sess_sec_cb(WOLFSSL *s, void *secret, int *secret_len, void *arg)
2148{
2149 struct tls_connection *conn = arg;
2150 int ret;
2151 unsigned char client_random[RAN_LEN];
2152 unsigned char server_random[RAN_LEN];
2153 word32 ticket_len = sizeof(conn->session_ticket);
2154
2155 if (!conn || !conn->session_ticket_cb)
2156 return 1;
2157
2158 if (wolfSSL_get_client_random(s, client_random,
2159 sizeof(client_random)) == 0 ||
2160 wolfSSL_get_server_random(s, server_random,
2161 sizeof(server_random)) == 0 ||
2162 wolfSSL_get_SessionTicket(s, conn->session_ticket,
2163 &ticket_len) != 1)
2164 return 1;
2165
2166 if (ticket_len == 0)
2167 return 0;
2168
2169 ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
2170 conn->session_ticket, ticket_len,
2171 client_random, server_random, secret);
2172 if (ret <= 0)
2173 return 1;
2174
2175 *secret_len = SECRET_LEN;
2176 return 0;
2177}
2178
2179#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
2180
2181
2182int tls_connection_set_session_ticket_cb(void *tls_ctx,
2183 struct tls_connection *conn,
2184 tls_session_ticket_cb cb,
2185 void *ctx)
2186{
2187#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
2188 conn->session_ticket_cb = cb;
2189 conn->session_ticket_cb_ctx = ctx;
2190
2191 if (cb) {
2192 if (wolfSSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
2193 conn) != 1)
2194 return -1;
2195 } else {
2196 if (wolfSSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
2197 return -1;
2198 }
2199
2200 return 0;
2201#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
2202 return -1;
2203#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
2204}
2205
2206
2207void tls_connection_set_success_data_resumed(struct tls_connection *conn)
2208{
2209 wpa_printf(MSG_DEBUG,
2210 "wolfSSL: Success data accepted for resumed session");
2211}
2212
2213
2214void tls_connection_remove_session(struct tls_connection *conn)
2215{
2216 WOLFSSL_SESSION *sess;
2217
2218 sess = wolfSSL_get_session(conn->ssl);
2219 if (!sess)
2220 return;
2221
2222 wolfSSL_SSL_SESSION_set_timeout(sess, 0);
2223 wpa_printf(MSG_DEBUG,
2224 "wolfSSL: Removed cached session to disable session resumption");
2225}
2226
2227
Sunil Ravia04bd252022-05-02 22:54:18 -07002228int tls_get_tls_unique(struct tls_connection *conn, u8 *buf, size_t max_len)
2229{
2230 size_t len;
2231 int reused;
2232
2233 reused = wolfSSL_session_reused(conn->ssl);
2234 if ((wolfSSL_is_server(conn->ssl) && !reused) ||
2235 (!wolfSSL_is_server(conn->ssl) && reused))
2236 len = wolfSSL_get_peer_finished(conn->ssl, buf, max_len);
2237 else
2238 len = wolfSSL_get_finished(conn->ssl, buf, max_len);
2239
2240 if (len == 0 || len > max_len)
2241 return -1;
2242
2243 return len;
2244}
2245
2246
2247u16 tls_connection_get_cipher_suite(struct tls_connection *conn)
2248{
2249 return (u16) wolfSSL_get_current_cipher_suite(conn->ssl);
2250}
2251
2252
2253const char * tls_connection_get_peer_subject(struct tls_connection *conn)
2254{
2255 if (conn)
2256 return conn->peer_subject;
2257 return NULL;
2258}
2259
2260
Roshan Pius3a1667e2018-07-03 15:17:14 -07002261void tls_connection_set_success_data(struct tls_connection *conn,
2262 struct wpabuf *data)
2263{
2264 WOLFSSL_SESSION *sess;
2265 struct wpabuf *old;
2266
2267 wpa_printf(MSG_DEBUG, "wolfSSL: Set success data");
2268
2269 sess = wolfSSL_get_session(conn->ssl);
2270 if (!sess) {
2271 wpa_printf(MSG_DEBUG,
2272 "wolfSSL: No session found for success data");
2273 goto fail;
2274 }
2275
2276 old = wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
2277 if (old) {
2278 wpa_printf(MSG_DEBUG, "wolfSSL: Replacing old success data %p",
2279 old);
2280 wpabuf_free(old);
2281 }
2282 if (wolfSSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1)
2283 goto fail;
2284
2285 wpa_printf(MSG_DEBUG, "wolfSSL: Stored success data %p", data);
2286 conn->success_data = 1;
2287 return;
2288
2289fail:
2290 wpa_printf(MSG_INFO, "wolfSSL: Failed to store success data");
2291 wpabuf_free(data);
2292}
2293
2294
2295const struct wpabuf *
2296tls_connection_get_success_data(struct tls_connection *conn)
2297{
2298 WOLFSSL_SESSION *sess;
2299
2300 wpa_printf(MSG_DEBUG, "wolfSSL: Get success data");
2301
2302 sess = wolfSSL_get_session(conn->ssl);
2303 if (!sess)
2304 return NULL;
2305 return wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
2306}
Sunil Ravia04bd252022-05-02 22:54:18 -07002307
2308
2309bool tls_connection_get_own_cert_used(struct tls_connection *conn)
2310{
2311 if (conn)
2312 return wolfSSL_get_certificate(conn->ssl) != NULL;
2313 return false;
2314}