xref: /dragonfly/contrib/wpa_supplicant/src/crypto/tls_gnutls.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
1 /*
2  * SSL/TLS interface functions for GnuTLS
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 #include <gnutls/gnutls.h>
11 #include <gnutls/x509.h>
12 #ifdef PKCS12_FUNCS
13 #include <gnutls/pkcs12.h>
14 #endif /* PKCS12_FUNCS */
15 #if GNUTLS_VERSION_NUMBER >= 0x030103
16 #include <gnutls/ocsp.h>
17 #endif /* 3.1.3 */
18 
19 #include "common.h"
20 #include "crypto/crypto.h"
21 #include "tls.h"
22 
23 
24 static int tls_gnutls_ref_count = 0;
25 
26 struct tls_global {
27           /* Data for session resumption */
28           void *session_data;
29           size_t session_data_size;
30 
31           int server;
32 
33           int params_set;
34           gnutls_certificate_credentials_t xcred;
35 
36           void (*event_cb)(void *ctx, enum tls_event ev,
37                                union tls_event_data *data);
38           void *cb_ctx;
39           int cert_in_cb;
40 
41           char *ocsp_stapling_response;
42 };
43 
44 struct tls_connection {
45           struct tls_global *global;
46           gnutls_session_t session;
47           int read_alerts, write_alerts, failed;
48 
49           u8 *pre_shared_secret;
50           size_t pre_shared_secret_len;
51           int established;
52           int verify_peer;
53           unsigned int disable_time_checks:1;
54 
55           struct wpabuf *push_buf;
56           struct wpabuf *pull_buf;
57           const u8 *pull_buf_offset;
58 
59           int params_set;
60           gnutls_certificate_credentials_t xcred;
61 
62           char *suffix_match;
63           char *domain_match;
64           unsigned int flags;
65 };
66 
67 
68 static int tls_connection_verify_peer(gnutls_session_t session);
69 
70 
tls_log_func(int level,const char * msg)71 static void tls_log_func(int level, const char *msg)
72 {
73           char *s, *pos;
74           if (level == 6 || level == 7) {
75                     /* These levels seem to be mostly I/O debug and msg dumps */
76                     return;
77           }
78 
79           s = os_strdup(msg);
80           if (s == NULL)
81                     return;
82 
83           pos = s;
84           while (*pos != '\0') {
85                     if (*pos == '\n') {
86                               *pos = '\0';
87                               break;
88                     }
89                     pos++;
90           }
91           wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
92                        "gnutls<%d> %s", level, s);
93           os_free(s);
94 }
95 
96 
tls_init(const struct tls_config * conf)97 void * tls_init(const struct tls_config *conf)
98 {
99           struct tls_global *global;
100 
101           if (tls_gnutls_ref_count == 0) {
102                     wpa_printf(MSG_DEBUG,
103                                  "GnuTLS: Library version %s (runtime) - %s (build)",
104                                  gnutls_check_version(NULL), GNUTLS_VERSION);
105           }
106 
107           global = os_zalloc(sizeof(*global));
108           if (global == NULL)
109                     return NULL;
110 
111           if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
112                     os_free(global);
113                     return NULL;
114           }
115           tls_gnutls_ref_count++;
116 
117           gnutls_global_set_log_function(tls_log_func);
118           if (wpa_debug_show_keys)
119                     gnutls_global_set_log_level(11);
120 
121           if (conf) {
122                     global->event_cb = conf->event_cb;
123                     global->cb_ctx = conf->cb_ctx;
124                     global->cert_in_cb = conf->cert_in_cb;
125           }
126 
127           return global;
128 }
129 
130 
tls_deinit(void * ssl_ctx)131 void tls_deinit(void *ssl_ctx)
132 {
133           struct tls_global *global = ssl_ctx;
134           if (global) {
135                     if (global->params_set)
136                               gnutls_certificate_free_credentials(global->xcred);
137                     os_free(global->session_data);
138                     os_free(global->ocsp_stapling_response);
139                     os_free(global);
140           }
141 
142           tls_gnutls_ref_count--;
143           if (tls_gnutls_ref_count == 0)
144                     gnutls_global_deinit();
145 }
146 
147 
tls_get_errors(void * ssl_ctx)148 int tls_get_errors(void *ssl_ctx)
149 {
150           return 0;
151 }
152 
153 
tls_pull_func(gnutls_transport_ptr_t ptr,void * buf,size_t len)154 static ssize_t tls_pull_func(gnutls_transport_ptr_t ptr, void *buf,
155                                    size_t len)
156 {
157           struct tls_connection *conn = (struct tls_connection *) ptr;
158           const u8 *end;
159           if (conn->pull_buf == NULL) {
160                     errno = EWOULDBLOCK;
161                     return -1;
162           }
163 
164           end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf);
165           if ((size_t) (end - conn->pull_buf_offset) < len)
166                     len = end - conn->pull_buf_offset;
167           os_memcpy(buf, conn->pull_buf_offset, len);
168           conn->pull_buf_offset += len;
169           if (conn->pull_buf_offset == end) {
170                     wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
171                     wpabuf_free(conn->pull_buf);
172                     conn->pull_buf = NULL;
173                     conn->pull_buf_offset = NULL;
174           } else {
175                     wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
176                                  __func__,
177                                  (unsigned long) (end - conn->pull_buf_offset));
178           }
179           return len;
180 }
181 
182 
tls_push_func(gnutls_transport_ptr_t ptr,const void * buf,size_t len)183 static ssize_t tls_push_func(gnutls_transport_ptr_t ptr, const void *buf,
184                                    size_t len)
185 {
186           struct tls_connection *conn = (struct tls_connection *) ptr;
187 
188           if (wpabuf_resize(&conn->push_buf, len) < 0) {
189                     errno = ENOMEM;
190                     return -1;
191           }
192           wpabuf_put_data(conn->push_buf, buf, len);
193 
194           return len;
195 }
196 
197 
tls_gnutls_init_session(struct tls_global * global,struct tls_connection * conn)198 static int tls_gnutls_init_session(struct tls_global *global,
199                                            struct tls_connection *conn)
200 {
201           const char *err;
202           int ret;
203 
204           ret = gnutls_init(&conn->session,
205                                 global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
206           if (ret < 0) {
207                     wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
208                                  "connection: %s", gnutls_strerror(ret));
209                     return -1;
210           }
211 
212           ret = gnutls_set_default_priority(conn->session);
213           if (ret < 0)
214                     goto fail;
215 
216           ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
217                                                    &err);
218           if (ret < 0) {
219                     wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at "
220                                  "'%s'", err);
221                     goto fail;
222           }
223 
224           gnutls_transport_set_pull_function(conn->session, tls_pull_func);
225           gnutls_transport_set_push_function(conn->session, tls_push_func);
226           gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr_t) conn);
227           gnutls_session_set_ptr(conn->session, conn);
228 
229           return 0;
230 
231 fail:
232           wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
233                        gnutls_strerror(ret));
234           gnutls_deinit(conn->session);
235           return -1;
236 }
237 
238 
tls_connection_init(void * ssl_ctx)239 struct tls_connection * tls_connection_init(void *ssl_ctx)
240 {
241           struct tls_global *global = ssl_ctx;
242           struct tls_connection *conn;
243           int ret;
244 
245           conn = os_zalloc(sizeof(*conn));
246           if (conn == NULL)
247                     return NULL;
248           conn->global = global;
249 
250           if (tls_gnutls_init_session(global, conn)) {
251                     os_free(conn);
252                     return NULL;
253           }
254 
255           if (global->params_set) {
256                     ret = gnutls_credentials_set(conn->session,
257                                                        GNUTLS_CRD_CERTIFICATE,
258                                                        global->xcred);
259                     if (ret < 0) {
260                               wpa_printf(MSG_INFO, "Failed to configure "
261                                            "credentials: %s", gnutls_strerror(ret));
262                               os_free(conn);
263                               return NULL;
264                     }
265           }
266 
267           if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
268                     os_free(conn);
269                     return NULL;
270           }
271 
272           return conn;
273 }
274 
275 
tls_connection_deinit(void * ssl_ctx,struct tls_connection * conn)276 void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
277 {
278           if (conn == NULL)
279                     return;
280 
281           gnutls_certificate_free_credentials(conn->xcred);
282           gnutls_deinit(conn->session);
283           os_free(conn->pre_shared_secret);
284           wpabuf_free(conn->push_buf);
285           wpabuf_free(conn->pull_buf);
286           os_free(conn->suffix_match);
287           os_free(conn->domain_match);
288           os_free(conn);
289 }
290 
291 
tls_connection_established(void * ssl_ctx,struct tls_connection * conn)292 int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
293 {
294           return conn ? conn->established : 0;
295 }
296 
297 
tls_connection_peer_serial_num(void * tls_ctx,struct tls_connection * conn)298 char * tls_connection_peer_serial_num(void *tls_ctx,
299                                               struct tls_connection *conn)
300 {
301           /* TODO */
302           return NULL;
303 }
304 
305 
tls_connection_shutdown(void * ssl_ctx,struct tls_connection * conn)306 int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
307 {
308           struct tls_global *global = ssl_ctx;
309           int ret;
310 
311           if (conn == NULL)
312                     return -1;
313 
314           /* Shutdown previous TLS connection without notifying the peer
315            * because the connection was already terminated in practice
316            * and "close notify" shutdown alert would confuse AS. */
317           gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
318           wpabuf_free(conn->push_buf);
319           conn->push_buf = NULL;
320           conn->established = 0;
321 
322           gnutls_deinit(conn->session);
323           if (tls_gnutls_init_session(global, conn)) {
324                     wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
325                                  "for session resumption use");
326                     return -1;
327           }
328 
329           ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
330                                              conn->params_set ? conn->xcred :
331                                              global->xcred);
332           if (ret < 0) {
333                     wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
334                                  "for session resumption: %s", gnutls_strerror(ret));
335                     return -1;
336           }
337 
338           if (global->session_data) {
339                     ret = gnutls_session_set_data(conn->session,
340                                                         global->session_data,
341                                                         global->session_data_size);
342                     if (ret < 0) {
343                               wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
344                                            "data: %s", gnutls_strerror(ret));
345                               return -1;
346                     }
347           }
348 
349           return 0;
350 }
351 
352 
tls_connection_set_params(void * tls_ctx,struct tls_connection * conn,const struct tls_connection_params * params)353 int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
354                                     const struct tls_connection_params *params)
355 {
356           int ret;
357           const char *err;
358           char prio_buf[100];
359           const char *prio = NULL;
360 
361           if (conn == NULL || params == NULL)
362                     return -1;
363 
364           if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
365                     wpa_printf(MSG_INFO,
366                                  "GnuTLS: ocsp=3 not supported");
367                     return -1;
368           }
369 
370           if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
371                     wpa_printf(MSG_INFO,
372                                  "GnuTLS: tls_ext_cert_check=1 not supported");
373                     return -1;
374           }
375 
376           if (params->subject_match) {
377                     wpa_printf(MSG_INFO, "GnuTLS: subject_match not supported");
378                     return -1;
379           }
380 
381           if (params->altsubject_match) {
382                     wpa_printf(MSG_INFO, "GnuTLS: altsubject_match not supported");
383                     return -1;
384           }
385 
386           os_free(conn->suffix_match);
387           conn->suffix_match = NULL;
388           if (params->suffix_match) {
389                     conn->suffix_match = os_strdup(params->suffix_match);
390                     if (conn->suffix_match == NULL)
391                               return -1;
392           }
393 
394 #if GNUTLS_VERSION_NUMBER >= 0x030300
395           os_free(conn->domain_match);
396           conn->domain_match = NULL;
397           if (params->domain_match) {
398                     conn->domain_match = os_strdup(params->domain_match);
399                     if (conn->domain_match == NULL)
400                               return -1;
401           }
402 #else /* < 3.3.0 */
403           if (params->domain_match) {
404                     wpa_printf(MSG_INFO, "GnuTLS: domain_match not supported");
405                     return -1;
406           }
407 #endif /* >= 3.3.0 */
408 
409           conn->flags = params->flags;
410 
411           if (params->flags & (TLS_CONN_DISABLE_TLSv1_0 |
412                                    TLS_CONN_DISABLE_TLSv1_1 |
413                                    TLS_CONN_DISABLE_TLSv1_2)) {
414                     os_snprintf(prio_buf, sizeof(prio_buf),
415                                   "NORMAL:-VERS-SSL3.0%s%s%s",
416                                   params->flags & TLS_CONN_DISABLE_TLSv1_0 ?
417                                   ":-VERS-TLS1.0" : "",
418                                   params->flags & TLS_CONN_DISABLE_TLSv1_1 ?
419                                   ":-VERS-TLS1.1" : "",
420                                   params->flags & TLS_CONN_DISABLE_TLSv1_2 ?
421                                   ":-VERS-TLS1.2" : "");
422                     prio = prio_buf;
423           }
424 
425           if (params->openssl_ciphers) {
426                     if (os_strcmp(params->openssl_ciphers, "SUITEB128") == 0) {
427                               prio = "SUITEB128";
428                     } else if (os_strcmp(params->openssl_ciphers,
429                                              "SUITEB192") == 0) {
430                               prio = "SUITEB192";
431                     } else if ((params->flags & TLS_CONN_SUITEB) &&
432                                  os_strcmp(params->openssl_ciphers,
433                                              "ECDHE-RSA-AES256-GCM-SHA384") == 0) {
434                               prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
435                     } else if (os_strcmp(params->openssl_ciphers,
436                                              "ECDHE-RSA-AES256-GCM-SHA384") == 0) {
437                               prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
438                     } else if (os_strcmp(params->openssl_ciphers,
439                                              "DHE-RSA-AES256-GCM-SHA384") == 0) {
440                               prio = "NONE:+VERS-TLS1.2:+AEAD:+DHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL:%PROFILE_HIGH";
441                     } else if (os_strcmp(params->openssl_ciphers,
442                                              "ECDHE-ECDSA-AES256-GCM-SHA384") == 0) {
443                               prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-ECDSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
444                     } else {
445                               wpa_printf(MSG_INFO,
446                                            "GnuTLS: openssl_ciphers not supported");
447                               return -1;
448                     }
449           } else if (params->flags & TLS_CONN_SUITEB) {
450                     prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-ECDSA:+ECDHE-RSA:+DHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL:%PROFILE_HIGH";
451           }
452 
453           if (prio) {
454                     wpa_printf(MSG_DEBUG, "GnuTLS: Set priority string: %s", prio);
455                     ret = gnutls_priority_set_direct(conn->session, prio, &err);
456                     if (ret < 0) {
457                               wpa_printf(MSG_ERROR,
458                                            "GnuTLS: Priority string failure at '%s'",
459                                            err);
460                               return -1;
461                     }
462           }
463 
464           if (params->openssl_ecdh_curves) {
465                     wpa_printf(MSG_INFO,
466                                  "GnuTLS: openssl_ecdh_curves not supported");
467                     return -1;
468           }
469 
470           /* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
471            * to force peer validation(?) */
472 
473           if (params->ca_cert) {
474                     wpa_printf(MSG_DEBUG, "GnuTLS: Try to parse %s in DER format",
475                                  params->ca_cert);
476                     ret = gnutls_certificate_set_x509_trust_file(
477                               conn->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
478                     if (ret < 0) {
479                               wpa_printf(MSG_DEBUG,
480                                            "GnuTLS: Failed to read CA cert '%s' in DER format (%s) - try in PEM format",
481                                            params->ca_cert,
482                                            gnutls_strerror(ret));
483                               ret = gnutls_certificate_set_x509_trust_file(
484                                         conn->xcred, params->ca_cert,
485                                         GNUTLS_X509_FMT_PEM);
486                               if (ret < 0) {
487                                         wpa_printf(MSG_DEBUG,
488                                                      "Failed to read CA cert '%s' in PEM format: %s",
489                                                      params->ca_cert,
490                                                      gnutls_strerror(ret));
491                                         return -1;
492                               }
493                               wpa_printf(MSG_DEBUG,
494                                            "GnuTLS: Successfully read CA cert '%s' in PEM format",
495                                            params->ca_cert);
496                     } else {
497                               wpa_printf(MSG_DEBUG,
498                                            "GnuTLS: Successfully read CA cert '%s' in DER format",
499                                            params->ca_cert);
500                     }
501           } else if (params->ca_cert_blob) {
502                     gnutls_datum_t ca;
503 
504                     ca.data = (unsigned char *) params->ca_cert_blob;
505                     ca.size = params->ca_cert_blob_len;
506 
507                     ret = gnutls_certificate_set_x509_trust_mem(
508                               conn->xcred, &ca, GNUTLS_X509_FMT_DER);
509                     if (ret < 0) {
510                               wpa_printf(MSG_DEBUG,
511                                            "Failed to parse CA cert in DER format: %s",
512                                            gnutls_strerror(ret));
513                               ret = gnutls_certificate_set_x509_trust_mem(
514                                         conn->xcred, &ca, GNUTLS_X509_FMT_PEM);
515                               if (ret < 0) {
516                                         wpa_printf(MSG_DEBUG,
517                                                      "Failed to parse CA cert in PEM format: %s",
518                                                      gnutls_strerror(ret));
519                                         return -1;
520                               }
521                     }
522           } else if (params->ca_path) {
523                     wpa_printf(MSG_INFO, "GnuTLS: ca_path not supported");
524                     return -1;
525           }
526 
527           conn->disable_time_checks = 0;
528           if (params->ca_cert || params->ca_cert_blob) {
529                     conn->verify_peer = 1;
530                     gnutls_certificate_set_verify_function(
531                               conn->xcred, tls_connection_verify_peer);
532 
533                     if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
534                               gnutls_certificate_set_verify_flags(
535                                         conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
536                     }
537 
538                     if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
539                               conn->disable_time_checks = 1;
540                               gnutls_certificate_set_verify_flags(
541                                         conn->xcred,
542                                         GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
543                     }
544           }
545 
546           if (params->client_cert && params->private_key) {
547                     wpa_printf(MSG_DEBUG,
548                                  "GnuTLS: Try to parse client cert '%s' and key '%s' in DER format",
549                                  params->client_cert, params->private_key);
550 #if GNUTLS_VERSION_NUMBER >= 0x03010b
551                     ret = gnutls_certificate_set_x509_key_file2(
552                               conn->xcred, params->client_cert, params->private_key,
553                               GNUTLS_X509_FMT_DER, params->private_key_passwd, 0);
554 #else
555                     /* private_key_passwd not (easily) supported here */
556                     ret = gnutls_certificate_set_x509_key_file(
557                               conn->xcred, params->client_cert, params->private_key,
558                               GNUTLS_X509_FMT_DER);
559 #endif
560                     if (ret < 0) {
561                               wpa_printf(MSG_DEBUG,
562                                            "GnuTLS: Failed to read client cert/key in DER format (%s) - try in PEM format",
563                                            gnutls_strerror(ret));
564 #if GNUTLS_VERSION_NUMBER >= 0x03010b
565                               ret = gnutls_certificate_set_x509_key_file2(
566                                         conn->xcred, params->client_cert,
567                                         params->private_key, GNUTLS_X509_FMT_PEM,
568                                         params->private_key_passwd, 0);
569 #else
570                               ret = gnutls_certificate_set_x509_key_file(
571                                         conn->xcred, params->client_cert,
572                                         params->private_key, GNUTLS_X509_FMT_PEM);
573 #endif
574                               if (ret < 0) {
575                                         wpa_printf(MSG_DEBUG, "Failed to read client "
576                                                      "cert/key in PEM format: %s",
577                                                      gnutls_strerror(ret));
578                                         return ret;
579                               }
580                               wpa_printf(MSG_DEBUG,
581                                            "GnuTLS: Successfully read client cert/key in PEM format");
582                     } else {
583                               wpa_printf(MSG_DEBUG,
584                                            "GnuTLS: Successfully read client cert/key in DER format");
585                     }
586           } else if (params->private_key) {
587                     int pkcs12_ok = 0;
588 #ifdef PKCS12_FUNCS
589                     /* Try to load in PKCS#12 format */
590                     wpa_printf(MSG_DEBUG,
591                                  "GnuTLS: Try to parse client cert/key '%s'in PKCS#12 DER format",
592                                  params->private_key);
593                     ret = gnutls_certificate_set_x509_simple_pkcs12_file(
594                               conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
595                               params->private_key_passwd);
596                     if (ret != 0) {
597                               wpa_printf(MSG_DEBUG, "Failed to load private_key in "
598                                            "PKCS#12 format: %s", gnutls_strerror(ret));
599                               return -1;
600                     } else
601                               pkcs12_ok = 1;
602 #endif /* PKCS12_FUNCS */
603 
604                     if (!pkcs12_ok) {
605                               wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
606                                            "included");
607                               return -1;
608                     }
609           } else if (params->client_cert_blob && params->private_key_blob) {
610                     gnutls_datum_t cert, key;
611 
612                     cert.data = (unsigned char *) params->client_cert_blob;
613                     cert.size = params->client_cert_blob_len;
614                     key.data = (unsigned char *) params->private_key_blob;
615                     key.size = params->private_key_blob_len;
616 
617 #if GNUTLS_VERSION_NUMBER >= 0x03010b
618                     ret = gnutls_certificate_set_x509_key_mem2(
619                               conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER,
620                               params->private_key_passwd, 0);
621 #else
622                     /* private_key_passwd not (easily) supported here */
623                     ret = gnutls_certificate_set_x509_key_mem(
624                               conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER);
625 #endif
626                     if (ret < 0) {
627                               wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
628                                            "in DER format: %s", gnutls_strerror(ret));
629 #if GNUTLS_VERSION_NUMBER >= 0x03010b
630                               ret = gnutls_certificate_set_x509_key_mem2(
631                                         conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM,
632                                         params->private_key_passwd, 0);
633 #else
634                               /* private_key_passwd not (easily) supported here */
635                               ret = gnutls_certificate_set_x509_key_mem(
636                                         conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM);
637 #endif
638                               if (ret < 0) {
639                                         wpa_printf(MSG_DEBUG, "Failed to read client "
640                                                      "cert/key in PEM format: %s",
641                                                      gnutls_strerror(ret));
642                                         return ret;
643                               }
644                     }
645           } else if (params->private_key_blob) {
646 #ifdef PKCS12_FUNCS
647                     gnutls_datum_t key;
648 
649                     key.data = (unsigned char *) params->private_key_blob;
650                     key.size = params->private_key_blob_len;
651 
652                     /* Try to load in PKCS#12 format */
653                     ret = gnutls_certificate_set_x509_simple_pkcs12_mem(
654                               conn->xcred, &key, GNUTLS_X509_FMT_DER,
655                               params->private_key_passwd);
656                     if (ret != 0) {
657                               wpa_printf(MSG_DEBUG, "Failed to load private_key in "
658                                            "PKCS#12 format: %s", gnutls_strerror(ret));
659                               return -1;
660                     }
661 #else /* PKCS12_FUNCS */
662                     wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not included");
663                     return -1;
664 #endif /* PKCS12_FUNCS */
665           }
666 
667 #if GNUTLS_VERSION_NUMBER >= 0x030103
668           if (params->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)) {
669                     ret = gnutls_ocsp_status_request_enable_client(conn->session,
670                                                                              NULL, 0, NULL);
671                     if (ret != GNUTLS_E_SUCCESS) {
672                               wpa_printf(MSG_INFO,
673                                            "GnuTLS: Failed to enable OCSP client");
674                               return -1;
675                     }
676           }
677 #else /* 3.1.3 */
678           if (params->flags & TLS_CONN_REQUIRE_OCSP) {
679                     wpa_printf(MSG_INFO,
680                                  "GnuTLS: OCSP not supported by this version of GnuTLS");
681                     return -1;
682           }
683 #endif /* 3.1.3 */
684 
685           conn->params_set = 1;
686 
687           ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
688                                              conn->xcred);
689           if (ret < 0) {
690                     wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
691                                  gnutls_strerror(ret));
692           }
693 
694           return ret;
695 }
696 
697 
698 #if GNUTLS_VERSION_NUMBER >= 0x030103
server_ocsp_status_req(gnutls_session_t session,void * ptr,gnutls_datum_t * resp)699 static int server_ocsp_status_req(gnutls_session_t session, void *ptr,
700                                           gnutls_datum_t *resp)
701 {
702           struct tls_global *global = ptr;
703           char *cached;
704           size_t len;
705 
706           if (!global->ocsp_stapling_response) {
707                     wpa_printf(MSG_DEBUG, "GnuTLS: OCSP status callback - no response configured");
708                     return GNUTLS_E_NO_CERTIFICATE_STATUS;
709           }
710 
711           cached = os_readfile(global->ocsp_stapling_response, &len);
712           if (!cached) {
713                     wpa_printf(MSG_DEBUG,
714                                  "GnuTLS: OCSP status callback - could not read response file (%s)",
715                                  global->ocsp_stapling_response);
716                     return GNUTLS_E_NO_CERTIFICATE_STATUS;
717           }
718 
719           wpa_printf(MSG_DEBUG,
720                        "GnuTLS: OCSP status callback - send cached response");
721           resp->data = gnutls_malloc(len);
722           if (!resp->data) {
723                     os_free(resp);
724                     return GNUTLS_E_MEMORY_ERROR;
725           }
726 
727           os_memcpy(resp->data, cached, len);
728           resp->size = len;
729           os_free(cached);
730 
731           return GNUTLS_E_SUCCESS;
732 }
733 #endif /* 3.1.3 */
734 
735 
tls_global_set_params(void * tls_ctx,const struct tls_connection_params * params)736 int tls_global_set_params(void *tls_ctx,
737                                 const struct tls_connection_params *params)
738 {
739           struct tls_global *global = tls_ctx;
740           int ret;
741 
742           if (params->check_cert_subject)
743                     return -1; /* not yet supported */
744 
745           /* Currently, global parameters are only set when running in server
746            * mode. */
747           global->server = 1;
748 
749           if (global->params_set) {
750                     gnutls_certificate_free_credentials(global->xcred);
751                     global->params_set = 0;
752           }
753 
754           ret = gnutls_certificate_allocate_credentials(&global->xcred);
755           if (ret) {
756                     wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
757                                  "%s", gnutls_strerror(ret));
758                     return -1;
759           }
760 
761           if (params->ca_cert) {
762                     ret = gnutls_certificate_set_x509_trust_file(
763                               global->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
764                     if (ret < 0) {
765                               wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
766                                            "in DER format: %s", params->ca_cert,
767                                            gnutls_strerror(ret));
768                               ret = gnutls_certificate_set_x509_trust_file(
769                                         global->xcred, params->ca_cert,
770                                         GNUTLS_X509_FMT_PEM);
771                               if (ret < 0) {
772                                         wpa_printf(MSG_DEBUG, "Failed to read CA cert "
773                                                      "'%s' in PEM format: %s",
774                                                      params->ca_cert,
775                                                      gnutls_strerror(ret));
776                                         goto fail;
777                               }
778                     }
779 
780                     if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
781                               gnutls_certificate_set_verify_flags(
782                                         global->xcred,
783                                         GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
784                     }
785 
786                     if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
787                               gnutls_certificate_set_verify_flags(
788                                         global->xcred,
789                                         GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
790                     }
791           }
792 
793           if (params->client_cert && params->private_key) {
794                     /* TODO: private_key_passwd? */
795                     ret = gnutls_certificate_set_x509_key_file(
796                               global->xcred, params->client_cert,
797                               params->private_key, GNUTLS_X509_FMT_DER);
798                     if (ret < 0) {
799                               wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
800                                            "in DER format: %s", gnutls_strerror(ret));
801                               ret = gnutls_certificate_set_x509_key_file(
802                                         global->xcred, params->client_cert,
803                                         params->private_key, GNUTLS_X509_FMT_PEM);
804                               if (ret < 0) {
805                                         wpa_printf(MSG_DEBUG, "Failed to read client "
806                                                      "cert/key in PEM format: %s",
807                                                      gnutls_strerror(ret));
808                                         goto fail;
809                               }
810                     }
811           } else if (params->private_key) {
812                     int pkcs12_ok = 0;
813 #ifdef PKCS12_FUNCS
814                     /* Try to load in PKCS#12 format */
815                     ret = gnutls_certificate_set_x509_simple_pkcs12_file(
816                               global->xcred, params->private_key,
817                               GNUTLS_X509_FMT_DER, params->private_key_passwd);
818                     if (ret != 0) {
819                               wpa_printf(MSG_DEBUG, "Failed to load private_key in "
820                                            "PKCS#12 format: %s", gnutls_strerror(ret));
821                               goto fail;
822                     } else
823                               pkcs12_ok = 1;
824 #endif /* PKCS12_FUNCS */
825 
826                     if (!pkcs12_ok) {
827                               wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
828                                            "included");
829                               goto fail;
830                     }
831           }
832 
833 #if GNUTLS_VERSION_NUMBER >= 0x030103
834           os_free(global->ocsp_stapling_response);
835           if (params->ocsp_stapling_response)
836                     global->ocsp_stapling_response =
837                               os_strdup(params->ocsp_stapling_response);
838           else
839                     global->ocsp_stapling_response = NULL;
840           gnutls_certificate_set_ocsp_status_request_function(
841                     global->xcred, server_ocsp_status_req, global);
842 #endif /* 3.1.3 */
843 
844           global->params_set = 1;
845 
846           return 0;
847 
848 fail:
849           gnutls_certificate_free_credentials(global->xcred);
850           return -1;
851 }
852 
853 
tls_global_set_verify(void * ssl_ctx,int check_crl,int strict)854 int tls_global_set_verify(void *ssl_ctx, int check_crl, int strict)
855 {
856           /* TODO */
857           return 0;
858 }
859 
860 
tls_connection_set_verify(void * ssl_ctx,struct tls_connection * conn,int verify_peer,unsigned int flags,const u8 * session_ctx,size_t session_ctx_len)861 int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
862                                     int verify_peer, unsigned int flags,
863                                     const u8 *session_ctx, size_t session_ctx_len)
864 {
865           if (conn == NULL || conn->session == NULL)
866                     return -1;
867 
868           conn->verify_peer = verify_peer;
869           gnutls_certificate_server_set_request(conn->session,
870                                                         verify_peer ? GNUTLS_CERT_REQUIRE
871                                                         : GNUTLS_CERT_REQUEST);
872 
873           return 0;
874 }
875 
876 
tls_connection_get_random(void * ssl_ctx,struct tls_connection * conn,struct tls_random * keys)877 int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
878                                   struct tls_random *keys)
879 {
880 #if GNUTLS_VERSION_NUMBER >= 0x030012
881           gnutls_datum_t client, server;
882 
883           if (conn == NULL || conn->session == NULL || keys == NULL)
884                     return -1;
885 
886           os_memset(keys, 0, sizeof(*keys));
887           gnutls_session_get_random(conn->session, &client, &server);
888           keys->client_random = client.data;
889           keys->server_random = server.data;
890           keys->client_random_len = client.size;
891           keys->server_random_len = client.size;
892 
893           return 0;
894 #else /* 3.0.18 */
895           return -1;
896 #endif /* 3.0.18 */
897 }
898 
899 
tls_connection_export_key(void * tls_ctx,struct tls_connection * conn,const char * label,const u8 * context,size_t context_len,u8 * out,size_t out_len)900 int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
901                                     const char *label, const u8 *context,
902                                     size_t context_len, u8 *out, size_t out_len)
903 {
904           if (conn == NULL || conn->session == NULL)
905                     return -1;
906 
907 #if GNUTLS_VERSION_NUMBER >= 0x030404
908           return gnutls_prf_rfc5705(conn->session, os_strlen(label), label,
909                                           context_len, (const char *) context,
910                                           out_len, (char *) out);
911 #else /* 3.4.4 */
912           if (context)
913                     return -1;
914           return gnutls_prf(conn->session, os_strlen(label), label,
915                                 0 /* client_random first */, 0, NULL, out_len,
916                                 (char *) out);
917 #endif /* 3.4.4 */
918 }
919 
920 
tls_connection_get_eap_fast_key(void * tls_ctx,struct tls_connection * conn,u8 * out,size_t out_len)921 int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
922                                             u8 *out, size_t out_len)
923 {
924           return -1;
925 }
926 
927 
gnutls_tls_fail_event(struct tls_connection * conn,const gnutls_datum_t * cert,int depth,const char * subject,const char * err_str,enum tls_fail_reason reason)928 static void gnutls_tls_fail_event(struct tls_connection *conn,
929                                           const gnutls_datum_t *cert, int depth,
930                                           const char *subject, const char *err_str,
931                                           enum tls_fail_reason reason)
932 {
933           union tls_event_data ev;
934           struct tls_global *global = conn->global;
935           struct wpabuf *cert_buf = NULL;
936 
937           if (global->event_cb == NULL)
938                     return;
939 
940           os_memset(&ev, 0, sizeof(ev));
941           ev.cert_fail.depth = depth;
942           ev.cert_fail.subject = subject ? subject : "";
943           ev.cert_fail.reason = reason;
944           ev.cert_fail.reason_txt = err_str;
945           if (cert) {
946                     cert_buf = wpabuf_alloc_copy(cert->data, cert->size);
947                     ev.cert_fail.cert = cert_buf;
948           }
949           global->event_cb(global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
950           wpabuf_free(cert_buf);
951 }
952 
953 
954 #if GNUTLS_VERSION_NUMBER < 0x030300
server_eku_purpose(gnutls_x509_crt_t cert)955 static int server_eku_purpose(gnutls_x509_crt_t cert)
956 {
957           unsigned int i;
958 
959           for (i = 0; ; i++) {
960                     char oid[128];
961                     size_t oid_size = sizeof(oid);
962                     int res;
963 
964                     res = gnutls_x509_crt_get_key_purpose_oid(cert, i, oid,
965                                                                         &oid_size, NULL);
966                     if (res == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
967                               if (i == 0) {
968                                         /* No EKU - assume any use allowed */
969                                         return 1;
970                               }
971                               break;
972                     }
973 
974                     if (res < 0) {
975                               wpa_printf(MSG_INFO, "GnuTLS: Failed to get EKU");
976                               return 0;
977                     }
978 
979                     wpa_printf(MSG_DEBUG, "GnuTLS: Certificate purpose: %s", oid);
980                     if (os_strcmp(oid, GNUTLS_KP_TLS_WWW_SERVER) == 0 ||
981                         os_strcmp(oid, GNUTLS_KP_ANY) == 0)
982                               return 1;
983           }
984 
985           return 0;
986 }
987 #endif /* < 3.3.0 */
988 
989 
check_ocsp(struct tls_connection * conn,gnutls_session_t session,gnutls_alert_description_t * err)990 static int check_ocsp(struct tls_connection *conn, gnutls_session_t session,
991                           gnutls_alert_description_t *err)
992 {
993 #if GNUTLS_VERSION_NUMBER >= 0x030103
994           gnutls_datum_t response, buf;
995           gnutls_ocsp_resp_t resp;
996           unsigned int cert_status;
997           int res;
998 
999           if (!(conn->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)))
1000                     return 0;
1001 
1002           if (!gnutls_ocsp_status_request_is_checked(session, 0)) {
1003                     if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
1004                               wpa_printf(MSG_INFO,
1005                                            "GnuTLS: No valid OCSP response received");
1006                               goto ocsp_error;
1007                     }
1008 
1009                     wpa_printf(MSG_DEBUG,
1010                                  "GnuTLS: Valid OCSP response was not received - continue since OCSP was not required");
1011                     return 0;
1012           }
1013 
1014           /*
1015            * GnuTLS has already verified the OCSP response in
1016            * check_ocsp_response() and rejected handshake if the certificate was
1017            * found to be revoked. However, if the response indicates that the
1018            * status is unknown, handshake continues and reaches here. We need to
1019            * re-import the OCSP response to check for unknown certificate status,
1020            * but we do not need to repeat gnutls_ocsp_resp_check_crt() and
1021            * gnutls_ocsp_resp_verify_direct() calls.
1022            */
1023 
1024           res = gnutls_ocsp_status_request_get(session, &response);
1025           if (res != GNUTLS_E_SUCCESS) {
1026                     wpa_printf(MSG_INFO,
1027                                  "GnuTLS: OCSP response was received, but it was not valid");
1028                     goto ocsp_error;
1029           }
1030 
1031           if (gnutls_ocsp_resp_init(&resp) != GNUTLS_E_SUCCESS)
1032                     goto ocsp_error;
1033 
1034           res = gnutls_ocsp_resp_import(resp, &response);
1035           if (res != GNUTLS_E_SUCCESS) {
1036                     wpa_printf(MSG_INFO,
1037                                  "GnuTLS: Could not parse received OCSP response: %s",
1038                                  gnutls_strerror(res));
1039                     gnutls_ocsp_resp_deinit(resp);
1040                     goto ocsp_error;
1041           }
1042 
1043           res = gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &buf);
1044           if (res == GNUTLS_E_SUCCESS) {
1045                     wpa_printf(MSG_DEBUG, "GnuTLS: %s", buf.data);
1046                     gnutls_free(buf.data);
1047           }
1048 
1049           res = gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL,
1050                                                     NULL, &cert_status, NULL,
1051                                                     NULL, NULL, NULL);
1052           gnutls_ocsp_resp_deinit(resp);
1053           if (res != GNUTLS_E_SUCCESS) {
1054                     wpa_printf(MSG_INFO,
1055                                  "GnuTLS: Failed to extract OCSP information: %s",
1056                                  gnutls_strerror(res));
1057                     goto ocsp_error;
1058           }
1059 
1060           if (cert_status == GNUTLS_OCSP_CERT_GOOD) {
1061                     wpa_printf(MSG_DEBUG, "GnuTLS: OCSP cert status: good");
1062           } else if (cert_status == GNUTLS_OCSP_CERT_REVOKED) {
1063                     wpa_printf(MSG_DEBUG,
1064                                  "GnuTLS: OCSP cert status: revoked");
1065                     goto ocsp_error;
1066           } else {
1067                     wpa_printf(MSG_DEBUG,
1068                                  "GnuTLS: OCSP cert status: unknown");
1069                     if (conn->flags & TLS_CONN_REQUIRE_OCSP)
1070                               goto ocsp_error;
1071                     wpa_printf(MSG_DEBUG,
1072                                  "GnuTLS: OCSP was not required, so allow connection to continue");
1073           }
1074 
1075           return 0;
1076 
1077 ocsp_error:
1078           gnutls_tls_fail_event(conn, NULL, 0, NULL,
1079                                     "bad certificate status response",
1080                                     TLS_FAIL_REVOKED);
1081           *err = GNUTLS_A_CERTIFICATE_REVOKED;
1082           return -1;
1083 #else /* GnuTLS 3.1.3 or newer */
1084           return 0;
1085 #endif /* GnuTLS 3.1.3 or newer */
1086 }
1087 
1088 
tls_match_suffix_helper(gnutls_x509_crt_t cert,const char * match,int full)1089 static int tls_match_suffix_helper(gnutls_x509_crt_t cert, const char *match,
1090                                            int full)
1091 {
1092           int res = -1;
1093 
1094 #if GNUTLS_VERSION_NUMBER >= 0x030300
1095           if (full)
1096                     res = gnutls_x509_crt_check_hostname2(
1097                               cert, match,
1098                               GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS);
1099 #endif /* >= 3.3.0 */
1100           if (res == -1)
1101                     res = gnutls_x509_crt_check_hostname(cert, match);
1102 
1103           wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s --> res=%d",
1104                        full ? "": "suffix ", match, res);
1105           return res;
1106 }
1107 
1108 
tls_match_suffix(gnutls_x509_crt_t cert,const char * match,int full)1109 static int tls_match_suffix(gnutls_x509_crt_t cert, const char *match,
1110                                   int full)
1111 {
1112           char *values, *token, *context = NULL;
1113           int ret = 0;
1114 
1115           if (!os_strchr(match, ';'))
1116                     return tls_match_suffix_helper(cert, match, full);
1117 
1118           values = os_strdup(match);
1119           if (!values)
1120                     return 0;
1121 
1122           /* Process each match alternative separately until a match is found */
1123           while ((token = str_token(values, ";", &context))) {
1124                     if (tls_match_suffix_helper(cert, token, full)) {
1125                               ret = 1;
1126                               break;
1127                     }
1128           }
1129 
1130           os_free(values);
1131           return ret;
1132 }
1133 
1134 
tls_connection_verify_peer(gnutls_session_t session)1135 static int tls_connection_verify_peer(gnutls_session_t session)
1136 {
1137           struct tls_connection *conn;
1138           unsigned int status, num_certs, i;
1139           struct os_time now;
1140           const gnutls_datum_t *certs;
1141           gnutls_x509_crt_t cert;
1142           gnutls_alert_description_t err;
1143           int res;
1144 
1145           conn = gnutls_session_get_ptr(session);
1146           if (!conn->verify_peer) {
1147                     wpa_printf(MSG_DEBUG,
1148                                  "GnuTLS: No peer certificate verification enabled");
1149                     return 0;
1150           }
1151 
1152           wpa_printf(MSG_DEBUG, "GnuTSL: Verifying peer certificate");
1153 
1154 #if GNUTLS_VERSION_NUMBER >= 0x030300
1155           {
1156                     gnutls_typed_vdata_st data[1];
1157                     unsigned int elements = 0;
1158 
1159                     os_memset(data, 0, sizeof(data));
1160                     if (!conn->global->server) {
1161                               data[elements].type = GNUTLS_DT_KEY_PURPOSE_OID;
1162                               data[elements].data = (void *) GNUTLS_KP_TLS_WWW_SERVER;
1163                               elements++;
1164                     }
1165                     res = gnutls_certificate_verify_peers(session, data, 1,
1166                                                                   &status);
1167           }
1168 #else /* < 3.3.0 */
1169           res = gnutls_certificate_verify_peers2(session, &status);
1170 #endif
1171           if (res < 0) {
1172                     wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
1173                                  "certificate chain");
1174                     err = GNUTLS_A_INTERNAL_ERROR;
1175                     goto out;
1176           }
1177 
1178 #if GNUTLS_VERSION_NUMBER >= 0x030104
1179           {
1180                     gnutls_datum_t info;
1181                     int ret, type;
1182 
1183                     type = gnutls_certificate_type_get(session);
1184                     ret = gnutls_certificate_verification_status_print(status, type,
1185                                                                                    &info, 0);
1186                     if (ret < 0) {
1187                               wpa_printf(MSG_DEBUG,
1188                                            "GnuTLS: Failed to print verification status");
1189                               err = GNUTLS_A_INTERNAL_ERROR;
1190                               goto out;
1191                     }
1192                     wpa_printf(MSG_DEBUG, "GnuTLS: %s", info.data);
1193                     gnutls_free(info.data);
1194           }
1195 #endif /* GnuTLS 3.1.4 or newer */
1196 
1197           certs = gnutls_certificate_get_peers(session, &num_certs);
1198           if (certs == NULL || num_certs == 0) {
1199                     wpa_printf(MSG_INFO, "TLS: No peer certificate chain received");
1200                     err = GNUTLS_A_UNKNOWN_CA;
1201                     goto out;
1202           }
1203 
1204           if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
1205                     wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
1206                     if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
1207                               wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
1208                                            "algorithm");
1209                               gnutls_tls_fail_event(conn, NULL, 0, NULL,
1210                                                         "certificate uses insecure algorithm",
1211                                                         TLS_FAIL_BAD_CERTIFICATE);
1212                               err = GNUTLS_A_INSUFFICIENT_SECURITY;
1213                               goto out;
1214                     }
1215                     if (status & GNUTLS_CERT_NOT_ACTIVATED) {
1216                               wpa_printf(MSG_INFO, "TLS: Certificate not yet "
1217                                            "activated");
1218                               gnutls_tls_fail_event(conn, NULL, 0, NULL,
1219                                                         "certificate not yet valid",
1220                                                         TLS_FAIL_NOT_YET_VALID);
1221                               err = GNUTLS_A_CERTIFICATE_EXPIRED;
1222                               goto out;
1223                     }
1224                     if (status & GNUTLS_CERT_EXPIRED) {
1225                               wpa_printf(MSG_INFO, "TLS: Certificate expired");
1226                               gnutls_tls_fail_event(conn, NULL, 0, NULL,
1227                                                         "certificate has expired",
1228                                                         TLS_FAIL_EXPIRED);
1229                               err = GNUTLS_A_CERTIFICATE_EXPIRED;
1230                               goto out;
1231                     }
1232                     gnutls_tls_fail_event(conn, NULL, 0, NULL,
1233                                               "untrusted certificate",
1234                                               TLS_FAIL_UNTRUSTED);
1235                     err = GNUTLS_A_INTERNAL_ERROR;
1236                     goto out;
1237           }
1238 
1239           if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
1240                     wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
1241                                  "known issuer");
1242                     gnutls_tls_fail_event(conn, NULL, 0, NULL, "signed not found",
1243                                               TLS_FAIL_UNTRUSTED);
1244                     err = GNUTLS_A_UNKNOWN_CA;
1245                     goto out;
1246           }
1247 
1248           if (status & GNUTLS_CERT_REVOKED) {
1249                     wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
1250                     gnutls_tls_fail_event(conn, NULL, 0, NULL,
1251                                               "certificate revoked",
1252                                               TLS_FAIL_REVOKED);
1253                     err = GNUTLS_A_CERTIFICATE_REVOKED;
1254                     goto out;
1255           }
1256 
1257           if (status != 0) {
1258                     wpa_printf(MSG_INFO, "TLS: Unknown verification status: %d",
1259                                  status);
1260                     err = GNUTLS_A_INTERNAL_ERROR;
1261                     goto out;
1262           }
1263 
1264           if (check_ocsp(conn, session, &err))
1265                     goto out;
1266 
1267           os_get_time(&now);
1268 
1269           for (i = 0; i < num_certs; i++) {
1270                     char *buf;
1271                     size_t len;
1272                     if (gnutls_x509_crt_init(&cert) < 0) {
1273                               wpa_printf(MSG_INFO, "TLS: Certificate initialization "
1274                                            "failed");
1275                               err = GNUTLS_A_BAD_CERTIFICATE;
1276                               goto out;
1277                     }
1278 
1279                     if (gnutls_x509_crt_import(cert, &certs[i],
1280                                                      GNUTLS_X509_FMT_DER) < 0) {
1281                               wpa_printf(MSG_INFO, "TLS: Could not parse peer "
1282                                            "certificate %d/%d", i + 1, num_certs);
1283                               gnutls_x509_crt_deinit(cert);
1284                               err = GNUTLS_A_BAD_CERTIFICATE;
1285                               goto out;
1286                     }
1287 
1288                     gnutls_x509_crt_get_dn(cert, NULL, &len);
1289                     len++;
1290                     buf = os_malloc(len + 1);
1291                     if (buf) {
1292                               buf[0] = buf[len] = '\0';
1293                               gnutls_x509_crt_get_dn(cert, buf, &len);
1294                     }
1295                     wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
1296                                  i + 1, num_certs, buf);
1297 
1298                     if (conn->global->event_cb) {
1299                               struct wpabuf *cert_buf = NULL;
1300                               union tls_event_data ev;
1301 #ifdef CONFIG_SHA256
1302                               u8 hash[32];
1303                               const u8 *_addr[1];
1304                               size_t _len[1];
1305 #endif /* CONFIG_SHA256 */
1306 
1307                               os_memset(&ev, 0, sizeof(ev));
1308                               if (conn->global->cert_in_cb) {
1309                                         cert_buf = wpabuf_alloc_copy(certs[i].data,
1310                                                                            certs[i].size);
1311                                         ev.peer_cert.cert = cert_buf;
1312                               }
1313 #ifdef CONFIG_SHA256
1314                               _addr[0] = certs[i].data;
1315                               _len[0] = certs[i].size;
1316                               if (sha256_vector(1, _addr, _len, hash) == 0) {
1317                                         ev.peer_cert.hash = hash;
1318                                         ev.peer_cert.hash_len = sizeof(hash);
1319                               }
1320 #endif /* CONFIG_SHA256 */
1321                               ev.peer_cert.depth = i;
1322                               ev.peer_cert.subject = buf;
1323                               conn->global->event_cb(conn->global->cb_ctx,
1324                                                          TLS_PEER_CERTIFICATE, &ev);
1325                               wpabuf_free(cert_buf);
1326                     }
1327 
1328                     if (i == 0) {
1329                               if (conn->suffix_match &&
1330                                   !tls_match_suffix(cert, conn->suffix_match, 0)) {
1331                                         wpa_printf(MSG_WARNING,
1332                                                      "TLS: Domain suffix match '%s' not found",
1333                                                      conn->suffix_match);
1334                                         gnutls_tls_fail_event(
1335                                                   conn, &certs[i], i, buf,
1336                                                   "Domain suffix mismatch",
1337                                                   TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
1338                                         err = GNUTLS_A_BAD_CERTIFICATE;
1339                                         gnutls_x509_crt_deinit(cert);
1340                                         os_free(buf);
1341                                         goto out;
1342                               }
1343 
1344 #if GNUTLS_VERSION_NUMBER >= 0x030300
1345                               if (conn->domain_match &&
1346                                   !tls_match_suffix(cert, conn->domain_match, 1)) {
1347                                         wpa_printf(MSG_WARNING,
1348                                                      "TLS: Domain match '%s' not found",
1349                                                      conn->domain_match);
1350                                         gnutls_tls_fail_event(
1351                                                   conn, &certs[i], i, buf,
1352                                                   "Domain mismatch",
1353                                                   TLS_FAIL_DOMAIN_MISMATCH);
1354                                         err = GNUTLS_A_BAD_CERTIFICATE;
1355                                         gnutls_x509_crt_deinit(cert);
1356                                         os_free(buf);
1357                                         goto out;
1358                               }
1359 #endif /* >= 3.3.0 */
1360 
1361                               /* TODO: validate altsubject_match.
1362                                * For now, any such configuration is rejected in
1363                                * tls_connection_set_params() */
1364 
1365 #if GNUTLS_VERSION_NUMBER < 0x030300
1366                               /*
1367                                * gnutls_certificate_verify_peers() not available, so
1368                                * need to check EKU separately.
1369                                */
1370                               if (!conn->global->server &&
1371                                   !server_eku_purpose(cert)) {
1372                                         wpa_printf(MSG_WARNING,
1373                                                      "GnuTLS: No server EKU");
1374                                         gnutls_tls_fail_event(
1375                                                   conn, &certs[i], i, buf,
1376                                                   "No server EKU",
1377                                                   TLS_FAIL_BAD_CERTIFICATE);
1378                                         err = GNUTLS_A_BAD_CERTIFICATE;
1379                                         gnutls_x509_crt_deinit(cert);
1380                                         os_free(buf);
1381                                         goto out;
1382                               }
1383 #endif /* < 3.3.0 */
1384                     }
1385 
1386                     if (!conn->disable_time_checks &&
1387                         (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
1388                          gnutls_x509_crt_get_activation_time(cert) > now.sec)) {
1389                               wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
1390                                            "not valid at this time",
1391                                            i + 1, num_certs);
1392                               gnutls_tls_fail_event(
1393                                         conn, &certs[i], i, buf,
1394                                         "Certificate is not valid at this time",
1395                                         TLS_FAIL_EXPIRED);
1396                               gnutls_x509_crt_deinit(cert);
1397                               os_free(buf);
1398                               err = GNUTLS_A_CERTIFICATE_EXPIRED;
1399                               goto out;
1400                     }
1401 
1402                     os_free(buf);
1403 
1404                     gnutls_x509_crt_deinit(cert);
1405           }
1406 
1407           if (conn->global->event_cb != NULL)
1408                     conn->global->event_cb(conn->global->cb_ctx,
1409                                                TLS_CERT_CHAIN_SUCCESS, NULL);
1410 
1411           return 0;
1412 
1413 out:
1414           conn->failed++;
1415           gnutls_alert_send(session, GNUTLS_AL_FATAL, err);
1416           return GNUTLS_E_CERTIFICATE_ERROR;
1417 }
1418 
1419 
gnutls_get_appl_data(struct tls_connection * conn)1420 static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
1421 {
1422           int res;
1423           struct wpabuf *ad;
1424           wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data");
1425           ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3);
1426           if (ad == NULL)
1427                     return NULL;
1428 
1429           res = gnutls_record_recv(conn->session, wpabuf_mhead(ad),
1430                                          wpabuf_size(ad));
1431           wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
1432           if (res < 0) {
1433                     wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
1434                                  "(%s)", __func__, (int) res,
1435                                  gnutls_strerror(res));
1436                     wpabuf_free(ad);
1437                     return NULL;
1438           }
1439 
1440           wpabuf_put(ad, res);
1441           wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data",
1442                        res);
1443           return ad;
1444 }
1445 
1446 
tls_connection_handshake(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data,struct wpabuf ** appl_data)1447 struct wpabuf * tls_connection_handshake(void *tls_ctx,
1448                                                    struct tls_connection *conn,
1449                                                    const struct wpabuf *in_data,
1450                                                    struct wpabuf **appl_data)
1451 {
1452           struct tls_global *global = tls_ctx;
1453           struct wpabuf *out_data;
1454           int ret;
1455 
1456           if (appl_data)
1457                     *appl_data = NULL;
1458 
1459           if (in_data && wpabuf_len(in_data) > 0) {
1460                     if (conn->pull_buf) {
1461                               wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1462                                            "pull_buf", __func__,
1463                                            (unsigned long) wpabuf_len(conn->pull_buf));
1464                               wpabuf_free(conn->pull_buf);
1465                     }
1466                     conn->pull_buf = wpabuf_dup(in_data);
1467                     if (conn->pull_buf == NULL)
1468                               return NULL;
1469                     conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1470           }
1471 
1472           ret = gnutls_handshake(conn->session);
1473           if (ret < 0) {
1474                     gnutls_alert_description_t alert;
1475                     union tls_event_data ev;
1476 
1477                     switch (ret) {
1478                     case GNUTLS_E_AGAIN:
1479                               if (global->server && conn->established &&
1480                                   conn->push_buf == NULL) {
1481                                         /* Need to return something to trigger
1482                                          * completion of EAP-TLS. */
1483                                         conn->push_buf = wpabuf_alloc(0);
1484                               }
1485                               break;
1486                     case GNUTLS_E_DH_PRIME_UNACCEPTABLE:
1487                               wpa_printf(MSG_DEBUG, "GnuTLS: Unacceptable DH prime");
1488                               if (conn->global->event_cb) {
1489                                         os_memset(&ev, 0, sizeof(ev));
1490                                         ev.alert.is_local = 1;
1491                                         ev.alert.type = "fatal";
1492                                         ev.alert.description = "insufficient security";
1493                                         conn->global->event_cb(conn->global->cb_ctx,
1494                                                                    TLS_ALERT, &ev);
1495                               }
1496                               /*
1497                                * Could send a TLS Alert to the server, but for now,
1498                                * simply terminate handshake.
1499                                */
1500                               conn->failed++;
1501                               conn->write_alerts++;
1502                               break;
1503                     case GNUTLS_E_FATAL_ALERT_RECEIVED:
1504                               alert = gnutls_alert_get(conn->session);
1505                               wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
1506                                            __func__, gnutls_alert_get_name(alert));
1507                               conn->read_alerts++;
1508                               if (conn->global->event_cb != NULL) {
1509                                         os_memset(&ev, 0, sizeof(ev));
1510                                         ev.alert.is_local = 0;
1511                                         ev.alert.type = gnutls_alert_get_name(alert);
1512                                         ev.alert.description = ev.alert.type;
1513                                         conn->global->event_cb(conn->global->cb_ctx,
1514                                                                    TLS_ALERT, &ev);
1515                               }
1516                               /* continue */
1517                     default:
1518                               wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
1519                                            "-> %s", __func__, gnutls_strerror(ret));
1520                               conn->failed++;
1521                     }
1522           } else {
1523                     size_t size;
1524 
1525                     wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
1526 
1527 #if GNUTLS_VERSION_NUMBER >= 0x03010a
1528                     {
1529                               char *desc;
1530 
1531                               desc = gnutls_session_get_desc(conn->session);
1532                               if (desc) {
1533                                         wpa_printf(MSG_DEBUG, "GnuTLS: %s", desc);
1534                                         gnutls_free(desc);
1535                               }
1536                     }
1537 #endif /* GnuTLS 3.1.10 or newer */
1538 
1539                     conn->established = 1;
1540                     if (conn->push_buf == NULL) {
1541                               /* Need to return something to get final TLS ACK. */
1542                               conn->push_buf = wpabuf_alloc(0);
1543                     }
1544 
1545                     gnutls_session_get_data(conn->session, NULL, &size);
1546                     if (global->session_data == NULL ||
1547                         global->session_data_size < size) {
1548                               os_free(global->session_data);
1549                               global->session_data = os_malloc(size);
1550                     }
1551                     if (global->session_data) {
1552                               global->session_data_size = size;
1553                               gnutls_session_get_data(conn->session,
1554                                                             global->session_data,
1555                                                             &global->session_data_size);
1556                     }
1557 
1558                     if (conn->pull_buf && appl_data)
1559                               *appl_data = gnutls_get_appl_data(conn);
1560           }
1561 
1562           out_data = conn->push_buf;
1563           conn->push_buf = NULL;
1564           return out_data;
1565 }
1566 
1567 
tls_connection_server_handshake(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data,struct wpabuf ** appl_data)1568 struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
1569                                                             struct tls_connection *conn,
1570                                                             const struct wpabuf *in_data,
1571                                                             struct wpabuf **appl_data)
1572 {
1573           return tls_connection_handshake(tls_ctx, conn, in_data, appl_data);
1574 }
1575 
1576 
tls_connection_encrypt(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data)1577 struct wpabuf * tls_connection_encrypt(void *tls_ctx,
1578                                                struct tls_connection *conn,
1579                                                const struct wpabuf *in_data)
1580 {
1581           ssize_t res;
1582           struct wpabuf *buf;
1583 
1584           res = gnutls_record_send(conn->session, wpabuf_head(in_data),
1585                                          wpabuf_len(in_data));
1586           if (res < 0) {
1587                     wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
1588                                  __func__, gnutls_strerror(res));
1589                     return NULL;
1590           }
1591 
1592           buf = conn->push_buf;
1593           conn->push_buf = NULL;
1594           return buf;
1595 }
1596 
1597 
tls_connection_decrypt(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data)1598 struct wpabuf * tls_connection_decrypt(void *tls_ctx,
1599                                                struct tls_connection *conn,
1600                                                const struct wpabuf *in_data)
1601 {
1602           ssize_t res;
1603           struct wpabuf *out;
1604 
1605           if (conn->pull_buf) {
1606                     wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1607                                  "pull_buf", __func__,
1608                                  (unsigned long) wpabuf_len(conn->pull_buf));
1609                     wpabuf_free(conn->pull_buf);
1610           }
1611           conn->pull_buf = wpabuf_dup(in_data);
1612           if (conn->pull_buf == NULL)
1613                     return NULL;
1614           conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1615 
1616           /*
1617            * Even though we try to disable TLS compression, it is possible that
1618            * this cannot be done with all TLS libraries. Add extra buffer space
1619            * to handle the possibility of the decrypted data being longer than
1620            * input data.
1621            */
1622           out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
1623           if (out == NULL)
1624                     return NULL;
1625 
1626           res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
1627                                          wpabuf_size(out));
1628           if (res < 0) {
1629                     wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
1630                                  "(%s)", __func__, (int) res, gnutls_strerror(res));
1631                     wpabuf_free(out);
1632                     return NULL;
1633           }
1634           wpabuf_put(out, res);
1635 
1636           return out;
1637 }
1638 
1639 
tls_connection_resumed(void * ssl_ctx,struct tls_connection * conn)1640 int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
1641 {
1642           if (conn == NULL)
1643                     return 0;
1644           return gnutls_session_is_resumed(conn->session);
1645 }
1646 
1647 
tls_connection_set_cipher_list(void * tls_ctx,struct tls_connection * conn,u8 * ciphers)1648 int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
1649                                            u8 *ciphers)
1650 {
1651           /* TODO */
1652           return -1;
1653 }
1654 
1655 
tls_get_version(void * ssl_ctx,struct tls_connection * conn,char * buf,size_t buflen)1656 int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
1657                         char *buf, size_t buflen)
1658 {
1659           gnutls_protocol_t ver;
1660 
1661           ver = gnutls_protocol_get_version(conn->session);
1662           if (ver == GNUTLS_TLS1_0)
1663                     os_strlcpy(buf, "TLSv1", buflen);
1664           else if (ver == GNUTLS_TLS1_1)
1665                     os_strlcpy(buf, "TLSv1.1", buflen);
1666           else if (ver == GNUTLS_TLS1_2)
1667                     os_strlcpy(buf, "TLSv1.2", buflen);
1668           else
1669                     return -1;
1670           return 0;
1671 }
1672 
1673 
tls_get_cipher(void * ssl_ctx,struct tls_connection * conn,char * buf,size_t buflen)1674 int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
1675                        char *buf, size_t buflen)
1676 {
1677           gnutls_cipher_algorithm_t cipher;
1678           gnutls_kx_algorithm_t kx;
1679           gnutls_mac_algorithm_t mac;
1680           const char *kx_str, *cipher_str, *mac_str;
1681           int res;
1682 
1683           cipher = gnutls_cipher_get(conn->session);
1684           cipher_str = gnutls_cipher_get_name(cipher);
1685           if (!cipher_str)
1686                     cipher_str = "";
1687 
1688           kx = gnutls_kx_get(conn->session);
1689           kx_str = gnutls_kx_get_name(kx);
1690           if (!kx_str)
1691                     kx_str = "";
1692 
1693           mac = gnutls_mac_get(conn->session);
1694           mac_str = gnutls_mac_get_name(mac);
1695           if (!mac_str)
1696                     mac_str = "";
1697 
1698           if (kx == GNUTLS_KX_RSA)
1699                     res = os_snprintf(buf, buflen, "%s-%s", cipher_str, mac_str);
1700           else
1701                     res = os_snprintf(buf, buflen, "%s-%s-%s",
1702                                           kx_str, cipher_str, mac_str);
1703           if (os_snprintf_error(buflen, res))
1704                     return -1;
1705 
1706           return 0;
1707 }
1708 
1709 
tls_connection_enable_workaround(void * ssl_ctx,struct tls_connection * conn)1710 int tls_connection_enable_workaround(void *ssl_ctx,
1711                                              struct tls_connection *conn)
1712 {
1713           gnutls_record_disable_padding(conn->session);
1714           return 0;
1715 }
1716 
1717 
tls_connection_client_hello_ext(void * ssl_ctx,struct tls_connection * conn,int ext_type,const u8 * data,size_t data_len)1718 int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
1719                                             int ext_type, const u8 *data,
1720                                             size_t data_len)
1721 {
1722           /* TODO */
1723           return -1;
1724 }
1725 
1726 
tls_connection_get_failed(void * ssl_ctx,struct tls_connection * conn)1727 int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
1728 {
1729           if (conn == NULL)
1730                     return -1;
1731           return conn->failed;
1732 }
1733 
1734 
tls_connection_get_read_alerts(void * ssl_ctx,struct tls_connection * conn)1735 int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
1736 {
1737           if (conn == NULL)
1738                     return -1;
1739           return conn->read_alerts;
1740 }
1741 
1742 
tls_connection_get_write_alerts(void * ssl_ctx,struct tls_connection * conn)1743 int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
1744 {
1745           if (conn == NULL)
1746                     return -1;
1747           return conn->write_alerts;
1748 }
1749 
1750 
tls_connection_set_session_ticket_cb(void * tls_ctx,struct tls_connection * conn,tls_session_ticket_cb cb,void * ctx)1751 int tls_connection_set_session_ticket_cb(void *tls_ctx,
1752                                                    struct tls_connection *conn,
1753                                                    tls_session_ticket_cb cb, void *ctx)
1754 {
1755           return -1;
1756 }
1757 
1758 
tls_get_library_version(char * buf,size_t buf_len)1759 int tls_get_library_version(char *buf, size_t buf_len)
1760 {
1761           return os_snprintf(buf, buf_len, "GnuTLS build=%s run=%s",
1762                                  GNUTLS_VERSION, gnutls_check_version(NULL));
1763 }
1764 
1765 
tls_connection_set_success_data(struct tls_connection * conn,struct wpabuf * data)1766 void tls_connection_set_success_data(struct tls_connection *conn,
1767                                              struct wpabuf *data)
1768 {
1769 }
1770 
1771 
tls_connection_set_success_data_resumed(struct tls_connection * conn)1772 void tls_connection_set_success_data_resumed(struct tls_connection *conn)
1773 {
1774 }
1775 
1776 
1777 const struct wpabuf *
tls_connection_get_success_data(struct tls_connection * conn)1778 tls_connection_get_success_data(struct tls_connection *conn)
1779 {
1780           return NULL;
1781 }
1782 
1783 
tls_connection_remove_session(struct tls_connection * conn)1784 void tls_connection_remove_session(struct tls_connection *conn)
1785 {
1786 }
1787