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>
46 #include <p11-kit/p11-kit.h>
47 #include <p11-kit/pin.h>
49 static P11KitPin *pin_callback(const char *pin_source, P11KitUri *pin_uri,
50 const char *pin_description,
55 #include "openconnect-internal.h"
57 /* Helper functions for reading/writing lines over SSL.
58 We could use cURL for the HTTP stuff, but it's overkill */
60 int openconnect_SSL_write(struct openconnect_info *vpninfo, char *buf, size_t len)
62 size_t orig_len = len;
65 int done = gnutls_record_send(vpninfo->https_sess, buf, len);
68 else if (done != GNUTLS_E_AGAIN) {
69 vpn_progress(vpninfo, PRG_ERR, _("Failed to write to SSL socket: %s"),
70 gnutls_strerror(done));
73 fd_set wr_set, rd_set;
74 int maxfd = vpninfo->ssl_fd;
79 if (gnutls_record_get_direction(vpninfo->https_sess))
80 FD_SET(vpninfo->ssl_fd, &wr_set);
82 FD_SET(vpninfo->ssl_fd, &rd_set);
84 if (vpninfo->cancel_fd != -1) {
85 FD_SET(vpninfo->cancel_fd, &rd_set);
86 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
87 maxfd = vpninfo->cancel_fd;
89 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
90 if (vpninfo->cancel_fd != -1 &&
91 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
92 vpn_progress(vpninfo, PRG_ERR, _("SSL write cancelled\n"));
100 int openconnect_SSL_read(struct openconnect_info *vpninfo, char *buf, size_t len)
104 while ((done = gnutls_record_recv(vpninfo->https_sess, buf, len)) < 0) {
105 fd_set wr_set, rd_set;
106 int maxfd = vpninfo->ssl_fd;
108 if (done != GNUTLS_E_AGAIN) {
109 vpn_progress(vpninfo, PRG_ERR, _("Failed to read from SSL socket: %s"),
110 gnutls_strerror(done));
116 if (gnutls_record_get_direction(vpninfo->https_sess))
117 FD_SET(vpninfo->ssl_fd, &wr_set);
119 FD_SET(vpninfo->ssl_fd, &rd_set);
121 if (vpninfo->cancel_fd != -1) {
122 FD_SET(vpninfo->cancel_fd, &rd_set);
123 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
124 maxfd = vpninfo->cancel_fd;
126 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
127 if (vpninfo->cancel_fd != -1 &&
128 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
129 vpn_progress(vpninfo, PRG_ERR, _("SSL read cancelled\n"));
137 int openconnect_SSL_gets(struct openconnect_info *vpninfo, char *buf, size_t len)
146 ret = gnutls_record_recv(vpninfo->https_sess, buf + i, 1);
148 if (buf[i] == '\n') {
150 if (i && buf[i-1] == '\r') {
162 } else if (ret != GNUTLS_E_AGAIN) {
163 vpn_progress(vpninfo, PRG_ERR, _("Failed to read from SSL socket: %s\n"),
164 gnutls_strerror(ret));
168 fd_set rd_set, wr_set;
169 int maxfd = vpninfo->ssl_fd;
174 if (gnutls_record_get_direction(vpninfo->https_sess))
175 FD_SET(vpninfo->ssl_fd, &wr_set);
177 FD_SET(vpninfo->ssl_fd, &rd_set);
179 if (vpninfo->cancel_fd != -1) {
180 FD_SET(vpninfo->cancel_fd, &rd_set);
181 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
182 maxfd = vpninfo->cancel_fd;
184 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
185 if (vpninfo->cancel_fd != -1 &&
186 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
187 vpn_progress(vpninfo, PRG_ERR, _("SSL read cancelled\n"));
197 static int check_certificate_expiry(struct openconnect_info *vpninfo, gnutls_x509_crt_t cert)
199 const char *reason = NULL;
200 time_t expires = gnutls_x509_crt_get_expiration_time(cert);
201 time_t now = time(NULL);
204 vpn_progress(vpninfo, PRG_ERR,
205 _("Could not extract expiration time of certificate\n"));
210 reason = _("Client certificate has expired at");
211 else if (expires < now + vpninfo->cert_expire_warning)
212 reason = _("Client certificate expires soon at");
218 gmtime_r(&expires, &tm);
219 strftime(buf, 80, "%a, %d %b %Y %T %Z", &tm);
221 vpn_progress(vpninfo, PRG_ERR, "%s: %s\n", reason, buf);
226 /* For systems that don't support O_CLOEXEC, just don't bother.
227 It's not open for long anyway. */
232 static int load_datum(struct openconnect_info *vpninfo,
233 gnutls_datum_t *datum, const char *fname)
238 fd = open(fname, O_RDONLY|O_CLOEXEC);
241 vpn_progress(vpninfo, PRG_ERR,
242 _("Failed to open certificate file %s: %s\n"),
243 vpninfo->cert, strerror(err));
246 if (fstat(fd, &st)) {
248 vpn_progress(vpninfo, PRG_ERR,
249 _("Failed to stat certificate file %s: %s\n"),
250 vpninfo->cert, strerror(err));
254 datum->size = st.st_size;
255 datum->data = gnutls_malloc(st.st_size + 1);
257 vpn_progress(vpninfo, PRG_ERR,
258 _("Failed to allocate certificate buffer\n"));
263 if (read(fd, datum->data, datum->size) != datum->size) {
265 vpn_progress(vpninfo, PRG_ERR,
266 _("Failed to read certificate into memory: %s\n"),
269 gnutls_free(datum->data);
272 datum->data[st.st_size] = 0;
277 #ifndef HAVE_GNUTLS_PKCS12_SIMPLE_PARSE
278 /* If we're using a version of GnuTLS from before this was
279 exported, pull in our local copy. */
280 #include "gnutls_pkcs12.c"
283 /* A non-zero, non-error return to make load_certificate() continue and
284 interpreting the file as other types */
287 static int load_pkcs12_certificate(struct openconnect_info *vpninfo,
288 gnutls_datum_t *datum,
289 gnutls_x509_privkey_t *key,
290 gnutls_x509_crt_t **chain,
291 unsigned int *chain_len,
292 gnutls_x509_crt_t **extra_certs,
293 unsigned int *extra_certs_len,
294 gnutls_x509_crl_t *crl)
300 err = gnutls_pkcs12_init(&p12);
302 vpn_progress(vpninfo, PRG_ERR,
303 _("Failed to setup PKCS#12 data structure: %s\n"),
304 gnutls_strerror(err));
308 err = gnutls_pkcs12_import(p12, datum, GNUTLS_X509_FMT_DER, 0);
310 gnutls_pkcs12_deinit(p12);
311 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN)
313 vpn_progress(vpninfo, PRG_ERR,
314 _("Failed to import PKCS#12 file: %s\n"),
315 gnutls_strerror(err));
319 pass = vpninfo->cert_password;
320 while ((err = gnutls_pkcs12_verify_mac(p12, pass)) == GNUTLS_E_MAC_VERIFY_FAILED) {
322 vpn_progress(vpninfo, PRG_ERR,
323 _("Failed to decrypt PKCS#12 certificate file\n"));
325 vpninfo->cert_password = NULL;
326 err = request_passphrase(vpninfo, &pass,
327 _("Enter PKCS#12 pass phrase:"));
329 gnutls_pkcs12_deinit(p12);
333 /* If it wasn't GNUTLS_E_MAC_VERIFY_FAILED, then the problem wasn't just a
334 bad password. Give up. */
339 gnutls_pkcs12_deinit(p12);
341 /* If the first attempt, and we didn't know for sure it was PKCS#12
342 anyway, bail out and try loading it as something different. */
343 if (pass == vpninfo->cert_password &&
344 vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
345 /* Make it non-fatal... */
350 vpn_progress(vpninfo, level,
351 _("Failed to process PKCS#12 file: %s\n"),
352 gnutls_strerror(err));
356 err = gnutls_pkcs12_simple_parse(p12, pass, key, chain, chain_len,
357 extra_certs, extra_certs_len, crl, 0);
358 gnutls_pkcs12_deinit(p12);
360 vpn_progress(vpninfo, PRG_ERR,
361 _("Failed to load PKCS#12 certificate: %s\n"),
362 gnutls_strerror(err));
368 /* Older versions of GnuTLS didn't actually bother to check this, so we'll
370 static int check_issuer_sanity(gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer)
372 #if GNUTLS_VERSION_NUMBER > 0x300014
375 unsigned char id1[512], id2[512];
376 size_t id1_size = 512, id2_size = 512;
379 err = gnutls_x509_crt_get_authority_key_id(cert, id1, &id1_size, NULL);
383 err = gnutls_x509_crt_get_subject_key_id(issuer, id2, &id2_size, NULL);
386 if (id1_size == id2_size && !memcmp(id1, id2, id1_size))
394 static int count_x509_certificates(gnutls_datum_t *datum)
397 char *p = (char *)datum->data;
400 p = strstr(p, "-----BEGIN ");
404 if (!strncmp(p, "CERTIFICATE", 11) ||
405 !strncmp(p, "X509 CERTIFICATE", 16))
411 static int load_certificate(struct openconnect_info *vpninfo)
413 gnutls_datum_t fdata;
414 gnutls_x509_privkey_t key = NULL;
415 gnutls_x509_crl_t crl = NULL;
416 gnutls_x509_crt_t last_cert, cert = NULL;
417 gnutls_x509_crt_t *extra_certs = NULL, *supporting_certs = NULL;
418 unsigned int nr_supporting_certs = 0, nr_extra_certs = 0;
419 unsigned int certs_to_free = 0; /* How many of supporting_certs */
420 int err; /* GnuTLS error */
421 int ret = 0; /* our error (zero or -errno) */
423 unsigned char key_id[20];
424 size_t key_id_size = sizeof(key_id);
426 if (vpninfo->cert_type == CERT_TYPE_TPM) {
427 vpn_progress(vpninfo, PRG_ERR,
428 _("TPM support not available with GnuTLS\n"));
432 if (!strncmp(vpninfo->cert, "pkcs11:", 7)) {
433 char *cert_url = (char *)vpninfo->cert;
434 char *key_url = (char *)vpninfo->sslkey;
439 sprintf(pin_source, "openconnect:%p", vpninfo);
441 uri = p11_kit_uri_new();
442 if (p11_kit_uri_parse(vpninfo->cert, P11_KIT_URI_FOR_OBJECT, uri) != P11_KIT_URI_OK) {
443 vpn_progress(vpninfo, PRG_ERR, _("Failed to parse PKCS#11 URL '%s'\n"),
445 p11_kit_uri_free(uri);
448 if (!p11_kit_uri_get_pin_source(uri)) {
449 p11_kit_uri_set_pin_source(uri, pin_source);
450 p11_kit_uri_format(uri, P11_KIT_URI_FOR_OBJECT, &cert_url);
453 if (p11_kit_uri_parse(vpninfo->sslkey, P11_KIT_URI_FOR_OBJECT, uri) != P11_KIT_URI_OK) {
454 vpn_progress(vpninfo, PRG_ERR, _("Failed to parse PKCS#11 URL '%s'\n"),
456 p11_kit_uri_free(uri);
460 if (!p11_kit_uri_get_pin_source(uri)) {
461 p11_kit_uri_set_pin_source(uri, pin_source);
462 p11_kit_uri_format(uri, P11_KIT_URI_FOR_OBJECT, &key_url);
464 p11_kit_uri_free(uri);
465 p11_kit_pin_register_callback(pin_source, pin_callback, vpninfo, NULL);
467 vpn_progress(vpninfo, PRG_TRACE,
468 _("Using PKCS#11 certificate %s\n"), vpninfo->cert);
470 err = gnutls_certificate_set_x509_key_file(vpninfo->https_cred,
472 GNUTLS_X509_FMT_PEM);
473 if (cert_url != vpninfo->cert)
475 if (key_url != vpninfo->sslkey)
479 vpn_progress(vpninfo, PRG_ERR,
480 _("Error loading PKCS#11 certificate: %s\n"),
481 gnutls_strerror(err));
487 vpn_progress(vpninfo, PRG_TRACE,
488 _("Using certificate file %s\n"), vpninfo->cert);
490 ret = load_datum(vpninfo, &fdata, vpninfo->cert);
494 if (vpninfo->cert_type == CERT_TYPE_PKCS12 ||
495 vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
496 ret = load_pkcs12_certificate(vpninfo, &fdata, &key,
497 &supporting_certs, &nr_supporting_certs,
498 &extra_certs, &nr_extra_certs,
503 if (nr_supporting_certs) {
504 cert = supporting_certs[0];
507 vpn_progress(vpninfo, PRG_ERR,
508 _("PKCS#11 file contained no certificate\n"));
513 /* It returned NOT_PKCS12.
514 Fall through to try PEM formats. */
517 /* We need to know how many there are in *advance*; it won't just allocate
518 the array for us :( */
519 nr_extra_certs = count_x509_certificates(&fdata);
521 nr_extra_certs = 1; /* wtf? Oh well, we'll fail later... */
523 extra_certs = calloc(nr_extra_certs, sizeof(cert));
529 err = gnutls_x509_crt_list_import(extra_certs, &nr_extra_certs, &fdata,
530 GNUTLS_X509_FMT_PEM, 0);
533 if (!err || err == GNUTLS_E_NO_CERTIFICATE_FOUND)
534 reason = _("No certificate found in file");
536 reason = gnutls_strerror(err);
538 vpn_progress(vpninfo, PRG_ERR,
539 _("Loading certificate failed: %s\n"),
544 nr_extra_certs = err;
547 if (vpninfo->sslkey != vpninfo->cert) {
548 gnutls_free(fdata.data);
550 vpn_progress(vpninfo, PRG_TRACE,
551 _("Using private key file %s\n"), vpninfo->cert);
553 ret = load_datum(vpninfo, &fdata, vpninfo->sslkey);
558 gnutls_x509_privkey_init(&key);
559 /* Try PKCS#1 (and PKCS#8 without password) first. GnuTLS doesn't
560 support OpenSSL's old PKCS#1-based encrypted format. We should
561 probably check for it and give a more coherent failure mode. */
562 err = gnutls_x509_privkey_import(key, &fdata, GNUTLS_X509_FMT_PEM);
564 /* If that fails, try PKCS#8 */
565 char *pass = vpninfo->cert_password;
567 /* Yay, just for fun this is *different* to PKCS#12. Where we could
568 try an empty password there, in this case the empty-password case
569 has already been *tried* by gnutls_x509_privkey_import(). If we
570 just call gnutls_x509_privkey_import_pkcs8() with a NULL password,
571 it'll SEGV. You have to set the GNUTLS_PKCS_PLAIN flag if you want
572 to try without a password. Passing NULL evidently isn't enough of
573 a hint. And in GnuTLS 3.1 where that crash has been fixed, passing
574 NULL will cause it to return GNUTLS_E_ENCRYPTED_STRUCTURE (a new
575 error code) rather than GNUTLS_E_DECRYPTION_FAILED. So just pass ""
576 instead of NULL, and don't worry about either case. */
577 while ((err = gnutls_x509_privkey_import_pkcs8(key, &fdata,
580 if (err != GNUTLS_E_DECRYPTION_FAILED) {
581 vpn_progress(vpninfo, PRG_ERR,
582 _("Failed to load private key as PKCS#8: %s\n"),
583 gnutls_strerror(err));
588 vpn_progress(vpninfo, PRG_ERR,
589 _("Failed to decrypt PKCS#8 certificate file\n"));
592 err = request_passphrase(vpninfo, &pass,
593 _("Enter PEM pass phrase:"));
600 err = gnutls_x509_privkey_get_key_id(key, 0, key_id, &key_id_size);
602 vpn_progress(vpninfo, PRG_ERR,
603 _("Failed to get key ID: %s\n"),
604 gnutls_strerror(err));
607 for (i = 0; i < nr_extra_certs; i++) {
608 unsigned char cert_id[20];
609 size_t cert_id_size = sizeof(cert_id);
611 err = gnutls_x509_crt_get_key_id(extra_certs[i], 0, cert_id, &cert_id_size);
615 if (cert_id_size == key_id_size && !memcmp(cert_id, key_id, key_id_size)) {
616 cert = extra_certs[i];
618 /* Move the rest of the array down */
619 for (; i < nr_extra_certs - 1; i++)
620 extra_certs[i] = extra_certs[i+1];
626 /* We shouldn't reach this. It means that we didn't find *any* matching cert */
627 vpn_progress(vpninfo, PRG_ERR,
628 _("No SSL certificate found to match private key\n"));
633 check_certificate_expiry(vpninfo, cert);
636 err = gnutls_certificate_set_x509_crl(vpninfo->https_cred, &crl, 1);
638 vpn_progress(vpninfo, PRG_ERR,
639 _("Setting certificate recovation list failed: %s\n"),
640 gnutls_strerror(err));
645 /* OpenSSL has problems with certificate chains — if there are
646 multiple certs with the same name, it doesn't necessarily
647 choose the _right_ one. (RT#1942)
648 Pick the right ones for ourselves and add them manually. */
650 if (nr_supporting_certs) {
651 /* We already got a bunch of certs from PKCS#12 file.
652 Remember how many need to be freed when we're done,
653 since we'll expand the supporting_certs array with
654 more from the cafile if we can. */
655 last_cert = supporting_certs[nr_supporting_certs-1];
656 certs_to_free = nr_supporting_certs;
659 certs_to_free = nr_supporting_certs = 1;
662 gnutls_x509_crt_t issuer;
664 for (i = 0; i < nr_extra_certs; i++) {
665 if (gnutls_x509_crt_check_issuer(last_cert, extra_certs[i]) &&
666 !check_issuer_sanity(last_cert, extra_certs[i]))
670 if (i < nr_extra_certs) {
671 issuer = extra_certs[i];
673 err = gnutls_certificate_get_issuer(vpninfo->https_cred,
674 last_cert, &issuer, 0);
679 /* The check_issuer_sanity() function works fine as a workaround where
680 it was used above, but when gnutls_certificate_get_issuer() returns
681 a bogus cert, there's nothing we can do to fix it up. We don't get
682 to iterate over all the available certs like we can over our own
684 if (check_issuer_sanity(last_cert, issuer)) {
685 /* Hm, is there a bug reference for this? Or just the git commit
686 reference (c1ef7efb in master, 5196786c in gnutls_3_0_x-2)? */
687 vpn_progress(vpninfo, PRG_ERR,
688 _("WARNING: GnuTLS returned incorrect issuer certs; authentication may fail!\n"));
692 if (issuer == last_cert) {
693 /* Don't actually include the root CA. If they don't already trust it,
694 then handing it to them isn't going to help. But don't omit the
695 original certificate if it's self-signed. */
696 if (nr_supporting_certs > 1)
697 nr_supporting_certs--;
701 /* OK, we found a new cert to add to our chain. */
702 supporting_certs = gnutls_realloc(supporting_certs,
703 sizeof(cert) * ++nr_supporting_certs);
704 if (!supporting_certs) {
705 vpn_progress(vpninfo, PRG_ERR,
706 _("Failed to allocate memory for supporting certificates\n"));
707 /* The world is probably about to end, but try without them anyway */
713 /* First time we actually allocated an array? Copy the first cert into it */
714 if (nr_supporting_certs == 2)
715 supporting_certs[0] = cert;
717 /* Append the new one */
718 supporting_certs[nr_supporting_certs-1] = issuer;
722 for (i = 1; i < nr_supporting_certs; i++) {
726 sprintf(name, "<unknown>");
727 namelen = sizeof(name);
728 if (gnutls_x509_crt_get_dn_by_oid(supporting_certs[i],
729 GNUTLS_OID_X520_COMMON_NAME,
730 0, 0, name, &namelen) &&
731 gnutls_x509_crt_get_dn(supporting_certs[i], name, &namelen))
732 sprintf(name, "<unknown>");
734 vpn_progress(vpninfo, PRG_DEBUG,
735 _("Adding supporting CA '%s'\n"), name);
738 err = gnutls_certificate_set_x509_key(vpninfo->https_cred,
739 supporting_certs ? supporting_certs : &cert,
740 supporting_certs ? 1 : nr_supporting_certs,
743 vpn_progress(vpninfo, PRG_ERR,
744 _("Setting certificate failed: %s\n"),
745 gnutls_strerror(err));
750 gnutls_x509_crl_deinit(crl);
752 gnutls_x509_privkey_deinit(key);
754 gnutls_x509_crt_deinit(cert);
755 /* From 1 because cert is the first one (and might exist
756 even if supporting_certs is NULL) */
757 for (i = 1; i < certs_to_free; i++) {
758 if (supporting_certs[i])
759 gnutls_x509_crt_deinit(supporting_certs[i]);
761 for (i = 0; i < nr_extra_certs; i++) {
763 gnutls_x509_crt_deinit(extra_certs[i]);
765 gnutls_free(extra_certs);
766 gnutls_free(supporting_certs);
767 gnutls_free(fdata.data);
771 static int get_cert_fingerprint(struct openconnect_info *vpninfo,
772 gnutls_x509_crt_t cert,
773 gnutls_digest_algorithm_t algo,
776 unsigned char md[256];
777 size_t md_size = sizeof(md);
780 if (gnutls_x509_crt_get_fingerprint(cert, algo, md, &md_size))
783 for (i=0; i < md_size; i++)
784 sprintf(&buf[i*2], "%02X", md[i]);
789 int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
790 OPENCONNECT_X509 *cert, char *buf)
792 return get_cert_fingerprint(vpninfo, cert, GNUTLS_DIG_MD5, buf);
795 int openconnect_get_cert_sha1(struct openconnect_info *vpninfo,
796 OPENCONNECT_X509 *cert, char *buf)
798 return get_cert_fingerprint(vpninfo, cert, GNUTLS_DIG_SHA1, buf);
801 char *openconnect_get_cert_details(struct openconnect_info *vpninfo,
802 OPENCONNECT_X509 *cert)
807 if (gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL, &buf))
810 /* Just in case gnutls_free() isn't free(), we can't steal it. */
811 ret = strdup((char *)buf.data);
812 gnutls_free(buf.data);
817 int openconnect_get_cert_DER(struct openconnect_info *vpninfo,
818 OPENCONNECT_X509 *cert, unsigned char **buf)
821 unsigned char *ret = NULL;
823 if (gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, ret, &l) !=
824 GNUTLS_E_SHORT_MEMORY_BUFFER)
831 if (gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, ret, &l)) {
839 static int verify_peer(gnutls_session_t session)
841 struct openconnect_info *vpninfo = gnutls_session_get_ptr(session);
842 const gnutls_datum_t *cert_list;
843 gnutls_x509_crt_t cert;
844 unsigned int status, cert_list_size;
845 const char *reason = NULL;
848 if (vpninfo->peer_cert) {
849 gnutls_x509_crt_deinit(vpninfo->peer_cert);
850 vpninfo->peer_cert = NULL;
853 cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
855 vpn_progress(vpninfo, PRG_ERR, _("Server presented no certificate\n"));
856 return GNUTLS_E_CERTIFICATE_ERROR;
859 if (vpninfo->servercert) {
860 unsigned char sha1bin[SHA1_SIZE];
861 char fingerprint[(SHA1_SIZE * 2) + 1];
864 err = openconnect_sha1(sha1bin, cert_list[0].data, cert_list[0].size);
866 vpn_progress(vpninfo, PRG_ERR,
867 _("Could not calculate SHA1 of server's certificate\n"));
868 return GNUTLS_E_CERTIFICATE_ERROR;
870 for (i=0; i < SHA1_SIZE; i++)
871 sprintf(&fingerprint[i*2], "%02X", sha1bin[i]);
873 if (strcasecmp(vpninfo->servercert, fingerprint)) {
874 vpn_progress(vpninfo, PRG_ERR,
875 _("Server SSL certificate didn't match: %s\n"), fingerprint);
876 return GNUTLS_E_CERTIFICATE_ERROR;
881 err = gnutls_certificate_verify_peers2 (session, &status);
883 vpn_progress(vpninfo, PRG_ERR, _("Error checking server cert status\n"));
884 return GNUTLS_E_CERTIFICATE_ERROR;
887 if (status & GNUTLS_CERT_REVOKED)
888 reason = _("certificate revoked");
889 else if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
890 reason = _("signer not found");
891 else if (status & GNUTLS_CERT_SIGNER_NOT_CA)
892 reason = _("signer not a CA certificate");
893 else if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
894 reason = _("insecure algorithm");
895 else if (status & GNUTLS_CERT_NOT_ACTIVATED)
896 reason = _("certificate not yet activated");
897 else if (status & GNUTLS_CERT_EXPIRED)
898 reason = _("certificate expired");
899 else if (status & GNUTLS_CERT_INVALID)
900 /* If this is set and no other reason, it apparently means
901 that signature verification failed. Not entirely sure
902 why we don't just set a bit for that too. */
903 reason = _("signature verification failed");
905 err = gnutls_x509_crt_init(&cert);
907 vpn_progress(vpninfo, PRG_ERR, _("Error initialising X509 cert structure\n"));
908 return GNUTLS_E_CERTIFICATE_ERROR;
911 err = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
913 vpn_progress(vpninfo, PRG_ERR, _("Error importing server's cert\n"));
914 gnutls_x509_crt_deinit(cert);
915 return GNUTLS_E_CERTIFICATE_ERROR;
918 if (!reason && !gnutls_x509_crt_check_hostname(cert, vpninfo->hostname))
919 reason = _("certificate does not match hostname");
922 vpn_progress(vpninfo, PRG_INFO, "Server certificate verify failed: %s\n",
924 if (vpninfo->validate_peer_cert)
925 err = vpninfo->validate_peer_cert(vpninfo->cbdata,
927 reason) ? GNUTLS_E_CERTIFICATE_ERROR : 0;
929 err = GNUTLS_E_CERTIFICATE_ERROR;
932 vpninfo->peer_cert = cert;
938 int openconnect_open_https(struct openconnect_info *vpninfo)
943 if (vpninfo->https_sess)
946 ssl_sock = connect_https_socket(vpninfo);
950 if (!vpninfo->https_cred) {
951 gnutls_certificate_allocate_credentials(&vpninfo->https_cred);
952 gnutls_certificate_set_x509_trust_file(vpninfo->https_cred,
953 "/etc/pki/tls/certs/ca-bundle.crt",
954 GNUTLS_X509_FMT_PEM);
955 gnutls_certificate_set_verify_function (vpninfo->https_cred,
957 /* FIXME: Ensure TLSv1.0, no options */
959 if (vpninfo->cafile) {
960 err = gnutls_certificate_set_x509_trust_file(vpninfo->https_cred,
962 GNUTLS_X509_FMT_PEM);
964 vpn_progress(vpninfo, PRG_ERR,
965 _("Failed to open CA file '%s': %s\n"),
966 vpninfo->cafile, gnutls_strerror(err));
973 err = load_certificate(vpninfo);
975 vpn_progress(vpninfo, PRG_ERR,
976 _("Loading certificate failed. Aborting.\n"));
981 /* We just want to do:
982 SSL_CTX_set_purpose(vpninfo->https_ctx, X509_PURPOSE_ANY);
983 ... but it doesn't work with OpenSSL < 0.9.8k because of
984 problems with inheritance (fixed in v1.1.4.6 of
985 crypto/x509/x509_vpm.c) so we have to play silly buggers
986 instead. This trick doesn't work _either_ in < 0.9.7 but
987 I don't know of _any_ workaround which will, and can't
988 be bothered to find out either. */
992 gnutls_init (&vpninfo->https_sess, GNUTLS_CLIENT);
993 gnutls_session_set_ptr (vpninfo->https_sess, (void *) vpninfo);
994 err = gnutls_priority_set_direct (vpninfo->https_sess, "NONE:+VERS-TLS1.0:+SHA1:+AES-128-CBC:+RSA:+COMP-NULL:%COMPAT:%DISABLE_SAFE_RENEGOTIATION", NULL);
996 vpn_progress(vpninfo, PRG_ERR,
997 _("Failed to set TLS priority string: %s\n"),
998 gnutls_strerror(err));
1002 gnutls_record_disable_padding (vpninfo->https_sess);
1003 gnutls_credentials_set (vpninfo->https_sess, GNUTLS_CRD_CERTIFICATE, vpninfo->https_cred);
1004 gnutls_transport_set_ptr(vpninfo->https_sess, /* really? */(gnutls_transport_ptr_t)(long) ssl_sock);
1006 vpn_progress(vpninfo, PRG_INFO, _("SSL negotiation with %s\n"),
1009 while ((err = gnutls_handshake (vpninfo->https_sess))) {
1010 if (err == GNUTLS_E_AGAIN) {
1011 fd_set rd_set, wr_set;
1012 int maxfd = ssl_sock;
1017 if (gnutls_record_get_direction(vpninfo->https_sess))
1018 FD_SET(ssl_sock, &wr_set);
1020 FD_SET(ssl_sock, &rd_set);
1022 if (vpninfo->cancel_fd != -1) {
1023 FD_SET(vpninfo->cancel_fd, &rd_set);
1024 if (vpninfo->cancel_fd > ssl_sock)
1025 maxfd = vpninfo->cancel_fd;
1027 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
1028 if (vpninfo->cancel_fd != -1 &&
1029 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
1030 vpn_progress(vpninfo, PRG_ERR, _("SSL connection cancelled\n"));
1031 gnutls_deinit(vpninfo->https_sess);
1032 vpninfo->https_sess = NULL;
1036 } else if (err == GNUTLS_E_INTERRUPTED || gnutls_error_is_fatal(err)) {
1037 vpn_progress(vpninfo, PRG_ERR, _("SSL connection failure: %s\n"),
1038 gnutls_strerror(err));
1039 gnutls_deinit(vpninfo->https_sess);
1040 vpninfo->https_sess = NULL;
1044 /* non-fatal error or warning. Ignore it and continue */
1045 vpn_progress(vpninfo, PRG_TRACE,
1046 _("GnuTLS non-fatal return during handshake: %s\n"),
1047 gnutls_strerror(err));
1051 vpninfo->ssl_fd = ssl_sock;
1053 vpn_progress(vpninfo, PRG_INFO, _("Connected to HTTPS on %s\n"),
1059 void openconnect_close_https(struct openconnect_info *vpninfo, int final)
1061 if (vpninfo->peer_cert) {
1062 gnutls_x509_crt_deinit(vpninfo->peer_cert);
1063 vpninfo->peer_cert = NULL;
1065 if (vpninfo->https_sess) {
1066 gnutls_deinit(vpninfo->https_sess);
1067 vpninfo->https_sess = NULL;
1069 if (vpninfo->ssl_fd != -1) {
1070 close(vpninfo->ssl_fd);
1071 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds);
1072 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
1073 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds);
1074 vpninfo->ssl_fd = -1;
1076 if (final && vpninfo->https_cred) {
1077 gnutls_certificate_free_credentials(vpninfo->https_cred);
1078 vpninfo->https_cred = NULL;
1080 if (!strncmp(vpninfo->cert, "pkcs11:", 7)) {
1081 char pin_source[40];
1083 sprintf(pin_source, "openconnect:%p", vpninfo);
1084 p11_kit_pin_unregister_callback(pin_source, pin_callback, vpninfo);
1090 void openconnect_init_ssl(void)
1092 gnutls_global_init();
1095 int openconnect_sha1(unsigned char *result, void *data, int datalen)
1098 size_t shalen = SHA1_SIZE;
1102 if (gnutls_fingerprint(GNUTLS_DIG_SHA1, &d, result, &shalen))
1108 int openconnect_random(void *bytes, int len)
1110 if (gnutls_rnd(GNUTLS_RND_RANDOM, bytes, len))
1115 int openconnect_local_cert_md5(struct openconnect_info *vpninfo,
1118 const gnutls_datum_t *d;
1123 d = gnutls_certificate_get_ours(vpninfo->https_sess);
1127 if (gnutls_fingerprint(GNUTLS_DIG_MD5, d, buf, &md5len))
1134 static P11KitPin *pin_callback(const char *pin_source, P11KitUri *pin_uri,
1135 const char *pin_description,
1136 P11KitPinFlags flags,
1139 struct openconnect_info *vpninfo = _vpninfo;
1140 struct oc_auth_form f;
1141 struct oc_form_opt o;
1146 if (!vpninfo || !vpninfo->process_auth_form)
1149 memset(&f, 0, sizeof(f));
1150 f.auth_id = (char *)"pkcs11_pin";
1153 message[sizeof(message)-1] = 0;
1154 snprintf(message, sizeof(message) - 1, _("PIN required for %s"), pin_description);
1155 f.message = message;
1158 * p11-kit flags are *odd*.
1159 * RETRY is 0xa, FINAL_TRY is 0x14 and MANY_TRIES is 0x28.
1160 * So don't treat it like a sane bitmask.
1162 if ((flags & P11_KIT_PIN_FLAGS_RETRY) == P11_KIT_PIN_FLAGS_RETRY)
1163 f.error = _("Wrong PIN");
1165 if ((flags & P11_KIT_PIN_FLAGS_FINAL_TRY) == P11_KIT_PIN_FLAGS_FINAL_TRY)
1166 f.banner = _("This is the final try before locking!");
1167 else if ((flags & P11_KIT_PIN_FLAGS_MANY_TRIES) == P11_KIT_PIN_FLAGS_MANY_TRIES)
1168 f.banner = _("Only a few tries left before locking!");
1171 o.type = OC_FORM_OPT_PASSWORD;
1172 o.name = (char *)"pkcs11_pin";
1173 o.label = _("Enter PIN:");
1176 ret = vpninfo->process_auth_form(vpninfo->cbdata, &f);
1177 if (ret || !o.value)
1180 pin = p11_kit_pin_new_for_string(o.value);