2 * OpenConnect (SSL + DTLS) VPN client
4 * Copyright © 2008-2012 Intel Corporation.
6 * Author: David Woodhouse <dwmw2@infradead.org>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * version 2.1, as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to:
20 * Free Software Foundation, Inc.
21 * 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301 USA
25 #include <sys/types.h>
27 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
40 #include <gnutls/gnutls.h>
41 #include <gnutls/x509.h>
42 #include <gnutls/crypto.h>
43 #include <gnutls/pkcs12.h>
45 #include "openconnect-internal.h"
47 /* OSX < 1.6 doesn't have AI_NUMERICSERV */
48 #ifndef AI_NUMERICSERV
49 #define AI_NUMERICSERV 0
52 /* Helper functions for reading/writing lines over SSL.
53 We could use cURL for the HTTP stuff, but it's overkill */
55 int openconnect_SSL_write(struct openconnect_info *vpninfo, char *buf, size_t len)
57 size_t orig_len = len;
60 int done = gnutls_record_send(vpninfo->https_sess, buf, len);
63 else if (done != GNUTLS_E_AGAIN) {
64 vpn_progress(vpninfo, PRG_ERR, _("Failed to write to SSL socket: %s"),
65 gnutls_strerror(done));
68 fd_set wr_set, rd_set;
69 int maxfd = vpninfo->ssl_fd;
74 if (gnutls_record_get_direction(vpninfo->https_sess))
75 FD_SET(vpninfo->ssl_fd, &wr_set);
77 FD_SET(vpninfo->ssl_fd, &rd_set);
79 if (vpninfo->cancel_fd != -1) {
80 FD_SET(vpninfo->cancel_fd, &rd_set);
81 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
82 maxfd = vpninfo->cancel_fd;
84 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
85 if (vpninfo->cancel_fd != -1 &&
86 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
87 vpn_progress(vpninfo, PRG_ERR, _("SSL write cancelled\n"));
95 int openconnect_SSL_read(struct openconnect_info *vpninfo, char *buf, size_t len)
99 while ((done = gnutls_record_recv(vpninfo->https_sess, buf, len)) < 0) {
100 fd_set wr_set, rd_set;
101 int maxfd = vpninfo->ssl_fd;
103 if (done != GNUTLS_E_AGAIN) {
104 vpn_progress(vpninfo, PRG_ERR, _("Failed to read from SSL socket: %s"),
105 gnutls_strerror(done));
111 if (gnutls_record_get_direction(vpninfo->https_sess))
112 FD_SET(vpninfo->ssl_fd, &wr_set);
114 FD_SET(vpninfo->ssl_fd, &rd_set);
116 if (vpninfo->cancel_fd != -1) {
117 FD_SET(vpninfo->cancel_fd, &rd_set);
118 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
119 maxfd = vpninfo->cancel_fd;
121 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
122 if (vpninfo->cancel_fd != -1 &&
123 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
124 vpn_progress(vpninfo, PRG_ERR, _("SSL read cancelled\n"));
132 int __attribute__ ((format (printf, 2, 3)))
133 openconnect_SSL_printf(struct openconnect_info *vpninfo, const char *fmt, ...)
141 vsnprintf(buf, 1023, fmt, args);
143 return openconnect_SSL_write(vpninfo, buf, strlen(buf));
147 int openconnect_SSL_gets(struct openconnect_info *vpninfo, char *buf, size_t len)
156 ret = gnutls_record_recv(vpninfo->https_sess, buf + i, 1);
158 if (buf[i] == '\n') {
160 if (i && buf[i-1] == '\r') {
172 } else if (ret != GNUTLS_E_AGAIN) {
173 vpn_progress(vpninfo, PRG_ERR, _("Failed to read from SSL socket: %s\n"),
174 gnutls_strerror(ret));
178 fd_set rd_set, wr_set;
179 int maxfd = vpninfo->ssl_fd;
184 if (gnutls_record_get_direction(vpninfo->https_sess))
185 FD_SET(vpninfo->ssl_fd, &wr_set);
187 FD_SET(vpninfo->ssl_fd, &rd_set);
189 if (vpninfo->cancel_fd != -1) {
190 FD_SET(vpninfo->cancel_fd, &rd_set);
191 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
192 maxfd = vpninfo->cancel_fd;
194 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
195 if (vpninfo->cancel_fd != -1 &&
196 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
197 vpn_progress(vpninfo, PRG_ERR, _("SSL read cancelled\n"));
207 static int request_passphrase(struct openconnect_info *vpninfo,
208 char **response, const char *fmt, ...)
210 struct oc_auth_form f;
211 struct oc_form_opt o;
217 memset(&f, 0, sizeof(f));
219 vsnprintf(buf, 1023, fmt, args);
222 f.auth_id = (char *)"gnutls_certificate";
226 o.type = OC_FORM_OPT_PASSWORD;
227 o.name = (char *)"passphrase";
231 ret = vpninfo->process_auth_form(vpninfo, &f);
240 static int load_datum(struct openconnect_info *vpninfo,
241 gnutls_datum_t *datum, const char *fname)
246 fd = open(fname, O_RDONLY|O_CLOEXEC);
249 vpn_progress(vpninfo, PRG_ERR,
250 _("Failed to open certificate file %s: %s\n"),
251 vpninfo->cert, strerror(err));
254 if (fstat(fd, &st)) {
256 vpn_progress(vpninfo, PRG_ERR,
257 _("Failed to stat certificate file %s: %s\n"),
258 vpninfo->cert, strerror(err));
262 datum->size = st.st_size;
263 datum->data = gnutls_malloc(st.st_size);
265 vpn_progress(vpninfo, PRG_ERR,
266 _("Failed to allocate certificate buffer\n"));
271 if (read(fd, datum->data, datum->size) != datum->size) {
273 vpn_progress(vpninfo, PRG_ERR,
274 _("Failed to read certificate into memory: %s\n"),
277 gnutls_free(datum->data);
284 static int load_pkcs12_certificate(struct openconnect_info *vpninfo,
285 gnutls_datum_t *datum)
291 err = gnutls_pkcs12_init(&p12);
293 vpn_progress(vpninfo, PRG_ERR,
294 _("Failed to setup PKCS#12 data structure: %s\n"),
295 gnutls_strerror(err));
299 err = gnutls_pkcs12_import(p12, datum, GNUTLS_X509_FMT_DER, 0);
301 gnutls_pkcs12_deinit(p12);
302 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN)
303 return 1; /* Try PEM */
304 vpn_progress(vpninfo, PRG_ERR,
305 _("Failed to import PKCS#12 file: %s\n"),
306 gnutls_strerror(err));
310 pass = vpninfo->cert_password;
311 while (gnutls_pkcs12_verify_mac(p12, pass)) {
313 vpn_progress(vpninfo, PRG_ERR,
314 _("Failed to decrypt PKCS#12 certificate file\n"));
316 err = request_passphrase(vpninfo, &pass,
317 _("Enter PKCS#12 pass phrase:"));
319 gnutls_pkcs12_deinit(p12);
323 /* We can't actually *use* this gnutls_pkcs12_t, AFAICT.
324 We have to let GnuTLS re-import it all again. */
325 gnutls_pkcs12_deinit(p12);
327 err = gnutls_certificate_set_x509_simple_pkcs12_mem(vpninfo->https_cred, datum,
328 GNUTLS_X509_FMT_DER, pass);
331 vpn_progress(vpninfo, PRG_ERR,
332 _("Failed to load PKCS#12 certificate: %s\n"),
333 gnutls_strerror(err));
339 static int load_certificate(struct openconnect_info *vpninfo)
341 gnutls_datum_t fdata;
342 gnutls_x509_crt_t cert;
343 gnutls_x509_privkey_t key;
346 if (vpninfo->cert_type == CERT_TYPE_TPM) {
347 vpn_progress(vpninfo, PRG_ERR,
348 _("TPM support not available with GnuTLS\n"));
352 if (!strncmp(vpninfo->cert, "pkcs11:", 7)) {
353 vpn_progress(vpninfo, PRG_TRACE,
354 _("Using PKCS#11 certificate %s\n"), vpninfo->cert);
356 err = gnutls_certificate_set_x509_key_file(vpninfo->https_cred,
359 GNUTLS_X509_FMT_PEM);
361 vpn_progress(vpninfo, PRG_ERR,
362 _("Error loading PKCS#11 certificate: %s\n"),
363 gnutls_strerror(err));
369 vpn_progress(vpninfo, PRG_TRACE,
370 _("Using certificate file %s\n"), vpninfo->cert);
372 err = load_datum(vpninfo, &fdata, vpninfo->cert);
376 if (vpninfo->cert_type == CERT_TYPE_PKCS12 ||
377 vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
378 err = load_pkcs12_certificate(vpninfo, &fdata);
379 /* Either it's printed and error and failed, or it's succeeded */
381 gnutls_free(fdata.data);
384 /* ... or it falls through to try PEM formats */
387 gnutls_x509_crt_init(&cert);
388 err = gnutls_x509_crt_import(cert, &fdata, GNUTLS_X509_FMT_PEM);
390 vpn_progress(vpninfo, PRG_ERR,
391 _("Loading certificate failed: %s\n"),
392 gnutls_strerror(err));
393 gnutls_free(fdata.data);
397 if (vpninfo->sslkey != vpninfo->cert) {
398 gnutls_free(fdata.data);
400 vpn_progress(vpninfo, PRG_TRACE,
401 _("Using private key file %s\n"), vpninfo->cert);
403 err = load_datum(vpninfo, &fdata, vpninfo->sslkey);
405 gnutls_x509_crt_deinit(cert);
410 gnutls_x509_privkey_init(&key);
411 /* Try PKCS#1 (and PKCS#8 without password) first. GnuTLS doesn't
412 support OpenSSL's old PKCS#1-based encrypted format. We should
413 probably check for it and give a more coherent failure mode. */
414 err = gnutls_x509_privkey_import(key, &fdata, GNUTLS_X509_FMT_PEM);
416 /* If that fails, try PKCS#8 */
417 char *pass = vpninfo->cert_password;
419 /* Yay, just for fun this is *different* to PKCS#12. Where we could
420 try an empty password there, in this case the empty-password case
421 has already been *tried* by gnutls_x509_privkey_import(). If we
422 just call gnutls_x509_privkey_import_pkcs8() with a NULL password,
423 it'll SEGV. You have to set the GNUTLS_PKCS_PLAIN flag if you want
424 to try without a password. Passing NULL evidently isn't enough of
426 while ((err = gnutls_x509_privkey_import_pkcs8(key, &fdata,
429 if (err != GNUTLS_E_DECRYPTION_FAILED) {
430 vpn_progress(vpninfo, PRG_ERR,
431 _("Failed to load private key as PKCS#8: %s\n"),
432 gnutls_strerror(err));
433 gnutls_x509_crt_deinit(cert);
434 gnutls_free(fdata.data);
438 vpn_progress(vpninfo, PRG_ERR,
439 _("Failed to decrypt PKCS#8 certificate file\n"));
442 err = request_passphrase(vpninfo, &pass,
443 _("Enter PEM pass phrase:"));
445 gnutls_x509_crt_deinit(cert);
446 gnutls_free(fdata.data);
451 /* FIXME: We need to work around OpenSSL RT#1942 on the server, by including
452 as much of the chain of issuer certificates as we can. */
453 err = gnutls_certificate_set_x509_key(vpninfo->https_cred,
455 gnutls_x509_privkey_deinit(key);
456 gnutls_x509_crt_deinit(cert);
457 gnutls_free(fdata.data);
459 vpn_progress(vpninfo, PRG_ERR,
460 _("Setting certificate failed: %s\n"),
461 gnutls_strerror(err));
467 static int get_cert_fingerprint(struct openconnect_info *vpninfo,
468 gnutls_x509_crt_t cert,
469 gnutls_digest_algorithm_t algo,
472 unsigned char md[256];
473 size_t md_size = sizeof(md);
476 if (gnutls_x509_crt_get_fingerprint(cert, algo, md, &md_size))
479 for (i=0; i < md_size; i++)
480 sprintf(&buf[i*2], "%02X", md[i]);
485 int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
486 OPENCONNECT_X509 *cert, char *buf)
488 return get_cert_fingerprint(vpninfo, cert, GNUTLS_DIG_MD5, buf);
491 int openconnect_get_cert_sha1(struct openconnect_info *vpninfo,
492 OPENCONNECT_X509 *cert, char *buf)
494 return get_cert_fingerprint(vpninfo, cert, GNUTLS_DIG_SHA1, buf);
497 static int check_server_cert(struct openconnect_info *vpninfo, OPENCONNECT_X509 *cert)
499 char fingerprint[41];
502 ret = openconnect_get_cert_sha1(vpninfo, cert, fingerprint);
506 if (strcasecmp(vpninfo->servercert, fingerprint)) {
507 vpn_progress(vpninfo, PRG_ERR,
508 _("Server SSL certificate didn't match: %s\n"), fingerprint);
514 char *openconnect_get_cert_details(struct openconnect_info *vpninfo,
515 OPENCONNECT_X509 *cert)
520 if (gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL, &buf))
523 /* Just in case gnutls_free() isn't free(), we can't steal it. */
524 ret = strdup((char *)buf.data);
525 gnutls_free(buf.data);
530 int openconnect_get_cert_DER(struct openconnect_info *vpninfo,
531 OPENCONNECT_X509 *cert, unsigned char **buf)
534 unsigned char *ret = NULL;
536 if (gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, ret, &l) !=
537 GNUTLS_E_SHORT_MEMORY_BUFFER)
544 if (gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, ret, &l)) {
552 static int verify_peer(struct openconnect_info *vpninfo, SSL *https_ssl)
557 peer_cert = SSL_get_peer_certificate(https_ssl);
559 if (vpninfo->servercert) {
560 /* If given a cert fingerprint on the command line, that's
562 ret = check_server_cert(vpninfo, peer_cert);
564 int vfy = SSL_get_verify_result(https_ssl);
565 const char *err_string = NULL;
567 if (vfy != X509_V_OK)
568 err_string = X509_verify_cert_error_string(vfy);
569 else if (match_cert_hostname(vpninfo, peer_cert))
570 err_string = _("certificate does not match hostname");
573 vpn_progress(vpninfo, PRG_INFO,
574 _("Server certificate verify failed: %s\n"),
577 if (vpninfo->validate_peer_cert)
578 ret = vpninfo->validate_peer_cert(vpninfo->cbdata,
587 X509_free(peer_cert);
592 static void workaround_openssl_certchain_bug(struct openconnect_info *vpninfo)
594 /* OpenSSL has problems with certificate chains -- if there are
595 multiple certs with the same name, it doesn't necessarily
596 choose the _right_ one. (RT#1942)
597 Pick the right ones for ourselves and add them manually. */
599 /* FIXME: Of course we still have to do this with GnuTLS, to work
600 around the issue on the server side */
603 static int check_certificate_expiry(struct openconnect_info *vpninfo)
609 const char *reason = NULL;
613 if (!vpninfo->cert_x509)
617 notAfter = X509_get_notAfter(vpninfo->cert_x509);
618 i = X509_cmp_time(notAfter, &t);
620 vpn_progress(vpninfo, PRG_ERR,
621 _("Error in client cert notAfter field\n"));
624 reason = _("Client certificate has expired at");
626 t += vpninfo->cert_expire_warning;
627 i = X509_cmp_time(notAfter, &t);
629 reason = _("Client certificate expires soon at");
633 BIO *bp = BIO_new(BIO_s_mem());
635 const char *expiry = _("<error>");
639 ASN1_TIME_print(bp, notAfter);
640 BIO_write(bp, &zero, 1);
641 BIO_get_mem_ptr(bp, &bm);
644 vpn_progress(vpninfo, PRG_ERR, "%s: %s\n", reason, expiry);
652 static int cancellable_connect(struct openconnect_info *vpninfo, int sockfd,
653 const struct sockaddr *addr, socklen_t addrlen)
655 struct sockaddr_storage peer;
656 socklen_t peerlen = sizeof(peer);
657 fd_set wr_set, rd_set;
660 fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK);
662 if (connect(sockfd, addr, addrlen) < 0 && errno != EINPROGRESS)
667 FD_SET(sockfd, &wr_set);
668 if (vpninfo->cancel_fd != -1) {
669 FD_SET(vpninfo->cancel_fd, &rd_set);
670 if (vpninfo->cancel_fd > sockfd)
671 maxfd = vpninfo->cancel_fd;
674 /* Later we'll render this whole exercise non-pointless by
675 including a 'cancelfd' here too. */
676 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
677 if (vpninfo->cancel_fd != -1 && FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
678 vpn_progress(vpninfo, PRG_ERR, _("Socket connect cancelled\n"));
683 /* Check whether connect() succeeded or failed by using
684 getpeername(). See http://cr.yp.to/docs/connect.html */
685 return getpeername(sockfd, (void *)&peer, &peerlen);
688 int openconnect_open_https(struct openconnect_info *vpninfo)
693 if (vpninfo->https_sess)
699 if (vpninfo->peer_addr) {
701 ssl_sock = socket(vpninfo->peer_addr->sa_family, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_IP);
705 ssl_sock = socket(vpninfo->peer_addr->sa_family, SOCK_STREAM, IPPROTO_IP);
708 fcntl(ssl_sock, F_SETFD, fcntl(ssl_sock, F_GETFD) | FD_CLOEXEC);
710 if (cancellable_connect(vpninfo, ssl_sock, vpninfo->peer_addr, vpninfo->peer_addrlen)) {
712 if (vpninfo->proxy) {
713 vpn_progress(vpninfo, PRG_ERR,
714 _("Failed to reconnect to proxy %s\n"),
717 vpn_progress(vpninfo, PRG_ERR,
718 _("Failed to reconnect to host %s\n"),
725 struct addrinfo hints, *result, *rp;
729 memset(&hints, 0, sizeof(struct addrinfo));
730 hints.ai_family = AF_UNSPEC;
731 hints.ai_socktype = SOCK_STREAM;
732 hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
733 hints.ai_protocol = 0;
734 hints.ai_canonname = NULL;
735 hints.ai_addr = NULL;
736 hints.ai_next = NULL;
738 /* The 'port' variable is a string because it's easier
739 this way than if we pass NULL to getaddrinfo() and
740 then try to fill in the numeric value into
741 different types of returned sockaddr_in{6,}. */
743 if (vpninfo->proxy_factory) {
748 free(vpninfo->proxy_type);
749 vpninfo->proxy_type = NULL;
750 free(vpninfo->proxy);
751 vpninfo->proxy = NULL;
753 if (vpninfo->port == 443)
754 i = asprintf(&url, "https://%s/%s", vpninfo->hostname,
755 vpninfo->urlpath?:"");
757 i = asprintf(&url, "https://%s:%d/%s", vpninfo->hostname,
758 vpninfo->port, vpninfo->urlpath?:"");
762 proxies = px_proxy_factory_get_proxies(vpninfo->proxy_factory,
766 while (proxies && proxies[i]) {
767 if (!vpninfo->proxy &&
768 (!strncmp(proxies[i], "http://", 7) ||
769 !strncmp(proxies[i], "socks://", 8) ||
770 !strncmp(proxies[i], "socks5://", 9)))
771 internal_parse_url(proxies[i], &vpninfo->proxy_type,
772 &vpninfo->proxy, &vpninfo->proxy_port,
779 vpn_progress(vpninfo, PRG_TRACE,
780 _("Proxy from libproxy: %s://%s:%d/\n"),
781 vpninfo->proxy_type, vpninfo->proxy, vpninfo->port);
784 if (vpninfo->proxy) {
785 hostname = vpninfo->proxy;
786 snprintf(port, 6, "%d", vpninfo->proxy_port);
788 hostname = vpninfo->hostname;
789 snprintf(port, 6, "%d", vpninfo->port);
792 if (hostname[0] == '[' && hostname[strlen(hostname)-1] == ']') {
793 /* Solaris has no strndup(). */
794 int len = strlen(hostname) - 2;
795 char *new_hostname = malloc(len + 1);
798 memcpy(new_hostname, hostname + 1, len);
799 new_hostname[len] = 0;
801 hostname = new_hostname;
802 hints.ai_flags |= AI_NUMERICHOST;
805 err = getaddrinfo(hostname, port, &hints, &result);
806 if (hints.ai_flags & AI_NUMERICHOST)
810 vpn_progress(vpninfo, PRG_ERR,
811 _("getaddrinfo failed for host '%s': %s\n"),
812 hostname, gai_strerror(err));
816 for (rp = result; rp ; rp = rp->ai_next) {
819 if (!getnameinfo(rp->ai_addr, rp->ai_addrlen, host,
820 sizeof(host), NULL, 0, NI_NUMERICHOST))
821 vpn_progress(vpninfo, PRG_INFO,
822 _("Attempting to connect to %s%s%s:%s\n"),
823 rp->ai_family == AF_INET6?"[":"",
825 rp->ai_family == AF_INET6?"]":"",
828 ssl_sock = socket(rp->ai_family, rp->ai_socktype,
832 if (cancellable_connect(vpninfo, ssl_sock, rp->ai_addr, rp->ai_addrlen) >= 0) {
833 /* Store the peer address we actually used, so that DTLS can
834 use it again later */
835 vpninfo->peer_addr = malloc(rp->ai_addrlen);
836 if (!vpninfo->peer_addr) {
837 vpn_progress(vpninfo, PRG_ERR,
838 _("Failed to allocate sockaddr storage\n"));
842 vpninfo->peer_addrlen = rp->ai_addrlen;
843 memcpy(vpninfo->peer_addr, rp->ai_addr, rp->ai_addrlen);
849 freeaddrinfo(result);
852 vpn_progress(vpninfo, PRG_ERR,
853 _("Failed to connect to host %s\n"),
854 vpninfo->proxy?:vpninfo->hostname);
859 if (vpninfo->proxy) {
860 err = process_proxy(vpninfo, ssl_sock);
867 if (!vpninfo->https_cred) {
868 gnutls_certificate_allocate_credentials(&vpninfo->https_cred);
869 gnutls_certificate_set_x509_trust_file(vpninfo->https_cred,
870 "/etc/pki/tls/certs/ca-bundle.crt",
871 GNUTLS_X509_FMT_PEM);
873 /* FIXME: Ensure TLSv1.0, no options */
876 err = load_certificate(vpninfo);
878 vpn_progress(vpninfo, PRG_ERR,
879 _("Loading certificate failed. Aborting.\n"));
882 check_certificate_expiry(vpninfo);
885 /* We just want to do:
886 SSL_CTX_set_purpose(vpninfo->https_ctx, X509_PURPOSE_ANY);
887 ... but it doesn't work with OpenSSL < 0.9.8k because of
888 problems with inheritance (fixed in v1.1.4.6 of
889 crypto/x509/x509_vpm.c) so we have to play silly buggers
890 instead. This trick doesn't work _either_ in < 0.9.7 but
891 I don't know of _any_ workaround which will, and can't
892 be bothered to find out either. */
894 if (vpninfo->cafile) {
895 err = gnutls_certificate_set_x509_trust_file(vpninfo->https_cred,
897 GNUTLS_X509_FMT_PEM);
899 vpn_progress(vpninfo, PRG_ERR,
900 _("Failed to open CA file '%s': %s\n"),
901 vpninfo->cafile, gnutls_strerror(err));
908 gnutls_init (&vpninfo->https_sess, GNUTLS_CLIENT);
909 err = gnutls_priority_set_direct (vpninfo->https_sess, "NONE:+VERS-TLS1.0:+SHA1:+AES-128-CBC:+RSA:+COMP-NULL:%COMPAT:%DISABLE_SAFE_RENEGOTIATION", NULL);
911 vpn_progress(vpninfo, PRG_ERR,
912 _("Failed to set TLS priority string: %s\n"),
913 gnutls_strerror(err));
917 gnutls_record_disable_padding (vpninfo->https_sess);
918 workaround_openssl_certchain_bug(vpninfo);
919 gnutls_credentials_set (vpninfo->https_sess, GNUTLS_CRD_CERTIFICATE, vpninfo->https_cred);
920 gnutls_transport_set_ptr(vpninfo->https_sess, /* really? */(gnutls_transport_ptr_t)(long) ssl_sock);
922 vpn_progress(vpninfo, PRG_INFO, _("SSL negotiation with %s\n"),
925 while ((err = gnutls_handshake (vpninfo->https_sess))) {
926 if (err == GNUTLS_E_AGAIN) {
927 fd_set rd_set, wr_set;
928 int maxfd = ssl_sock;
933 if (gnutls_record_get_direction(vpninfo->https_sess))
934 FD_SET(ssl_sock, &wr_set);
936 FD_SET(ssl_sock, &rd_set);
938 if (vpninfo->cancel_fd != -1) {
939 FD_SET(vpninfo->cancel_fd, &rd_set);
940 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
941 maxfd = vpninfo->cancel_fd;
943 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
944 if (vpninfo->cancel_fd != -1 &&
945 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
946 vpn_progress(vpninfo, PRG_ERR, _("SSL connection cancelled\n"));
947 gnutls_deinit(vpninfo->https_sess);
948 vpninfo->https_sess = NULL;
952 } else if (err == GNUTLS_E_INTERRUPTED || gnutls_error_is_fatal(err)) {
953 vpn_progress(vpninfo, PRG_ERR, _("SSL connection failure: %s\n"),
954 gnutls_strerror(err));
955 gnutls_deinit(vpninfo->https_sess);
956 vpninfo->https_sess = NULL;
960 /* non-fatal error or warning. Ignore it and continue */
961 vpn_progress(vpninfo, PRG_TRACE,
962 _("GnuTLS non-fatal return during handshake: %s\n"),
963 gnutls_strerror(err));
967 if (verify_peer(vpninfo, https_ssl)) {
973 vpninfo->ssl_fd = ssl_sock;
975 vpn_progress(vpninfo, PRG_INFO, _("Connected to HTTPS on %s\n"),
981 void openconnect_close_https(struct openconnect_info *vpninfo)
984 if (vpninfo->peer_cert) {
985 X509_free(vpninfo->peer_cert);
986 vpninfo->peer_cert = NULL;
989 if (vpninfo->https_sess) {
990 gnutls_deinit(vpninfo->https_sess);
991 vpninfo->https_sess = NULL;
993 if (vpninfo->ssl_fd != -1) {
994 close(vpninfo->ssl_fd);
995 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds);
996 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
997 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds);
998 vpninfo->ssl_fd = -1;
1002 void openconnect_init_openssl(void)
1004 gnutls_global_init();
1007 int openconnect_sha1(unsigned char *result, void *data, int datalen)
1010 size_t shalen = SHA1_SIZE;
1014 if (gnutls_fingerprint(GNUTLS_DIG_SHA1, &d, result, &shalen))
1020 int openconnect_random(void *bytes, int len)
1022 if (gnutls_rnd(GNUTLS_RND_RANDOM, bytes, len))
1027 int openconnect_local_cert_md5(struct openconnect_info *vpninfo,
1030 const gnutls_datum_t *d;
1035 d = gnutls_certificate_get_ours(vpninfo->https_sess);
1039 if (gnutls_fingerprint(GNUTLS_DIG_MD5, d, buf, &md5len))