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 /* Helper functions for reading/writing lines over SSL.
48 We could use cURL for the HTTP stuff, but it's overkill */
50 int openconnect_SSL_write(struct openconnect_info *vpninfo, char *buf, size_t len)
52 size_t orig_len = len;
55 int done = gnutls_record_send(vpninfo->https_sess, buf, len);
58 else if (done != GNUTLS_E_AGAIN) {
59 vpn_progress(vpninfo, PRG_ERR, _("Failed to write to SSL socket: %s"),
60 gnutls_strerror(done));
63 fd_set wr_set, rd_set;
64 int maxfd = vpninfo->ssl_fd;
69 if (gnutls_record_get_direction(vpninfo->https_sess))
70 FD_SET(vpninfo->ssl_fd, &wr_set);
72 FD_SET(vpninfo->ssl_fd, &rd_set);
74 if (vpninfo->cancel_fd != -1) {
75 FD_SET(vpninfo->cancel_fd, &rd_set);
76 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
77 maxfd = vpninfo->cancel_fd;
79 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
80 if (vpninfo->cancel_fd != -1 &&
81 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
82 vpn_progress(vpninfo, PRG_ERR, _("SSL write cancelled\n"));
90 int openconnect_SSL_read(struct openconnect_info *vpninfo, char *buf, size_t len)
94 while ((done = gnutls_record_recv(vpninfo->https_sess, buf, len)) < 0) {
95 fd_set wr_set, rd_set;
96 int maxfd = vpninfo->ssl_fd;
98 if (done != GNUTLS_E_AGAIN) {
99 vpn_progress(vpninfo, PRG_ERR, _("Failed to read from SSL socket: %s"),
100 gnutls_strerror(done));
106 if (gnutls_record_get_direction(vpninfo->https_sess))
107 FD_SET(vpninfo->ssl_fd, &wr_set);
109 FD_SET(vpninfo->ssl_fd, &rd_set);
111 if (vpninfo->cancel_fd != -1) {
112 FD_SET(vpninfo->cancel_fd, &rd_set);
113 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
114 maxfd = vpninfo->cancel_fd;
116 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
117 if (vpninfo->cancel_fd != -1 &&
118 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
119 vpn_progress(vpninfo, PRG_ERR, _("SSL read cancelled\n"));
127 int openconnect_SSL_gets(struct openconnect_info *vpninfo, char *buf, size_t len)
136 ret = gnutls_record_recv(vpninfo->https_sess, buf + i, 1);
138 if (buf[i] == '\n') {
140 if (i && buf[i-1] == '\r') {
152 } else if (ret != GNUTLS_E_AGAIN) {
153 vpn_progress(vpninfo, PRG_ERR, _("Failed to read from SSL socket: %s\n"),
154 gnutls_strerror(ret));
158 fd_set rd_set, wr_set;
159 int maxfd = vpninfo->ssl_fd;
164 if (gnutls_record_get_direction(vpninfo->https_sess))
165 FD_SET(vpninfo->ssl_fd, &wr_set);
167 FD_SET(vpninfo->ssl_fd, &rd_set);
169 if (vpninfo->cancel_fd != -1) {
170 FD_SET(vpninfo->cancel_fd, &rd_set);
171 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
172 maxfd = vpninfo->cancel_fd;
174 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
175 if (vpninfo->cancel_fd != -1 &&
176 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
177 vpn_progress(vpninfo, PRG_ERR, _("SSL read cancelled\n"));
187 static int check_certificate_expiry(struct openconnect_info *vpninfo, gnutls_x509_crt_t cert)
189 const char *reason = NULL;
190 time_t expires = gnutls_x509_crt_get_expiration_time(cert);
191 time_t now = time(NULL);
194 vpn_progress(vpninfo, PRG_ERR,
195 _("Could not extract expiration time of certificate\n"));
200 reason = _("Client certificate has expired at");
201 else if (expires < now + vpninfo->cert_expire_warning)
202 reason = _("Client certificate expires soon at");
208 gmtime_r(&expires, &tm);
209 strftime(buf, 80, "%a, %d %b %Y %T %Z", &tm);
211 vpn_progress(vpninfo, PRG_ERR, "%s: %s\n", reason, buf);
216 /* For systems that don't support O_CLOEXEC, just don't bother.
217 It's not open for long anyway. */
222 static int load_datum(struct openconnect_info *vpninfo,
223 gnutls_datum_t *datum, const char *fname)
228 fd = open(fname, O_RDONLY|O_CLOEXEC);
231 vpn_progress(vpninfo, PRG_ERR,
232 _("Failed to open certificate file %s: %s\n"),
233 vpninfo->cert, strerror(err));
236 if (fstat(fd, &st)) {
238 vpn_progress(vpninfo, PRG_ERR,
239 _("Failed to stat certificate file %s: %s\n"),
240 vpninfo->cert, strerror(err));
244 datum->size = st.st_size;
245 datum->data = gnutls_malloc(st.st_size + 1);
247 vpn_progress(vpninfo, PRG_ERR,
248 _("Failed to allocate certificate buffer\n"));
253 if (read(fd, datum->data, datum->size) != datum->size) {
255 vpn_progress(vpninfo, PRG_ERR,
256 _("Failed to read certificate into memory: %s\n"),
259 gnutls_free(datum->data);
262 datum->data[st.st_size] = 0;
267 #ifndef HAVE_GNUTLS_PKCS12_SIMPLE_PARSE
268 /* If we're using a version of GnuTLS from before this was
269 exported, pull in our local copy. */
270 #include "gnutls_pkcs12.c"
273 /* A non-zero, non-error return to make load_certificate() continue and
274 interpreting the file as other types */
277 static int load_pkcs12_certificate(struct openconnect_info *vpninfo,
278 gnutls_datum_t *datum,
279 gnutls_x509_privkey_t *key,
280 gnutls_x509_crt_t *cert,
281 gnutls_x509_crt_t **extra_certs,
282 unsigned int *nr_extra_certs,
283 gnutls_x509_crl_t *crl)
289 err = gnutls_pkcs12_init(&p12);
291 vpn_progress(vpninfo, PRG_ERR,
292 _("Failed to setup PKCS#12 data structure: %s\n"),
293 gnutls_strerror(err));
297 err = gnutls_pkcs12_import(p12, datum, GNUTLS_X509_FMT_DER, 0);
299 gnutls_pkcs12_deinit(p12);
300 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN)
302 vpn_progress(vpninfo, PRG_ERR,
303 _("Failed to import PKCS#12 file: %s\n"),
304 gnutls_strerror(err));
308 pass = vpninfo->cert_password;
309 while ((err = gnutls_pkcs12_verify_mac(p12, pass)) == GNUTLS_E_MAC_VERIFY_FAILED) {
311 vpn_progress(vpninfo, PRG_ERR,
312 _("Failed to decrypt PKCS#12 certificate file\n"));
314 vpninfo->cert_password = NULL;
315 err = request_passphrase(vpninfo, &pass,
316 _("Enter PKCS#12 pass phrase:"));
318 gnutls_pkcs12_deinit(p12);
322 /* If it wasn't GNUTLS_E_MAC_VERIFY_FAILED, then the problem wasn't just a
323 bad password. Give up. */
328 gnutls_pkcs12_deinit(p12);
330 /* If the first attempt, and we didn't know for sure it was PKCS#12
331 anyway, bail out and try loading it as something different. */
332 if (pass == vpninfo->cert_password &&
333 vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
334 /* Make it non-fatal... */
339 vpn_progress(vpninfo, level,
340 _("Failed to process PKCS#12 file: %s\n"),
341 gnutls_strerror(err));
345 err = gnutls_pkcs12_simple_parse(vpninfo->https_cred, p12, pass, key,
346 cert, extra_certs, nr_extra_certs, crl);
347 gnutls_pkcs12_deinit(p12);
349 vpn_progress(vpninfo, PRG_ERR,
350 _("Failed to load PKCS#12 certificate: %s\n"),
351 gnutls_strerror(err));
357 /* Older versions of GnuTLS didn't actually bother to check this, so we'll
359 static int check_issuer_sanity(gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer)
361 #if GNUTLS_VERSION_NUMBER > 0x300014
364 unsigned char id1[512], id2[512];
365 size_t id1_size = 512, id2_size = 512;
368 err = gnutls_x509_crt_get_authority_key_id(cert, id1, &id1_size, NULL);
372 err = gnutls_x509_crt_get_subject_key_id(issuer, id2, &id2_size, NULL);
375 if (id1_size == id2_size && !memcmp(id1, id2, id1_size))
383 static int count_x509_certificates(gnutls_datum_t *datum)
386 char *p = (char *)datum->data;
389 p = strstr(p, "-----BEGIN ");
393 if (!strncmp(p, "CERTIFICATE", 11) ||
394 !strncmp(p, "X509 CERTIFICATE", 16))
400 static int load_certificate(struct openconnect_info *vpninfo)
402 gnutls_datum_t fdata;
403 gnutls_x509_privkey_t key = NULL;
404 gnutls_x509_crl_t crl = NULL;
405 gnutls_x509_crt_t last_cert, cert = NULL;
406 gnutls_x509_crt_t *extra_certs = NULL, *supporting_certs = NULL;
407 unsigned int nr_supporting_certs, nr_extra_certs = 0;
408 int err; /* GnuTLS error */
409 int ret = 0; /* our error (zero or -errno) */
411 unsigned char key_id[20];
412 size_t key_id_size = sizeof(key_id);
414 if (vpninfo->cert_type == CERT_TYPE_TPM) {
415 vpn_progress(vpninfo, PRG_ERR,
416 _("TPM support not available with GnuTLS\n"));
420 if (!strncmp(vpninfo->cert, "pkcs11:", 7)) {
421 vpn_progress(vpninfo, PRG_TRACE,
422 _("Using PKCS#11 certificate %s\n"), vpninfo->cert);
424 err = gnutls_certificate_set_x509_key_file(vpninfo->https_cred,
427 GNUTLS_X509_FMT_PEM);
429 vpn_progress(vpninfo, PRG_ERR,
430 _("Error loading PKCS#11 certificate: %s\n"),
431 gnutls_strerror(err));
437 vpn_progress(vpninfo, PRG_TRACE,
438 _("Using certificate file %s\n"), vpninfo->cert);
440 ret = load_datum(vpninfo, &fdata, vpninfo->cert);
444 if (vpninfo->cert_type == CERT_TYPE_PKCS12 ||
445 vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
446 ret = load_pkcs12_certificate(vpninfo, &fdata, &key, &cert,
447 &extra_certs, &nr_extra_certs, &crl);
453 /* It returned NOT_PKCS12.
454 Fall through to try PEM formats. */
457 /* We need to know how many there are in *advance*; it won't just allocate
458 the array for us :( */
459 nr_extra_certs = count_x509_certificates(&fdata);
461 nr_extra_certs = 1; /* wtf? Oh well, we'll fail later... */
463 extra_certs = calloc(nr_extra_certs, sizeof(cert));
469 err = gnutls_x509_crt_list_import(extra_certs, &nr_extra_certs, &fdata,
470 GNUTLS_X509_FMT_PEM, 0);
473 if (!err || err == GNUTLS_E_NO_CERTIFICATE_FOUND)
474 reason = _("No certificate found in file");
476 reason = gnutls_strerror(err);
478 vpn_progress(vpninfo, PRG_ERR,
479 _("Loading certificate failed: %s\n"),
484 nr_extra_certs = err;
487 if (vpninfo->sslkey != vpninfo->cert) {
488 gnutls_free(fdata.data);
490 vpn_progress(vpninfo, PRG_TRACE,
491 _("Using private key file %s\n"), vpninfo->cert);
493 ret = load_datum(vpninfo, &fdata, vpninfo->sslkey);
498 gnutls_x509_privkey_init(&key);
499 /* Try PKCS#1 (and PKCS#8 without password) first. GnuTLS doesn't
500 support OpenSSL's old PKCS#1-based encrypted format. We should
501 probably check for it and give a more coherent failure mode. */
502 err = gnutls_x509_privkey_import(key, &fdata, GNUTLS_X509_FMT_PEM);
504 /* If that fails, try PKCS#8 */
505 char *pass = vpninfo->cert_password;
507 /* Yay, just for fun this is *different* to PKCS#12. Where we could
508 try an empty password there, in this case the empty-password case
509 has already been *tried* by gnutls_x509_privkey_import(). If we
510 just call gnutls_x509_privkey_import_pkcs8() with a NULL password,
511 it'll SEGV. You have to set the GNUTLS_PKCS_PLAIN flag if you want
512 to try without a password. Passing NULL evidently isn't enough of
513 a hint. And in GnuTLS 3.1 where that crash has been fixed, passing
514 NULL will cause it to return GNUTLS_E_ENCRYPTED_STRUCTURE (a new
515 error code) rather than GNUTLS_E_DECRYPTION_FAILED. So just pass ""
516 instead of NULL, and don't worry about either case. */
517 while ((err = gnutls_x509_privkey_import_pkcs8(key, &fdata,
520 if (err != GNUTLS_E_DECRYPTION_FAILED) {
521 vpn_progress(vpninfo, PRG_ERR,
522 _("Failed to load private key as PKCS#8: %s\n"),
523 gnutls_strerror(err));
528 vpn_progress(vpninfo, PRG_ERR,
529 _("Failed to decrypt PKCS#8 certificate file\n"));
532 err = request_passphrase(vpninfo, &pass,
533 _("Enter PEM pass phrase:"));
540 err = gnutls_x509_privkey_get_key_id(key, 0, key_id, &key_id_size);
542 vpn_progress(vpninfo, PRG_ERR,
543 _("Failed to get key ID: %s\n"),
544 gnutls_strerror(err));
547 for (i = 0; i < nr_extra_certs; i++) {
548 unsigned char cert_id[20];
549 size_t cert_id_size = sizeof(cert_id);
551 err = gnutls_x509_crt_get_key_id(extra_certs[i], 0, cert_id, &cert_id_size);
555 if (cert_id_size == key_id_size && !memcmp(cert_id, key_id, key_id_size)) {
556 cert = extra_certs[i];
558 /* Move the rest of the array down */
559 for (; i < nr_extra_certs - 1; i++)
560 extra_certs[i] = extra_certs[i+1];
566 /* We shouldn't reach this. It means that we didn't find *any* matching cert */
567 vpn_progress(vpninfo, PRG_ERR,
568 _("No SSL certificate found to match private key\n"));
573 check_certificate_expiry(vpninfo, cert);
576 err = gnutls_certificate_set_x509_crl(vpninfo->https_cred, &crl, 1);
578 vpn_progress(vpninfo, PRG_ERR,
579 _("Setting certificate recovation list failed: %s\n"),
580 gnutls_strerror(err));
585 /* OpenSSL has problems with certificate chains — if there are
586 multiple certs with the same name, it doesn't necessarily
587 choose the _right_ one. (RT#1942)
588 Pick the right ones for ourselves and add them manually. */
590 nr_supporting_certs = 1; /* Our starting cert */
592 gnutls_x509_crt_t issuer;
594 for (i = 0; i < nr_extra_certs; i++) {
595 if (gnutls_x509_crt_check_issuer(last_cert, extra_certs[i]) &&
596 !check_issuer_sanity(last_cert, extra_certs[i]))
600 if (i < nr_extra_certs) {
601 issuer = extra_certs[i];
603 err = gnutls_certificate_get_issuer(vpninfo->https_cred,
604 last_cert, &issuer, 0);
609 /* The check_issuer_sanity() function works fine as a workaround where
610 it was used above, but when gnutls_certificate_get_issuer() returns
611 a bogus cert, there's nothing we can do to fix it up. We don't get
612 to iterate over all the available certs like we can over our own
614 if (check_issuer_sanity(last_cert, issuer)) {
615 /* Hm, is there a bug reference for this? Or just the git commit
616 reference (c1ef7efb in master, 5196786c in gnutls_3_0_x-2)? */
617 vpn_progress(vpninfo, PRG_ERR,
618 _("WARNING: GnuTLS returned incorrect issuer certs; authentication may fail!\n"));
622 if (issuer == last_cert) {
623 /* Don't actually include the root CA. If they don't already trust it,
624 then handing it to them isn't going to help. But don't omit the
625 original certificate if it's self-signed. */
626 if (nr_supporting_certs > 1)
627 nr_supporting_certs--;
631 /* OK, we found a new cert to add to our chain. */
632 supporting_certs = realloc(supporting_certs,
633 sizeof(cert) * ++nr_supporting_certs);
634 if (!supporting_certs) {
635 vpn_progress(vpninfo, PRG_ERR,
636 _("Failed to allocate memory for supporting certificates\n"));
637 /* The world is probably about to end, but try without them anyway */
641 /* First time we actually allocated an array? Copy the first cert into it */
642 if (nr_supporting_certs == 2)
643 supporting_certs[0] = cert;
645 /* Append the new one */
646 supporting_certs[nr_supporting_certs-1] = issuer;
650 for (i = 1; i < nr_supporting_certs; i++) {
654 sprintf(name, "<unknown>");
655 namelen = sizeof(name);
656 if (gnutls_x509_crt_get_dn_by_oid(supporting_certs[i],
657 GNUTLS_OID_X520_COMMON_NAME,
658 0, 0, name, &namelen) &&
659 gnutls_x509_crt_get_dn(supporting_certs[i], name, &namelen))
660 sprintf(name, "<unknown>");
662 vpn_progress(vpninfo, PRG_DEBUG,
663 _("Adding supporting CA '%s'\n"), name);
666 err = gnutls_certificate_set_x509_key(vpninfo->https_cred,
667 supporting_certs ? supporting_certs : &cert,
668 supporting_certs ? 1 : nr_supporting_certs,
671 vpn_progress(vpninfo, PRG_ERR,
672 _("Setting certificate failed: %s\n"),
673 gnutls_strerror(err));
678 gnutls_x509_crl_deinit(crl);
680 gnutls_x509_privkey_deinit(key);
682 gnutls_x509_crt_deinit(cert);
683 for (i = 0; i < nr_extra_certs; i++) {
685 gnutls_x509_crt_deinit(extra_certs[i]);
688 free(supporting_certs);
689 gnutls_free(fdata.data);
693 static int get_cert_fingerprint(struct openconnect_info *vpninfo,
694 gnutls_x509_crt_t cert,
695 gnutls_digest_algorithm_t algo,
698 unsigned char md[256];
699 size_t md_size = sizeof(md);
702 if (gnutls_x509_crt_get_fingerprint(cert, algo, md, &md_size))
705 for (i=0; i < md_size; i++)
706 sprintf(&buf[i*2], "%02X", md[i]);
711 int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
712 OPENCONNECT_X509 *cert, char *buf)
714 return get_cert_fingerprint(vpninfo, cert, GNUTLS_DIG_MD5, buf);
717 int openconnect_get_cert_sha1(struct openconnect_info *vpninfo,
718 OPENCONNECT_X509 *cert, char *buf)
720 return get_cert_fingerprint(vpninfo, cert, GNUTLS_DIG_SHA1, buf);
723 char *openconnect_get_cert_details(struct openconnect_info *vpninfo,
724 OPENCONNECT_X509 *cert)
729 if (gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL, &buf))
732 /* Just in case gnutls_free() isn't free(), we can't steal it. */
733 ret = strdup((char *)buf.data);
734 gnutls_free(buf.data);
739 int openconnect_get_cert_DER(struct openconnect_info *vpninfo,
740 OPENCONNECT_X509 *cert, unsigned char **buf)
743 unsigned char *ret = NULL;
745 if (gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, ret, &l) !=
746 GNUTLS_E_SHORT_MEMORY_BUFFER)
753 if (gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, ret, &l)) {
761 static int verify_peer(gnutls_session_t session)
763 struct openconnect_info *vpninfo = gnutls_session_get_ptr(session);
764 const gnutls_datum_t *cert_list;
765 gnutls_x509_crt_t cert;
766 unsigned int status, cert_list_size;
767 const char *reason = NULL;
770 if (vpninfo->peer_cert) {
771 gnutls_x509_crt_deinit(vpninfo->peer_cert);
772 vpninfo->peer_cert = NULL;
775 cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
777 vpn_progress(vpninfo, PRG_ERR, _("Server presented no certificate\n"));
778 return GNUTLS_E_CERTIFICATE_ERROR;
781 if (vpninfo->servercert) {
782 unsigned char sha1bin[SHA1_SIZE];
783 char fingerprint[(SHA1_SIZE * 2) + 1];
786 err = openconnect_sha1(sha1bin, cert_list[0].data, cert_list[0].size);
788 vpn_progress(vpninfo, PRG_ERR,
789 _("Could not calculate SHA1 of server's certificate\n"));
790 return GNUTLS_E_CERTIFICATE_ERROR;
792 for (i=0; i < SHA1_SIZE; i++)
793 sprintf(&fingerprint[i*2], "%02X", sha1bin[i]);
795 if (strcasecmp(vpninfo->servercert, fingerprint)) {
796 vpn_progress(vpninfo, PRG_ERR,
797 _("Server SSL certificate didn't match: %s\n"), fingerprint);
798 return GNUTLS_E_CERTIFICATE_ERROR;
803 err = gnutls_certificate_verify_peers2 (session, &status);
805 vpn_progress(vpninfo, PRG_ERR, _("Error checking server cert status\n"));
806 return GNUTLS_E_CERTIFICATE_ERROR;
809 if (status & GNUTLS_CERT_REVOKED)
810 reason = _("certificate revoked");
811 else if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
812 reason = _("signer not found");
813 else if (status & GNUTLS_CERT_SIGNER_NOT_CA)
814 reason = _("signer not a CA certificate");
815 else if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
816 reason = _("insecure algorithm");
817 else if (status & GNUTLS_CERT_NOT_ACTIVATED)
818 reason = _("certificate not yet activated");
819 else if (status & GNUTLS_CERT_EXPIRED)
820 reason = _("certificate expired");
821 else if (status & GNUTLS_CERT_INVALID)
822 /* If this is set and no other reason, it apparently means
823 that signature verification failed. Not entirely sure
824 why we don't just set a bit for that too. */
825 reason = _("signature verification failed");
827 err = gnutls_x509_crt_init(&cert);
829 vpn_progress(vpninfo, PRG_ERR, _("Error initialising X509 cert structure\n"));
830 return GNUTLS_E_CERTIFICATE_ERROR;
833 err = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
835 vpn_progress(vpninfo, PRG_ERR, _("Error importing server's cert\n"));
836 gnutls_x509_crt_deinit(cert);
837 return GNUTLS_E_CERTIFICATE_ERROR;
840 if (!reason && !gnutls_x509_crt_check_hostname(cert, vpninfo->hostname))
841 reason = _("certificate does not match hostname");
844 vpn_progress(vpninfo, PRG_INFO, "Server certificate verify failed: %s\n",
846 if (vpninfo->validate_peer_cert)
847 err = vpninfo->validate_peer_cert(vpninfo->cbdata,
849 reason) ? GNUTLS_E_CERTIFICATE_ERROR : 0;
851 err = GNUTLS_E_CERTIFICATE_ERROR;
854 vpninfo->peer_cert = cert;
860 int openconnect_open_https(struct openconnect_info *vpninfo)
865 if (vpninfo->https_sess)
868 ssl_sock = connect_https_socket(vpninfo);
872 if (!vpninfo->https_cred) {
873 gnutls_certificate_allocate_credentials(&vpninfo->https_cred);
874 gnutls_certificate_set_x509_trust_file(vpninfo->https_cred,
875 "/etc/pki/tls/certs/ca-bundle.crt",
876 GNUTLS_X509_FMT_PEM);
877 gnutls_certificate_set_verify_function (vpninfo->https_cred,
879 /* FIXME: Ensure TLSv1.0, no options */
881 if (vpninfo->cafile) {
882 err = gnutls_certificate_set_x509_trust_file(vpninfo->https_cred,
884 GNUTLS_X509_FMT_PEM);
886 vpn_progress(vpninfo, PRG_ERR,
887 _("Failed to open CA file '%s': %s\n"),
888 vpninfo->cafile, gnutls_strerror(err));
895 err = load_certificate(vpninfo);
897 vpn_progress(vpninfo, PRG_ERR,
898 _("Loading certificate failed. Aborting.\n"));
903 /* We just want to do:
904 SSL_CTX_set_purpose(vpninfo->https_ctx, X509_PURPOSE_ANY);
905 ... but it doesn't work with OpenSSL < 0.9.8k because of
906 problems with inheritance (fixed in v1.1.4.6 of
907 crypto/x509/x509_vpm.c) so we have to play silly buggers
908 instead. This trick doesn't work _either_ in < 0.9.7 but
909 I don't know of _any_ workaround which will, and can't
910 be bothered to find out either. */
914 gnutls_init (&vpninfo->https_sess, GNUTLS_CLIENT);
915 gnutls_session_set_ptr (vpninfo->https_sess, (void *) vpninfo);
916 err = gnutls_priority_set_direct (vpninfo->https_sess, "NONE:+VERS-TLS1.0:+SHA1:+AES-128-CBC:+RSA:+COMP-NULL:%COMPAT:%DISABLE_SAFE_RENEGOTIATION", NULL);
918 vpn_progress(vpninfo, PRG_ERR,
919 _("Failed to set TLS priority string: %s\n"),
920 gnutls_strerror(err));
924 gnutls_record_disable_padding (vpninfo->https_sess);
925 gnutls_credentials_set (vpninfo->https_sess, GNUTLS_CRD_CERTIFICATE, vpninfo->https_cred);
926 gnutls_transport_set_ptr(vpninfo->https_sess, /* really? */(gnutls_transport_ptr_t)(long) ssl_sock);
928 vpn_progress(vpninfo, PRG_INFO, _("SSL negotiation with %s\n"),
931 while ((err = gnutls_handshake (vpninfo->https_sess))) {
932 if (err == GNUTLS_E_AGAIN) {
933 fd_set rd_set, wr_set;
934 int maxfd = ssl_sock;
939 if (gnutls_record_get_direction(vpninfo->https_sess))
940 FD_SET(ssl_sock, &wr_set);
942 FD_SET(ssl_sock, &rd_set);
944 if (vpninfo->cancel_fd != -1) {
945 FD_SET(vpninfo->cancel_fd, &rd_set);
946 if (vpninfo->cancel_fd > ssl_sock)
947 maxfd = vpninfo->cancel_fd;
949 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
950 if (vpninfo->cancel_fd != -1 &&
951 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
952 vpn_progress(vpninfo, PRG_ERR, _("SSL connection cancelled\n"));
953 gnutls_deinit(vpninfo->https_sess);
954 vpninfo->https_sess = NULL;
958 } else if (err == GNUTLS_E_INTERRUPTED || gnutls_error_is_fatal(err)) {
959 vpn_progress(vpninfo, PRG_ERR, _("SSL connection failure: %s\n"),
960 gnutls_strerror(err));
961 gnutls_deinit(vpninfo->https_sess);
962 vpninfo->https_sess = NULL;
966 /* non-fatal error or warning. Ignore it and continue */
967 vpn_progress(vpninfo, PRG_TRACE,
968 _("GnuTLS non-fatal return during handshake: %s\n"),
969 gnutls_strerror(err));
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)
983 if (vpninfo->peer_cert) {
984 gnutls_x509_crt_deinit(vpninfo->peer_cert);
985 vpninfo->peer_cert = NULL;
987 if (vpninfo->https_sess) {
988 gnutls_deinit(vpninfo->https_sess);
989 vpninfo->https_sess = NULL;
991 if (vpninfo->ssl_fd != -1) {
992 close(vpninfo->ssl_fd);
993 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds);
994 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
995 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds);
996 vpninfo->ssl_fd = -1;
1000 void openconnect_init_openssl(void)
1002 gnutls_global_init();
1005 int openconnect_sha1(unsigned char *result, void *data, int datalen)
1008 size_t shalen = SHA1_SIZE;
1012 if (gnutls_fingerprint(GNUTLS_DIG_SHA1, &d, result, &shalen))
1018 int openconnect_random(void *bytes, int len)
1020 if (gnutls_rnd(GNUTLS_RND_RANDOM, bytes, len))
1025 int openconnect_local_cert_md5(struct openconnect_info *vpninfo,
1028 const gnutls_datum_t *d;
1033 d = gnutls_certificate_get_ours(vpninfo->https_sess);
1037 if (gnutls_fingerprint(GNUTLS_DIG_MD5, d, buf, &md5len))