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
;