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 check_certificate_expiry(struct openconnect_info *vpninfo, gnutls_x509_crt_t cert)
242 const char *reason = NULL;
243 time_t expires = gnutls_x509_crt_get_expiration_time(cert);
244 time_t now = time(NULL);
247 vpn_progress(vpninfo, PRG_ERR,
248 _("Could not extract expiration time of certificate\n"));
253 reason = _("Client certificate has expired at");
254 else if (expires < now + vpninfo->cert_expire_warning)
255 reason = _("Client certificate expires soon at");
261 gmtime_r(&expires, &tm);
262 strftime(buf, 80, "%a, %d %b %Y %T %Z", &tm);
264 vpn_progress(vpninfo, PRG_ERR, "%s: %s\n", reason, buf);
269 static int load_datum(struct openconnect_info *vpninfo,
270 gnutls_datum_t *datum, const char *fname)
275 fd = open(fname, O_RDONLY|O_CLOEXEC);
278 vpn_progress(vpninfo, PRG_ERR,
279 _("Failed to open certificate file %s: %s\n"),
280 vpninfo->cert, strerror(err));
283 if (fstat(fd, &st)) {
285 vpn_progress(vpninfo, PRG_ERR,
286 _("Failed to stat certificate file %s: %s\n"),
287 vpninfo->cert, strerror(err));
291 datum->size = st.st_size;
292 datum->data = gnutls_malloc(st.st_size);
294 vpn_progress(vpninfo, PRG_ERR,
295 _("Failed to allocate certificate buffer\n"));
300 if (read(fd, datum->data, datum->size) != datum->size) {
302 vpn_progress(vpninfo, PRG_ERR,
303 _("Failed to read certificate into memory: %s\n"),
306 gnutls_free(datum->data);
313 /* Pull in our local copy of GnuTLS's parse_pkcs12() function, for now */
314 #include "gnutls_pkcs12.c"
316 /* A non-zero, non-error return to make load_certificate() continue and
317 interpreting the file as other types */
320 static int load_pkcs12_certificate(struct openconnect_info *vpninfo,
321 gnutls_datum_t *datum,
322 gnutls_x509_privkey_t *key,
323 gnutls_x509_crt_t *cert,
324 gnutls_x509_crt_t **extra_certs,
325 unsigned int *nr_extra_certs,
326 gnutls_x509_crl_t *crl)
332 err = gnutls_pkcs12_init(&p12);
334 vpn_progress(vpninfo, PRG_ERR,
335 _("Failed to setup PKCS#12 data structure: %s\n"),
336 gnutls_strerror(err));
340 err = gnutls_pkcs12_import(p12, datum, GNUTLS_X509_FMT_DER, 0);
342 gnutls_pkcs12_deinit(p12);
343 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN)
345 vpn_progress(vpninfo, PRG_ERR,
346 _("Failed to import PKCS#12 file: %s\n"),
347 gnutls_strerror(err));
351 pass = vpninfo->cert_password;
352 while ((err = gnutls_pkcs12_verify_mac(p12, pass)) == GNUTLS_E_MAC_VERIFY_FAILED) {
354 vpn_progress(vpninfo, PRG_ERR,
355 _("Failed to decrypt PKCS#12 certificate file\n"));
357 vpninfo->cert_password = NULL;
358 err = request_passphrase(vpninfo, &pass,
359 _("Enter PKCS#12 pass phrase:"));
361 gnutls_pkcs12_deinit(p12);
365 /* If it wasn't GNUTLS_E_MAC_VERIFY_FAILED, then the problem wasn't just a
366 bad password. Give up. */
371 gnutls_pkcs12_deinit(p12);
373 /* If the first attempt, and we didn't know for sure it was PKCS#12
374 anyway, bail out and try loading it as something different. */
375 if (pass == vpninfo->cert_password &&
376 vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
377 /* Make it non-fatal... */
382 vpn_progress(vpninfo, level,
383 _("Failed to process PKCS#12 file: %s\n"),
384 gnutls_strerror(err));
388 err = parse_pkcs12(vpninfo->https_cred, p12, pass, key, cert,
389 extra_certs, nr_extra_certs, crl);
390 gnutls_pkcs12_deinit(p12);
392 vpn_progress(vpninfo, PRG_ERR,
393 _("Failed to load PKCS#12 certificate: %s\n"),
394 gnutls_strerror(err));
400 /* Older versions of GnuTLS didn't actually bother to check this, so we'll
402 static int check_issuer_sanity(gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer)
404 #if GNUTLS_VERSION_NUMBER > 0x300014
407 unsigned char id1[512], id2[512];
408 size_t id1_size = 512, id2_size = 512;
411 err = gnutls_x509_crt_get_authority_key_id(cert, id1, &id1_size, NULL);
415 err = gnutls_x509_crt_get_subject_key_id(issuer, id2, &id2_size, NULL);
418 if (id1_size == id2_size && !memcmp(id1, id2, id1_size))
426 static int load_certificate(struct openconnect_info *vpninfo)
428 gnutls_datum_t fdata;
429 gnutls_x509_privkey_t key = NULL;
430 gnutls_x509_crl_t crl = NULL;
431 gnutls_x509_crt_t last_cert, cert = NULL;
432 gnutls_x509_crt_t *extra_certs = NULL, *supporting_certs = NULL;
433 unsigned int nr_supporting_certs, nr_extra_certs = 0;
434 int err; /* GnuTLS error */
435 int ret = 0; /* our error (zero or -errno) */
438 if (vpninfo->cert_type == CERT_TYPE_TPM) {
439 vpn_progress(vpninfo, PRG_ERR,
440 _("TPM support not available with GnuTLS\n"));
444 if (!strncmp(vpninfo->cert, "pkcs11:", 7)) {
445 vpn_progress(vpninfo, PRG_TRACE,
446 _("Using PKCS#11 certificate %s\n"), vpninfo->cert);
448 err = gnutls_certificate_set_x509_key_file(vpninfo->https_cred,
451 GNUTLS_X509_FMT_PEM);
453 vpn_progress(vpninfo, PRG_ERR,
454 _("Error loading PKCS#11 certificate: %s\n"),
455 gnutls_strerror(err));
461 vpn_progress(vpninfo, PRG_TRACE,
462 _("Using certificate file %s\n"), vpninfo->cert);
464 ret = load_datum(vpninfo, &fdata, vpninfo->cert);
468 if (vpninfo->cert_type == CERT_TYPE_PKCS12 ||
469 vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
470 ret = load_pkcs12_certificate(vpninfo, &fdata, &key, &cert,
471 &extra_certs, &nr_extra_certs, &crl);
473 gnutls_free(fdata.data);
478 /* It returned NOT_PKCS12.
479 Fall through to try PEM formats. */
482 gnutls_x509_crt_init(&cert);
483 err = gnutls_x509_crt_import(cert, &fdata, GNUTLS_X509_FMT_PEM);
485 vpn_progress(vpninfo, PRG_ERR,
486 _("Loading certificate failed: %s\n"),
487 gnutls_strerror(err));
488 gnutls_free(fdata.data);
492 if (vpninfo->sslkey != vpninfo->cert) {
493 gnutls_free(fdata.data);
495 vpn_progress(vpninfo, PRG_TRACE,
496 _("Using private key file %s\n"), vpninfo->cert);
498 ret = load_datum(vpninfo, &fdata, vpninfo->sslkey);
503 gnutls_x509_privkey_init(&key);
504 /* Try PKCS#1 (and PKCS#8 without password) first. GnuTLS doesn't
505 support OpenSSL's old PKCS#1-based encrypted format. We should
506 probably check for it and give a more coherent failure mode. */
507 err = gnutls_x509_privkey_import(key, &fdata, GNUTLS_X509_FMT_PEM);
509 /* If that fails, try PKCS#8 */
510 char *pass = vpninfo->cert_password;
512 /* Yay, just for fun this is *different* to PKCS#12. Where we could
513 try an empty password there, in this case the empty-password case
514 has already been *tried* by gnutls_x509_privkey_import(). If we
515 just call gnutls_x509_privkey_import_pkcs8() with a NULL password,
516 it'll SEGV. You have to set the GNUTLS_PKCS_PLAIN flag if you want
517 to try without a password. Passing NULL evidently isn't enough of
519 while ((err = gnutls_x509_privkey_import_pkcs8(key, &fdata,
522 if (err != GNUTLS_E_DECRYPTION_FAILED) {
523 vpn_progress(vpninfo, PRG_ERR,
524 _("Failed to load private key as PKCS#8: %s\n"),
525 gnutls_strerror(err));
530 vpn_progress(vpninfo, PRG_ERR,
531 _("Failed to decrypt PKCS#8 certificate file\n"));
534 err = request_passphrase(vpninfo, &pass,
535 _("Enter PEM pass phrase:"));
543 check_certificate_expiry(vpninfo, cert);
546 err = gnutls_certificate_set_x509_crl(vpninfo->https_cred, &crl, 1);
548 vpn_progress(vpninfo, PRG_ERR,
549 _("Setting certificate recovation list failed: %s\n"),
550 gnutls_strerror(err));
555 /* OpenSSL has problems with certificate chains — if there are
556 multiple certs with the same name, it doesn't necessarily
557 choose the _right_ one. (RT#1942)
558 Pick the right ones for ourselves and add them manually. */
560 nr_supporting_certs = 1; /* Our starting cert */
562 gnutls_x509_crt_t issuer;
566 for (i = 0; i < nr_extra_certs; i++) {
567 if (gnutls_x509_crt_check_issuer(last_cert, extra_certs[i]) &&
568 !check_issuer_sanity(last_cert, extra_certs[i]))
572 if (i < nr_extra_certs) {
573 issuer = extra_certs[i];
575 err = gnutls_certificate_get_issuer(vpninfo->https_cred,
576 last_cert, &issuer, 0);
578 printf("can't get issuer for %p: %s\n",
579 last_cert, gnutls_strerror(err));
584 /* The check_issuer_sanity() function works fine as a workaround where
585 it was used above, but when gnutls_certificate_get_issuer() returns
586 a bogus cert, there's nothing we can do to fix it up. We don't get
587 to iterate over all the available certs like we can over our own
589 if (check_issuer_sanity(last_cert, issuer)) {
590 /* Hm, is there a bug reference for this? Or just the git commit
591 reference (c1ef7efb in master, 5196786c in gnutls_3_0_x-2)? */
592 vpn_progress(vpninfo, PRG_ERR,
593 _("WARNING: GnuTLS returned incorrect issuer certs; authentication may fail!\n"));
597 if (issuer == last_cert)
600 /* OK, we found a new cert to add to our chain. */
601 supporting_certs = realloc(supporting_certs,
602 sizeof(cert) * ++nr_supporting_certs);
603 if (!supporting_certs) {
604 vpn_progress(vpninfo, PRG_ERR,
605 _("Failed to allocate memory for supporting certificates\n"));
606 /* The world is probably about to end, but try without them anyway */
610 /* First time we actually allocated an array? Copy the first cert into it */
611 if (nr_supporting_certs == 2)
612 supporting_certs[0] = cert;
614 /* Append the new one */
615 supporting_certs[nr_supporting_certs-1] = issuer;
619 sprintf(name, "<unknown>");
620 namelen = sizeof(name);
621 if (gnutls_x509_crt_get_dn_by_oid(issuer, GNUTLS_OID_X520_COMMON_NAME, 0, 0,
623 gnutls_x509_crt_get_dn(issuer, name, &namelen))
624 sprintf(name, "<unknown>");
626 vpn_progress(vpninfo, PRG_DEBUG,
627 _("Adding supporting CA '%s'\n"), name);
630 err = gnutls_certificate_set_x509_key(vpninfo->https_cred,
631 supporting_certs ? supporting_certs : &cert,
632 supporting_certs ? 1 : nr_supporting_certs,
635 vpn_progress(vpninfo, PRG_ERR,
636 _("Setting certificate failed: %s\n"),
637 gnutls_strerror(err));
642 gnutls_x509_crl_deinit(crl);
644 gnutls_x509_privkey_deinit(key);
646 gnutls_x509_crt_deinit(cert);
647 for (i = 0; i < nr_extra_certs; i++)
648 gnutls_x509_crt_deinit(extra_certs[i]);
650 free(supporting_certs);
651 gnutls_free(fdata.data);
655 static int get_cert_fingerprint(struct openconnect_info *vpninfo,
656 gnutls_x509_crt_t cert,
657 gnutls_digest_algorithm_t algo,
660 unsigned char md[256];
661 size_t md_size = sizeof(md);
664 if (gnutls_x509_crt_get_fingerprint(cert, algo, md, &md_size))
667 for (i=0; i < md_size; i++)
668 sprintf(&buf[i*2], "%02X", md[i]);
673 int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
674 OPENCONNECT_X509 *cert, char *buf)
676 return get_cert_fingerprint(vpninfo, cert, GNUTLS_DIG_MD5, buf);
679 int openconnect_get_cert_sha1(struct openconnect_info *vpninfo,
680 OPENCONNECT_X509 *cert, char *buf)
682 return get_cert_fingerprint(vpninfo, cert, GNUTLS_DIG_SHA1, buf);
685 char *openconnect_get_cert_details(struct openconnect_info *vpninfo,
686 OPENCONNECT_X509 *cert)
691 if (gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL, &buf))
694 /* Just in case gnutls_free() isn't free(), we can't steal it. */
695 ret = strdup((char *)buf.data);
696 gnutls_free(buf.data);
701 int openconnect_get_cert_DER(struct openconnect_info *vpninfo,
702 OPENCONNECT_X509 *cert, unsigned char **buf)
705 unsigned char *ret = NULL;
707 if (gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, ret, &l) !=
708 GNUTLS_E_SHORT_MEMORY_BUFFER)
715 if (gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, ret, &l)) {
723 static int verify_peer(gnutls_session_t session)
725 struct openconnect_info *vpninfo = gnutls_session_get_ptr(session);
726 const gnutls_datum_t *cert_list;
727 gnutls_x509_crt_t cert;
728 unsigned int status, cert_list_size;
732 cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
734 vpn_progress(vpninfo, PRG_ERR, _("Server presented no certificate\n"));
735 return GNUTLS_E_CERTIFICATE_ERROR;
738 if (vpninfo->servercert) {
739 unsigned char sha1bin[SHA1_SIZE];
740 char fingerprint[(SHA1_SIZE * 2) + 1];
743 err = openconnect_sha1(sha1bin, cert_list[0].data, cert_list[0].size);
745 vpn_progress(vpninfo, PRG_ERR,
746 _("Could not calculate SHA1 of server's certificate\n"));
747 return GNUTLS_E_CERTIFICATE_ERROR;
749 for (i=0; i < SHA1_SIZE; i++)
750 sprintf(&fingerprint[i*2], "%02X", sha1bin[i]);
752 if (strcasecmp(vpninfo->servercert, fingerprint)) {
753 vpn_progress(vpninfo, PRG_ERR,
754 _("Server SSL certificate didn't match: %s\n"), fingerprint);
755 return GNUTLS_E_CERTIFICATE_ERROR;
760 err = gnutls_certificate_verify_peers2 (session, &status);
762 vpn_progress(vpninfo, PRG_ERR, _("Error checking server cert status\n"));
763 return GNUTLS_E_CERTIFICATE_ERROR;
766 if (status & GNUTLS_CERT_REVOKED)
767 reason = _("certificate revoked");
768 else if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
769 reason = _("signer not found");
770 else if (status & GNUTLS_CERT_SIGNER_NOT_CA)
771 reason = _("signer not a CA certificate");
772 else if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
773 reason = _("insecure algorithm");
774 else if (status & GNUTLS_CERT_NOT_ACTIVATED)
775 reason = _("certificate not yet activated");
776 else if (status & GNUTLS_CERT_EXPIRED)
777 reason = _("certificate expired");
778 else if (status & GNUTLS_CERT_INVALID)
779 /* If this is set and no other reason, it apparently means
780 that signature verification failed. Not entirely sure
781 why we don't just set a bit for that too. */
782 reason = _("signature verification failed");
784 err = gnutls_x509_crt_init(&cert);
786 vpn_progress(vpninfo, PRG_ERR, _("Error initialising X509 cert structure\n"));
787 return GNUTLS_E_CERTIFICATE_ERROR;
790 err = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
792 vpn_progress(vpninfo, PRG_ERR, _("Error importing server's cert\n"));
793 gnutls_x509_crt_deinit(cert);
794 return GNUTLS_E_CERTIFICATE_ERROR;
797 if (!reason && !gnutls_x509_crt_check_hostname(cert, vpninfo->hostname))
798 reason = _("certificate does not match hostname");
801 vpn_progress(vpninfo, PRG_ERR, "Server certificate verify failed: %s\n",
803 if (vpninfo->validate_peer_cert)
804 err = vpninfo->validate_peer_cert(vpninfo->cbdata,
806 reason) ? GNUTLS_E_CERTIFICATE_ERROR : 0;
808 err = GNUTLS_E_CERTIFICATE_ERROR;
811 gnutls_x509_crt_deinit(cert);
815 static void workaround_openssl_certchain_bug(struct openconnect_info *vpninfo)
817 /* OpenSSL has problems with certificate chains -- if there are
818 multiple certs with the same name, it doesn't necessarily
819 choose the _right_ one. (RT#1942)
820 Pick the right ones for ourselves and add them manually. */
822 /* FIXME: Of course we still have to do this with GnuTLS, to work
823 around the issue on the server side */
826 static int cancellable_connect(struct openconnect_info *vpninfo, int sockfd,
827 const struct sockaddr *addr, socklen_t addrlen)
829 struct sockaddr_storage peer;
830 socklen_t peerlen = sizeof(peer);
831 fd_set wr_set, rd_set;
834 fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK);
836 if (connect(sockfd, addr, addrlen) < 0 && errno != EINPROGRESS)
841 FD_SET(sockfd, &wr_set);
842 if (vpninfo->cancel_fd != -1) {
843 FD_SET(vpninfo->cancel_fd, &rd_set);
844 if (vpninfo->cancel_fd > sockfd)
845 maxfd = vpninfo->cancel_fd;
848 /* Later we'll render this whole exercise non-pointless by
849 including a 'cancelfd' here too. */
850 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
851 if (vpninfo->cancel_fd != -1 && FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
852 vpn_progress(vpninfo, PRG_ERR, _("Socket connect cancelled\n"));
857 /* Check whether connect() succeeded or failed by using
858 getpeername(). See http://cr.yp.to/docs/connect.html */
859 return getpeername(sockfd, (void *)&peer, &peerlen);
862 int openconnect_open_https(struct openconnect_info *vpninfo)
867 if (vpninfo->https_sess)
873 if (vpninfo->peer_addr) {
875 ssl_sock = socket(vpninfo->peer_addr->sa_family, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_IP);
879 ssl_sock = socket(vpninfo->peer_addr->sa_family, SOCK_STREAM, IPPROTO_IP);
882 fcntl(ssl_sock, F_SETFD, fcntl(ssl_sock, F_GETFD) | FD_CLOEXEC);
884 if (cancellable_connect(vpninfo, ssl_sock, vpninfo->peer_addr, vpninfo->peer_addrlen)) {
886 if (vpninfo->proxy) {
887 vpn_progress(vpninfo, PRG_ERR,
888 _("Failed to reconnect to proxy %s\n"),
891 vpn_progress(vpninfo, PRG_ERR,
892 _("Failed to reconnect to host %s\n"),
899 struct addrinfo hints, *result, *rp;
903 memset(&hints, 0, sizeof(struct addrinfo));
904 hints.ai_family = AF_UNSPEC;
905 hints.ai_socktype = SOCK_STREAM;
906 hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
907 hints.ai_protocol = 0;
908 hints.ai_canonname = NULL;
909 hints.ai_addr = NULL;
910 hints.ai_next = NULL;
912 /* The 'port' variable is a string because it's easier
913 this way than if we pass NULL to getaddrinfo() and
914 then try to fill in the numeric value into
915 different types of returned sockaddr_in{6,}. */
917 if (vpninfo->proxy_factory) {
922 free(vpninfo->proxy_type);
923 vpninfo->proxy_type = NULL;
924 free(vpninfo->proxy);
925 vpninfo->proxy = NULL;
927 if (vpninfo->port == 443)
928 i = asprintf(&url, "https://%s/%s", vpninfo->hostname,
929 vpninfo->urlpath?:"");
931 i = asprintf(&url, "https://%s:%d/%s", vpninfo->hostname,
932 vpninfo->port, vpninfo->urlpath?:"");
936 proxies = px_proxy_factory_get_proxies(vpninfo->proxy_factory,
940 while (proxies && proxies[i]) {
941 if (!vpninfo->proxy &&
942 (!strncmp(proxies[i], "http://", 7) ||
943 !strncmp(proxies[i], "socks://", 8) ||
944 !strncmp(proxies[i], "socks5://", 9)))
945 internal_parse_url(proxies[i], &vpninfo->proxy_type,
946 &vpninfo->proxy, &vpninfo->proxy_port,
953 vpn_progress(vpninfo, PRG_TRACE,
954 _("Proxy from libproxy: %s://%s:%d/\n"),
955 vpninfo->proxy_type, vpninfo->proxy, vpninfo->port);
958 if (vpninfo->proxy) {
959 hostname = vpninfo->proxy;
960 snprintf(port, 6, "%d", vpninfo->proxy_port);
962 hostname = vpninfo->hostname;
963 snprintf(port, 6, "%d", vpninfo->port);
966 if (hostname[0] == '[' && hostname[strlen(hostname)-1] == ']') {
967 /* Solaris has no strndup(). */
968 int len = strlen(hostname) - 2;
969 char *new_hostname = malloc(len + 1);
972 memcpy(new_hostname, hostname + 1, len);
973 new_hostname[len] = 0;
975 hostname = new_hostname;
976 hints.ai_flags |= AI_NUMERICHOST;
979 err = getaddrinfo(hostname, port, &hints, &result);
980 if (hints.ai_flags & AI_NUMERICHOST)
984 vpn_progress(vpninfo, PRG_ERR,
985 _("getaddrinfo failed for host '%s': %s\n"),
986 hostname, gai_strerror(err));
990 for (rp = result; rp ; rp = rp->ai_next) {
993 if (!getnameinfo(rp->ai_addr, rp->ai_addrlen, host,
994 sizeof(host), NULL, 0, NI_NUMERICHOST))
995 vpn_progress(vpninfo, PRG_INFO,
996 _("Attempting to connect to %s%s%s:%s\n"),
997 rp->ai_family == AF_INET6?"[":"",
999 rp->ai_family == AF_INET6?"]":"",
1002 ssl_sock = socket(rp->ai_family, rp->ai_socktype,
1006 if (cancellable_connect(vpninfo, ssl_sock, rp->ai_addr, rp->ai_addrlen) >= 0) {
1007 /* Store the peer address we actually used, so that DTLS can
1008 use it again later */
1009 vpninfo->peer_addr = malloc(rp->ai_addrlen);
1010 if (!vpninfo->peer_addr) {
1011 vpn_progress(vpninfo, PRG_ERR,
1012 _("Failed to allocate sockaddr storage\n"));
1016 vpninfo->peer_addrlen = rp->ai_addrlen;
1017 memcpy(vpninfo->peer_addr, rp->ai_addr, rp->ai_addrlen);
1023 freeaddrinfo(result);
1026 vpn_progress(vpninfo, PRG_ERR,
1027 _("Failed to connect to host %s\n"),
1028 vpninfo->proxy?:vpninfo->hostname);
1033 if (vpninfo->proxy) {
1034 err = process_proxy(vpninfo, ssl_sock);
1041 if (!vpninfo->https_cred) {
1042 gnutls_certificate_allocate_credentials(&vpninfo->https_cred);
1043 gnutls_certificate_set_x509_trust_file(vpninfo->https_cred,
1044 "/etc/pki/tls/certs/ca-bundle.crt",
1045 GNUTLS_X509_FMT_PEM);
1046 gnutls_certificate_set_verify_function (vpninfo->https_cred,
1048 /* FIXME: Ensure TLSv1.0, no options */
1050 if (vpninfo->cert) {
1051 err = load_certificate(vpninfo);
1053 vpn_progress(vpninfo, PRG_ERR,
1054 _("Loading certificate failed. Aborting.\n"));
1059 /* We just want to do:
1060 SSL_CTX_set_purpose(vpninfo->https_ctx, X509_PURPOSE_ANY);
1061 ... but it doesn't work with OpenSSL < 0.9.8k because of
1062 problems with inheritance (fixed in v1.1.4.6 of
1063 crypto/x509/x509_vpm.c) so we have to play silly buggers
1064 instead. This trick doesn't work _either_ in < 0.9.7 but
1065 I don't know of _any_ workaround which will, and can't
1066 be bothered to find out either. */
1068 if (vpninfo->cafile) {
1069 err = gnutls_certificate_set_x509_trust_file(vpninfo->https_cred,
1071 GNUTLS_X509_FMT_PEM);
1073 vpn_progress(vpninfo, PRG_ERR,
1074 _("Failed to open CA file '%s': %s\n"),
1075 vpninfo->cafile, gnutls_strerror(err));
1082 gnutls_init (&vpninfo->https_sess, GNUTLS_CLIENT);
1083 gnutls_session_set_ptr (vpninfo->https_sess, (void *) vpninfo);
1084 err = gnutls_priority_set_direct (vpninfo->https_sess, "NONE:+VERS-TLS1.0:+SHA1:+AES-128-CBC:+RSA:+COMP-NULL:%COMPAT:%DISABLE_SAFE_RENEGOTIATION", NULL);
1086 vpn_progress(vpninfo, PRG_ERR,
1087 _("Failed to set TLS priority string: %s\n"),
1088 gnutls_strerror(err));
1092 gnutls_record_disable_padding (vpninfo->https_sess);
1093 workaround_openssl_certchain_bug(vpninfo);
1094 gnutls_credentials_set (vpninfo->https_sess, GNUTLS_CRD_CERTIFICATE, vpninfo->https_cred);
1095 gnutls_transport_set_ptr(vpninfo->https_sess, /* really? */(gnutls_transport_ptr_t)(long) ssl_sock);
1097 vpn_progress(vpninfo, PRG_INFO, _("SSL negotiation with %s\n"),
1100 while ((err = gnutls_handshake (vpninfo->https_sess))) {
1101 if (err == GNUTLS_E_AGAIN) {
1102 fd_set rd_set, wr_set;
1103 int maxfd = ssl_sock;
1108 if (gnutls_record_get_direction(vpninfo->https_sess))
1109 FD_SET(ssl_sock, &wr_set);
1111 FD_SET(ssl_sock, &rd_set);
1113 if (vpninfo->cancel_fd != -1) {
1114 FD_SET(vpninfo->cancel_fd, &rd_set);
1115 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
1116 maxfd = vpninfo->cancel_fd;
1118 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
1119 if (vpninfo->cancel_fd != -1 &&
1120 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
1121 vpn_progress(vpninfo, PRG_ERR, _("SSL connection cancelled\n"));
1122 gnutls_deinit(vpninfo->https_sess);
1123 vpninfo->https_sess = NULL;
1127 } else if (err == GNUTLS_E_INTERRUPTED || gnutls_error_is_fatal(err)) {
1128 vpn_progress(vpninfo, PRG_ERR, _("SSL connection failure: %s\n"),
1129 gnutls_strerror(err));
1130 gnutls_deinit(vpninfo->https_sess);
1131 vpninfo->https_sess = NULL;
1135 /* non-fatal error or warning. Ignore it and continue */
1136 vpn_progress(vpninfo, PRG_TRACE,
1137 _("GnuTLS non-fatal return during handshake: %s\n"),
1138 gnutls_strerror(err));
1142 vpninfo->ssl_fd = ssl_sock;
1144 vpn_progress(vpninfo, PRG_INFO, _("Connected to HTTPS on %s\n"),
1150 void openconnect_close_https(struct openconnect_info *vpninfo)
1153 if (vpninfo->peer_cert) {
1154 X509_free(vpninfo->peer_cert);
1155 vpninfo->peer_cert = NULL;
1158 if (vpninfo->https_sess) {
1159 gnutls_deinit(vpninfo->https_sess);
1160 vpninfo->https_sess = NULL;
1162 if (vpninfo->ssl_fd != -1) {
1163 close(vpninfo->ssl_fd);
1164 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds);
1165 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
1166 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds);
1167 vpninfo->ssl_fd = -1;
1171 void openconnect_init_openssl(void)
1173 gnutls_global_init();
1176 int openconnect_sha1(unsigned char *result, void *data, int datalen)
1179 size_t shalen = SHA1_SIZE;
1183 if (gnutls_fingerprint(GNUTLS_DIG_SHA1, &d, result, &shalen))
1189 int openconnect_random(void *bytes, int len)
1191 if (gnutls_rnd(GNUTLS_RND_RANDOM, bytes, len))
1196 int openconnect_local_cert_md5(struct openconnect_info *vpninfo,
1199 const gnutls_datum_t *d;
1204 d = gnutls_certificate_get_ours(vpninfo->https_sess);
1208 if (gnutls_fingerprint(GNUTLS_DIG_MD5, d, buf, &md5len))