2 * WPA Supplicant / SSL/TLS interface functions for openssl
3 * Copyright (c) 2004-2006, Jouni Malinen <jkmaline@cc.hut.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
19 #include <gnutls/gnutls.h>
20 #include <gnutls/x509.h>
27 * It looks like gnutls does not provide access to client/server_random and
28 * master_key. This is somewhat unfortunate since these are needed for key
29 * derivation in EAP-{TLS,TTLS,PEAP,FAST}. Workaround for now is a horrible
30 * hack that copies the gnutls_session_int definition from gnutls_int.h so that
31 * we can get the needed information.
35 #define TLS_RANDOM_SIZE 32
36 #define TLS_MASTER_SIZE 48
37 typedef unsigned char opaque;
43 gnutls_connection_end_t entity;
44 gnutls_kx_algorithm_t kx_algorithm;
45 gnutls_cipher_algorithm_t read_bulk_cipher_algorithm;
46 gnutls_mac_algorithm_t read_mac_algorithm;
47 gnutls_compression_method_t read_compression_algorithm;
48 gnutls_cipher_algorithm_t write_bulk_cipher_algorithm;
49 gnutls_mac_algorithm_t write_mac_algorithm;
50 gnutls_compression_method_t write_compression_algorithm;
51 cipher_suite_st current_cipher_suite;
52 opaque master_secret[TLS_MASTER_SIZE];
53 opaque client_random[TLS_RANDOM_SIZE];
54 opaque server_random[TLS_RANDOM_SIZE];
55 /* followed by stuff we are not interested in */
56 } security_parameters_st;
58 struct gnutls_session_int {
59 security_parameters_st security_parameters;
60 /* followed by things we are not interested in */
63 static int tls_gnutls_ref_count = 0;
65 struct tls_connection {
66 gnutls_session session;
67 char *subject_match, *altsubject_match;
68 int read_alerts, write_alerts, failed;
70 u8 *pre_shared_secret;
71 size_t pre_shared_secret_len;
75 u8 *push_buf, *pull_buf, *pull_buf_offset;
76 size_t push_buf_len, pull_buf_len;
78 gnutls_certificate_credentials_t xcred;
82 static void tls_log_func(int level, const char *msg)
85 if (level == 6 || level == 7) {
86 /* These levels seem to be mostly I/O debug and msg dumps */
95 while (*pos != '\0') {
102 wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
103 "gnutls<%d> %s", level, s);
108 extern int wpa_debug_show_keys;
110 void * tls_init(const struct tls_config *conf)
112 /* Because of the horrible hack to get master_secret and client/server
113 * random, we need to make sure that the gnutls version is something
114 * that is expected to have same structure definition for the session
117 const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", NULL };
120 if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0)
122 tls_gnutls_ref_count++;
124 ver = gnutls_check_version(NULL);
127 wpa_printf(MSG_DEBUG, "%s - gnutls version %s", __func__, ver);
128 for (i = 0; ok_ver[i]; i++) {
129 if (strcmp(ok_ver[i], ver) == 0)
132 if (ok_ver[i] == NULL) {
133 wpa_printf(MSG_INFO, "Untested gnutls version %s - this needs "
134 "to be tested and enabled in tls_gnutls.c", ver);
138 gnutls_global_set_log_function(tls_log_func);
139 if (wpa_debug_show_keys)
140 gnutls_global_set_log_level(11);
145 void tls_deinit(void *ssl_ctx)
147 tls_gnutls_ref_count--;
148 if (tls_gnutls_ref_count == 0)
149 gnutls_global_deinit();
153 int tls_get_errors(void *ssl_ctx)
159 static ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf,
162 struct tls_connection *conn = (struct tls_connection *) ptr;
164 if (conn->pull_buf == NULL) {
169 end = conn->pull_buf + conn->pull_buf_len;
170 if (end - conn->pull_buf_offset < len)
171 len = end - conn->pull_buf_offset;
172 memcpy(buf, conn->pull_buf_offset, len);
173 conn->pull_buf_offset += len;
174 if (conn->pull_buf_offset == end) {
175 wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
176 free(conn->pull_buf);
177 conn->pull_buf = conn->pull_buf_offset = NULL;
178 conn->pull_buf_len = 0;
180 wpa_printf(MSG_DEBUG, "%s - %d bytes remaining in pull_buf",
181 __func__, end - conn->pull_buf_offset);
187 static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
190 struct tls_connection *conn = (struct tls_connection *) ptr;
193 nbuf = realloc(conn->push_buf, conn->push_buf_len + len);
198 memcpy(nbuf + conn->push_buf_len, buf, len);
199 conn->push_buf = nbuf;
200 conn->push_buf_len += len;
206 struct tls_connection * tls_connection_init(void *ssl_ctx)
208 struct tls_connection *conn;
209 const int cert_types[2] = { GNUTLS_CRT_X509, 0 };
210 const int protos[2] = { GNUTLS_TLS1, 0 };
213 conn = malloc(sizeof(*conn));
216 memset(conn, 0, sizeof(*conn));
217 if (gnutls_init(&conn->session, GNUTLS_CLIENT) < 0) {
218 wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
224 gnutls_set_default_priority(conn->session);
225 gnutls_certificate_type_set_priority(conn->session, cert_types);
226 gnutls_protocol_set_priority(conn->session, protos);
228 gnutls_transport_set_pull_function(conn->session, tls_pull_func);
229 gnutls_transport_set_push_function(conn->session, tls_push_func);
230 gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn);
232 gnutls_certificate_allocate_credentials(&conn->xcred);
238 void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
242 gnutls_certificate_free_credentials(conn->xcred);
243 gnutls_deinit(conn->session);
244 free(conn->pre_shared_secret);
245 free(conn->subject_match);
246 free(conn->altsubject_match);
247 free(conn->push_buf);
248 free(conn->pull_buf);
253 int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
255 return conn ? conn->established : 0;
259 int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
264 /* Shutdown previous TLS connection without notifying the peer
265 * because the connection was already terminated in practice
266 * and "close notify" shutdown alert would confuse AS. */
267 gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
268 free(conn->push_buf);
269 conn->push_buf = NULL;
270 conn->push_buf_len = 0;
271 conn->established = 0;
272 /* TODO: what to do trigger new handshake for re-auth? */
278 static int tls_match_altsubject(X509 *cert, const char *match)
286 ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
288 for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
289 gen = sk_GENERAL_NAME_value(ext, i);
302 wpa_printf(MSG_DEBUG, "TLS: altSubjectName: "
303 "unsupported type=%d", gen->type);
310 wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s",
311 field, gen->d.ia5->data);
312 len = strlen(field) + 1 + strlen((char *) gen->d.ia5->data) +
317 snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data);
318 if (strstr(tmp, match))
329 static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
335 struct tls_connection *conn;
336 char *match, *altmatch;
338 err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
339 err = X509_STORE_CTX_get_error(x509_ctx);
340 depth = X509_STORE_CTX_get_error_depth(x509_ctx);
341 ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
342 SSL_get_ex_data_X509_STORE_CTX_idx());
343 X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
345 conn = SSL_get_app_data(ssl);
346 match = conn ? conn->subject_match : NULL;
347 altmatch = conn ? conn->altsubject_match : NULL;
350 wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
351 " error %d (%s) depth %d for '%s'", err,
352 X509_verify_cert_error_string(err), depth, buf);
354 wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - "
355 "preverify_ok=%d err=%d (%s) depth=%d buf='%s'",
357 X509_verify_cert_error_string(err), depth, buf);
358 if (depth == 0 && match && strstr(buf, match) == NULL) {
359 wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
360 "match with '%s'", buf, match);
362 } else if (depth == 0 && altmatch &&
363 !tls_match_altsubject(err_cert, altmatch)) {
364 wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
365 "'%s' not found", altmatch);
375 int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
376 const struct tls_connection_params *params)
380 if (conn == NULL || params == NULL)
383 free(conn->subject_match);
384 conn->subject_match = NULL;
385 if (params->subject_match) {
386 conn->subject_match = strdup(params->subject_match);
387 if (conn->subject_match == NULL)
391 free(conn->altsubject_match);
392 conn->altsubject_match = NULL;
393 if (params->altsubject_match) {
394 conn->altsubject_match = strdup(params->altsubject_match);
395 if (conn->altsubject_match == NULL)
399 /* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
400 * to force peer validation(?) */
402 if (params->ca_cert) {
403 conn->verify_peer = 1;
404 ret = gnutls_certificate_set_x509_trust_file(
405 conn->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
407 wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
408 "in PEM format: %s", params->ca_cert,
409 gnutls_strerror(ret));
410 ret = gnutls_certificate_set_x509_trust_file(
411 conn->xcred, params->ca_cert,
412 GNUTLS_X509_FMT_DER);
414 wpa_printf(MSG_DEBUG, "Failed to read CA cert "
415 "'%s' in DER format: %s",
417 gnutls_strerror(ret));
422 if (params->client_cert && params->private_key) {
423 /* TODO: private_key_passwd? */
424 ret = gnutls_certificate_set_x509_key_file(
425 conn->xcred, params->client_cert, params->private_key,
426 GNUTLS_X509_FMT_PEM);
428 wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
429 "in PEM format: %s", gnutls_strerror(ret));
430 ret = gnutls_certificate_set_x509_key_file(
431 conn->xcred, params->client_cert,
432 params->private_key, GNUTLS_X509_FMT_DER);
434 wpa_printf(MSG_DEBUG, "Failed to read client "
435 "cert/key in DER format: %s",
436 gnutls_strerror(ret));
442 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
445 wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
446 gnutls_strerror(ret));
453 int tls_global_ca_cert(void *_ssl_ctx, const char *ca_cert)
460 int tls_global_set_verify(void *ssl_ctx, int check_crl)
467 int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
479 int tls_global_client_cert(void *_ssl_ctx, const char *client_cert)
486 int tls_global_private_key(void *_ssl_ctx, const char *private_key,
487 const char *private_key_passwd)
494 int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
495 struct tls_keys *keys)
497 security_parameters_st *sec;
499 if (conn == NULL || conn->session == NULL || keys == NULL)
502 memset(keys, 0, sizeof(*keys));
503 sec = &conn->session->security_parameters;
504 keys->master_key = sec->master_secret;
505 keys->master_key_len = TLS_MASTER_SIZE;
506 keys->client_random = sec->client_random;
507 keys->client_random_len = TLS_RANDOM_SIZE;
508 keys->server_random = sec->server_random;
509 keys->server_random_len = TLS_RANDOM_SIZE;
515 static int tls_connection_verify_peer(struct tls_connection *conn)
517 unsigned int status, num_certs, i;
519 const gnutls_datum_t *certs;
520 gnutls_x509_crt_t cert;
522 if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) {
523 wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
524 "certificate chain");
528 if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
529 wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
533 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
534 wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
539 if (status & GNUTLS_CERT_REVOKED) {
540 wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
546 certs = gnutls_certificate_get_peers(conn->session, &num_certs);
548 wpa_printf(MSG_INFO, "TLS: No peer certificate chain "
553 for (i = 0; i < num_certs; i++) {
556 if (gnutls_x509_crt_init(&cert) < 0) {
557 wpa_printf(MSG_INFO, "TLS: Certificate initialization "
562 if (gnutls_x509_crt_import(cert, &certs[i],
563 GNUTLS_X509_FMT_DER) < 0) {
564 wpa_printf(MSG_INFO, "TLS: Could not parse peer "
565 "certificate %d/%d", i + 1, num_certs);
566 gnutls_x509_crt_deinit(cert);
570 gnutls_x509_crt_get_dn(cert, NULL, &len);
572 buf = malloc(len + 1);
574 buf[0] = buf[len] = '\0';
575 gnutls_x509_crt_get_dn(cert, buf, &len);
577 wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
578 i + 1, num_certs, buf);
581 /* TODO: validate subject_match and altsubject_match */
586 if (gnutls_x509_crt_get_expiration_time(cert) < now ||
587 gnutls_x509_crt_get_activation_time(cert) > now) {
588 wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
589 "not valid at this time",
591 gnutls_x509_crt_deinit(cert);
595 gnutls_x509_crt_deinit(cert);
602 u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
603 const u8 *in_data, size_t in_len,
609 if (in_data && in_len) {
610 if (conn->pull_buf) {
611 wpa_printf(MSG_DEBUG, "%s - %d bytes remaining in "
612 "pull_buf", __func__, conn->pull_buf_len);
613 free(conn->pull_buf);
615 conn->pull_buf = malloc(in_len);
616 if (conn->pull_buf == NULL)
618 memcpy(conn->pull_buf, in_data, in_len);
619 conn->pull_buf_offset = conn->pull_buf;
620 conn->pull_buf_len = in_len;
623 ret = gnutls_handshake(conn->session);
628 case GNUTLS_E_FATAL_ALERT_RECEIVED:
629 wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
630 __func__, gnutls_alert_get_name(
631 gnutls_alert_get(conn->session)));
635 wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
636 "-> %s", __func__, gnutls_strerror(ret));
640 wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
641 if (conn->verify_peer && tls_connection_verify_peer(conn)) {
642 wpa_printf(MSG_INFO, "TLS: Peer certificate chain "
643 "failed validation");
647 conn->established = 1;
648 if (conn->push_buf == NULL) {
649 /* Need to return something to get final TLS ACK. */
650 conn->push_buf = malloc(1);
654 out_data = conn->push_buf;
655 *out_len = conn->push_buf_len;
656 conn->push_buf = NULL;
657 conn->push_buf_len = 0;
662 u8 * tls_connection_server_handshake(void *ssl_ctx,
663 struct tls_connection *conn,
664 const u8 *in_data, size_t in_len,
672 int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn,
673 const u8 *in_data, size_t in_len,
674 u8 *out_data, size_t out_len)
677 res = gnutls_record_send(conn->session, in_data, in_len);
678 if (conn->push_buf == NULL)
680 if (conn->push_buf_len < out_len)
681 out_len = conn->push_buf_len;
682 memcpy(out_data, conn->push_buf, out_len);
683 free(conn->push_buf);
684 conn->push_buf = NULL;
685 conn->push_buf_len = 0;
690 int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn,
691 const u8 *in_data, size_t in_len,
692 u8 *out_data, size_t out_len)
696 if (conn->pull_buf) {
697 wpa_printf(MSG_DEBUG, "%s - %d bytes remaining in "
698 "pull_buf", __func__, conn->pull_buf_len);
699 free(conn->pull_buf);
701 conn->pull_buf = malloc(in_len);
702 if (conn->pull_buf == NULL)
704 memcpy(conn->pull_buf, in_data, in_len);
705 conn->pull_buf_offset = conn->pull_buf;
706 conn->pull_buf_len = in_len;
708 res = gnutls_record_recv(conn->session, out_data, out_len);
710 wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
711 "(%s)", __func__, res, gnutls_strerror(res));
718 int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
722 return gnutls_session_is_resumed(conn->session);
727 int tls_connection_set_master_key(void *ssl_ctx, struct tls_connection *conn,
728 const u8 *key, size_t key_len)
733 #endif /* EAP_FAST */
736 int tls_connection_set_anon_dh(void *ssl_ctx, struct tls_connection *conn)
738 /* TODO: set ADH-AES128-SHA cipher */
743 int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
744 char *buf, size_t buflen)
752 int tls_connection_enable_workaround(void *ssl_ctx,
753 struct tls_connection *conn)
755 /* TODO: set SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS */
761 int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
762 int ext_type, const u8 *data,
768 #endif /* EAP_FAST */
771 int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
779 int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
783 return conn->read_alerts;
787 int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
791 return conn->write_alerts;