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
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
30 #include <openssl/ssl.h>
31 #include <openssl/err.h>
32 #include <openssl/engine.h>
33 #include <openssl/evp.h>
34 #include <openssl/rand.h>
35 #include <openssl/pkcs12.h>
36 #include <openssl/x509v3.h>
37 #include <openssl/x509.h>
38 #include <openssl/bio.h>
40 #include "openconnect-internal.h"
42 int openconnect_sha1(unsigned char *result, void *data, int len)
47 EVP_Digest(data, len, result, NULL, EVP_sha1(), NULL);
48 EVP_MD_CTX_cleanup(&c);
53 int openconnect_get_cert_DER(struct openconnect_info *vpninfo,
54 struct x509_st *cert, unsigned char **buf)
56 BIO *bp = BIO_new(BIO_s_mem());
60 if (!i2d_X509_bio(bp, cert)) {
65 BIO_get_mem_ptr(bp, &certinfo);
72 memcpy(*buf, certinfo->data, l);
77 int openconnect_random(void *bytes, int len)
79 if (RAND_bytes(bytes, len) != 1)
84 /* Helper functions for reading/writing lines over SSL.
85 We could use cURL for the HTTP stuff, but it's overkill */
87 int openconnect_SSL_write(struct openconnect_info *vpninfo, char *buf, size_t len)
89 size_t orig_len = len;
92 int done = SSL_write(vpninfo->https_ssl, buf, len);
97 int err = SSL_get_error(vpninfo->https_ssl, done);
98 fd_set wr_set, rd_set;
99 int maxfd = vpninfo->ssl_fd;
104 if (err == SSL_ERROR_WANT_READ)
105 FD_SET(vpninfo->ssl_fd, &rd_set);
106 else if (err == SSL_ERROR_WANT_WRITE)
107 FD_SET(vpninfo->ssl_fd, &wr_set);
109 vpn_progress(vpninfo, PRG_ERR, _("Failed to write to SSL socket"));
110 openconnect_report_ssl_errors(vpninfo);
113 if (vpninfo->cancel_fd != -1) {
114 FD_SET(vpninfo->cancel_fd, &rd_set);
115 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
116 maxfd = vpninfo->cancel_fd;
118 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
119 if (vpninfo->cancel_fd != -1 &&
120 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
121 vpn_progress(vpninfo, PRG_ERR, _("SSL write cancelled\n"));
129 int openconnect_SSL_read(struct openconnect_info *vpninfo, char *buf, size_t len)
133 while ((done = SSL_read(vpninfo->https_ssl, buf, len)) == -1) {
134 int err = SSL_get_error(vpninfo->https_ssl, done);
135 fd_set wr_set, rd_set;
136 int maxfd = vpninfo->ssl_fd;
141 if (err == SSL_ERROR_WANT_READ)
142 FD_SET(vpninfo->ssl_fd, &rd_set);
143 else if (err == SSL_ERROR_WANT_WRITE)
144 FD_SET(vpninfo->ssl_fd, &wr_set);
146 vpn_progress(vpninfo, PRG_ERR, _("Failed to read from SSL socket"));
147 openconnect_report_ssl_errors(vpninfo);
150 if (vpninfo->cancel_fd != -1) {
151 FD_SET(vpninfo->cancel_fd, &rd_set);
152 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
153 maxfd = vpninfo->cancel_fd;
155 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
156 if (vpninfo->cancel_fd != -1 &&
157 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
158 vpn_progress(vpninfo, PRG_ERR, _("SSL read cancelled\n"));
165 static int print_err(const char *str, size_t len, void *ptr)
167 struct openconnect_info *vpninfo = ptr;
169 vpn_progress(vpninfo, PRG_ERR, "%s", str);
173 void openconnect_report_ssl_errors(struct openconnect_info *vpninfo)
175 ERR_print_errors_cb(print_err, vpninfo);
178 int openconnect_SSL_gets(struct openconnect_info *vpninfo, char *buf, size_t len)
187 ret = SSL_read(vpninfo->https_ssl, buf + i, 1);
189 if (buf[i] == '\n') {
191 if (i && buf[i-1] == '\r') {
204 fd_set rd_set, wr_set;
205 int maxfd = vpninfo->ssl_fd;
210 ret = SSL_get_error(vpninfo->https_ssl, ret);
211 if (ret == SSL_ERROR_WANT_READ)
212 FD_SET(vpninfo->ssl_fd, &rd_set);
213 else if (ret == SSL_ERROR_WANT_WRITE)
214 FD_SET(vpninfo->ssl_fd, &wr_set);
216 vpn_progress(vpninfo, PRG_ERR, _("Failed to read from SSL socket\n"));
217 openconnect_report_ssl_errors(vpninfo);
221 if (vpninfo->cancel_fd != -1) {
222 FD_SET(vpninfo->cancel_fd, &rd_set);
223 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
224 maxfd = vpninfo->cancel_fd;
226 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
227 if (vpninfo->cancel_fd != -1 &&
228 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
229 vpn_progress(vpninfo, PRG_ERR, _("SSL read cancelled\n"));
239 static int pem_pw_cb(char *buf, int len, int w, void *v)
241 struct openconnect_info *vpninfo = v;
245 if (vpninfo->cert_password) {
246 pass = vpninfo->cert_password;
247 vpninfo->cert_password = NULL;
248 } else if (request_passphrase(vpninfo, &pass,
249 _("Enter PEM pass phrase:")))
255 vpn_progress(vpninfo, PRG_ERR,
256 _("PEM password too long (%d >= %d)\n"),
262 memcpy(buf, pass, plen+1);
267 static int load_pkcs12_certificate(struct openconnect_info *vpninfo, PKCS12 *p12)
269 EVP_PKEY *pkey = NULL;
275 pass = vpninfo->cert_password;
276 vpninfo->cert_password = NULL;
278 /* We do this every time round the loop, to work around a bug in
279 OpenSSL < 1.0.0-beta2 -- where the stack at *ca will be freed
280 when PKCS12_parse() returns an error, but *ca is left pointing
281 to the freed memory. */
283 if (!pass && request_passphrase(vpninfo, &pass,
284 _("Enter PKCS#12 pass phrase:")) < 0) {
288 if (!PKCS12_parse(p12, pass, &pkey, &cert, &ca)) {
289 unsigned long err = ERR_peek_error();
291 openconnect_report_ssl_errors(vpninfo);
293 if (ERR_GET_LIB(err) == ERR_LIB_PKCS12 &&
294 ERR_GET_FUNC(err) == PKCS12_F_PKCS12_PARSE &&
295 ERR_GET_REASON(err) == PKCS12_R_MAC_VERIFY_FAILURE) {
296 vpn_progress(vpninfo, PRG_ERR,
297 _("Parse PKCS#12 failed (wrong passphrase?)\n"));
303 vpn_progress(vpninfo, PRG_ERR,
304 _("Parse PKCS#12 failed (see above errors)\n"));
309 vpninfo->cert_x509 = cert;
310 SSL_CTX_use_certificate(vpninfo->https_ctx, cert);
312 vpn_progress(vpninfo, PRG_ERR,
313 _("PKCS#12 contained no certificate!"));
318 SSL_CTX_use_PrivateKey(vpninfo->https_ctx, pkey);
321 vpn_progress(vpninfo, PRG_ERR,
322 _("PKCS#12 contained no private key!"));
326 /* Only include supporting certificates which are actually necessary */
330 for (i = 0; i < sk_X509_num(ca); i++) {
331 X509 *cert2 = sk_X509_value(ca, i);
332 if (X509_check_issued(cert2, cert) == X509_V_OK) {
337 if (X509_check_issued(cert2, cert2) == X509_V_OK)
340 X509_NAME_oneline(X509_get_subject_name(cert2),
342 vpn_progress(vpninfo, PRG_DEBUG,
343 _("Extra cert from PKCS#12: '%s'\n"), buf);
344 CRYPTO_add(&cert2->references, 1, CRYPTO_LOCK_X509);
345 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert2);
350 sk_X509_pop_free(ca, X509_free);
358 static int load_tpm_certificate(struct openconnect_info *vpninfo)
362 ENGINE_load_builtin_engines();
364 e = ENGINE_by_id("tpm");
366 vpn_progress(vpninfo, PRG_ERR, _("Can't load TPM engine.\n"));
367 openconnect_report_ssl_errors(vpninfo);
370 if (!ENGINE_init(e) || !ENGINE_set_default_RSA(e) ||
371 !ENGINE_set_default_RAND(e)) {
372 vpn_progress(vpninfo, PRG_ERR, _("Failed to init TPM engine\n"));
373 openconnect_report_ssl_errors(vpninfo);
378 if (vpninfo->cert_password) {
379 if (!ENGINE_ctrl_cmd(e, "PIN", strlen(vpninfo->cert_password),
380 vpninfo->cert_password, NULL, 0)) {
381 vpn_progress(vpninfo, PRG_ERR,
382 _("Failed to set TPM SRK password\n"));
383 openconnect_report_ssl_errors(vpninfo);
386 key = ENGINE_load_private_key(e, vpninfo->sslkey, NULL, NULL);
388 vpn_progress(vpninfo, PRG_ERR,
389 _("Failed to load TPM private key\n"));
390 openconnect_report_ssl_errors(vpninfo);
395 if (!SSL_CTX_use_PrivateKey(vpninfo->https_ctx, key)) {
396 vpn_progress(vpninfo, PRG_ERR, _("Add key from TPM failed\n"));
397 openconnect_report_ssl_errors(vpninfo);
405 static int load_tpm_certificate(struct openconnect_info *vpninfo)
407 vpn_progress(vpninfo, PRG_ERR,
408 _("This version of OpenConnect was built without TPM support\n"));
413 static int reload_pem_cert(struct openconnect_info *vpninfo)
415 BIO *b = BIO_new(BIO_s_file_internal());
420 if (BIO_read_filename(b, vpninfo->cert) <= 0) {
423 vpn_progress(vpninfo, PRG_ERR,
424 _("Failed to reload X509 cert for expiry check\n"));
425 openconnect_report_ssl_errors(vpninfo);
428 vpninfo->cert_x509 = PEM_read_bio_X509_AUX(b, NULL, NULL, NULL);
429 if (!vpninfo->cert_x509)
435 static int load_certificate(struct openconnect_info *vpninfo)
437 vpn_progress(vpninfo, PRG_TRACE,
438 _("Using certificate file %s\n"), vpninfo->cert);
440 if (vpninfo->cert_type == CERT_TYPE_PKCS12 ||
441 vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
445 f = fopen(vpninfo->cert, "r");
447 vpn_progress(vpninfo, PRG_ERR,
448 _("Failed to open certificate file %s: %s\n"),
449 vpninfo->cert, strerror(errno));
452 p12 = d2i_PKCS12_fp(f, NULL);
455 return load_pkcs12_certificate(vpninfo, p12);
458 if (vpninfo->cert_type == CERT_TYPE_PKCS12) {
459 vpn_progress(vpninfo, PRG_ERR, _("Read PKCS#12 failed\n"));
460 openconnect_report_ssl_errors(vpninfo);
463 /* Clear error and fall through to see if it's a PEM file... */
467 /* It's PEM or TPM now, and either way we need to load the plain cert: */
468 if (!SSL_CTX_use_certificate_chain_file(vpninfo->https_ctx,
470 vpn_progress(vpninfo, PRG_ERR,
471 _("Loading certificate failed\n"));
472 openconnect_report_ssl_errors(vpninfo);
476 /* Ew, we can't get it back from the OpenSSL CTX in any sane fashion */
477 reload_pem_cert(vpninfo);
479 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
480 FILE *f = fopen(vpninfo->sslkey, "r");
484 vpn_progress(vpninfo, PRG_ERR,
485 _("Failed to open private key file %s: %s\n"),
486 vpninfo->cert, strerror(errno));
491 while (fgets(buf, 255, f)) {
492 if (!strcmp(buf, "-----BEGIN TSS KEY BLOB-----\n")) {
493 vpninfo->cert_type = CERT_TYPE_TPM;
495 } else if (!strcmp(buf, "-----BEGIN RSA PRIVATE KEY-----\n") ||
496 !strcmp(buf, "-----BEGIN DSA PRIVATE KEY-----\n") ||
497 !strcmp(buf, "-----BEGIN ENCRYPTED PRIVATE KEY-----\n")) {
498 vpninfo->cert_type = CERT_TYPE_PEM;
503 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
504 vpn_progress(vpninfo, PRG_ERR,
505 _("Failed to identify private key type in '%s'\n"),
511 if (vpninfo->cert_type == CERT_TYPE_TPM)
512 return load_tpm_certificate(vpninfo);
514 /* Standard PEM certificate */
515 SSL_CTX_set_default_passwd_cb(vpninfo->https_ctx, pem_pw_cb);
516 SSL_CTX_set_default_passwd_cb_userdata(vpninfo->https_ctx, vpninfo);
518 if (!SSL_CTX_use_RSAPrivateKey_file(vpninfo->https_ctx, vpninfo->sslkey,
520 unsigned long err = ERR_peek_error();
522 openconnect_report_ssl_errors(vpninfo);
524 #ifndef EVP_F_EVP_DECRYPTFINAL_EX
525 #define EVP_F_EVP_DECRYPTFINAL_EX EVP_F_EVP_DECRYPTFINAL
527 /* If the user fat-fingered the passphrase, try again */
528 if (ERR_GET_LIB(err) == ERR_LIB_EVP &&
529 ERR_GET_FUNC(err) == EVP_F_EVP_DECRYPTFINAL_EX &&
530 ERR_GET_REASON(err) == EVP_R_BAD_DECRYPT) {
531 vpn_progress(vpninfo, PRG_ERR,
532 _("Loading private key failed (wrong passphrase?)\n"));
536 vpn_progress(vpninfo, PRG_ERR,
537 _("Loading private key failed (see above errors)\n"));
543 static int get_cert_fingerprint(struct openconnect_info *vpninfo,
544 X509 *cert, const EVP_MD *type,
547 unsigned char md[EVP_MAX_MD_SIZE];
550 if (!X509_digest(cert, type, md, &n))
553 for (i=0; i < n; i++)
554 sprintf(&buf[i*2], "%02X", md[i]);
559 int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
560 X509 *cert, char *buf)
562 return get_cert_fingerprint(vpninfo, cert, EVP_md5(), buf);
565 int openconnect_get_cert_sha1(struct openconnect_info *vpninfo,
566 X509 *cert, char *buf)
568 return get_cert_fingerprint(vpninfo, cert, EVP_sha1(), buf);
571 static int check_server_cert(struct openconnect_info *vpninfo, X509 *cert)
573 char fingerprint[EVP_MAX_MD_SIZE * 2 + 1];
576 ret = openconnect_get_cert_sha1(vpninfo, cert, fingerprint);
580 if (strcasecmp(vpninfo->servercert, fingerprint)) {
581 vpn_progress(vpninfo, PRG_ERR,
582 _("Server SSL certificate didn't match: %s\n"), fingerprint);
588 static int match_hostname_elem(const char *hostname, int helem_len,
589 const char *match, int melem_len)
591 if (!helem_len && !melem_len)
594 if (!helem_len || !melem_len)
598 if (match[0] == '*') {
601 for (i = 1 ; i <= helem_len; i++) {
602 if (!match_hostname_elem(hostname + i, helem_len - i,
603 match + 1, melem_len - 1))
609 /* From the NetBSD (5.1) man page for ctype(3):
610 Values of type char or signed char must first be cast to unsigned char,
611 to ensure that the values are within the correct range. The result
612 should then be cast to int to avoid warnings from some compilers.
613 We do indeed get warning "array subscript has type 'char'" without
615 if (toupper((int)(unsigned char)hostname[0]) ==
616 toupper((int)(unsigned char)match[0]))
617 return match_hostname_elem(hostname + 1, helem_len - 1,
618 match + 1, melem_len - 1);
623 static int match_hostname(const char *hostname, const char *match)
626 const char *h_dot, *m_dot;
627 int helem_len, melem_len;
629 h_dot = strchr(hostname, '.');
630 m_dot = strchr(match, '.');
632 if (h_dot && m_dot) {
633 helem_len = h_dot - hostname + 1;
634 melem_len = m_dot - match + 1;
635 } else if (!h_dot && !m_dot) {
636 helem_len = strlen(hostname);
637 melem_len = strlen(match);
642 if (match_hostname_elem(hostname, helem_len,
646 hostname += helem_len;
655 /* cf. RFC2818 and RFC2459 */
656 static int match_cert_hostname(struct openconnect_info *vpninfo, X509 *peer_cert)
658 STACK_OF(GENERAL_NAME) *altnames;
660 ASN1_STRING *subjasn1;
661 char *subjstr = NULL;
664 char addrbuf[sizeof(struct in6_addr)];
667 /* Allow GEN_IP in the certificate only if we actually connected
668 by IP address rather than by name. */
669 if (inet_pton(AF_INET, vpninfo->hostname, addrbuf) > 0)
671 else if (inet_pton(AF_INET6, vpninfo->hostname, addrbuf) > 0)
673 else if (vpninfo->hostname[0] == '[' &&
674 vpninfo->hostname[strlen(vpninfo->hostname)-1] == ']') {
675 char *p = &vpninfo->hostname[strlen(vpninfo->hostname)-1];
677 if (inet_pton(AF_INET6, vpninfo->hostname + 1, addrbuf) > 0)
682 altnames = X509_get_ext_d2i(peer_cert, NID_subject_alt_name,
684 for (i = 0; i < sk_GENERAL_NAME_num(altnames); i++) {
685 const GENERAL_NAME *this = sk_GENERAL_NAME_value(altnames, i);
687 if (this->type == GEN_DNS) {
690 int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
696 /* We don't like names with embedded NUL */
697 if (strlen(str) != len)
700 if (!match_hostname(vpninfo->hostname, str)) {
701 vpn_progress(vpninfo, PRG_TRACE,
702 _("Matched DNS altname '%s'\n"),
704 GENERAL_NAMES_free(altnames);
708 vpn_progress(vpninfo, PRG_TRACE,
709 _("No match for altname '%s'\n"),
713 } else if (this->type == GEN_IPADD && addrlen) {
717 if (this->d.ip->length == 4) {
719 } else if (this->d.ip->length == 16) {
722 vpn_progress(vpninfo, PRG_ERR,
723 _("Certificate has GEN_IPADD altname with bogus length %d\n"),
728 /* We only do this for the debug messages */
729 inet_ntop(family, this->d.ip->data, host, sizeof(host));
731 if (this->d.ip->length == addrlen &&
732 !memcmp(addrbuf, this->d.ip->data, addrlen)) {
733 vpn_progress(vpninfo, PRG_TRACE,
734 _("Matched %s address '%s'\n"),
735 (family == AF_INET6)?"IPv6":"IPv4",
737 GENERAL_NAMES_free(altnames);
740 vpn_progress(vpninfo, PRG_TRACE,
741 _("No match for %s address '%s'\n"),
742 (family == AF_INET6)?"IPv6":"IPv4",
745 } else if (this->type == GEN_URI) {
747 char *url_proto, *url_host, *url_path, *url_host2;
749 int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
754 /* We don't like names with embedded NUL */
755 if (strlen(str) != len)
758 if (internal_parse_url(str, &url_proto, &url_host, &url_port, &url_path, 0)) {
763 if (!url_proto || strcasecmp(url_proto, "https"))
766 if (url_port != vpninfo->port)
769 /* Leave url_host as it was so that it can be freed */
770 url_host2 = url_host;
771 if (addrlen == 16 && vpninfo->hostname[0] != '[' &&
772 url_host[0] == '[' && url_host[strlen(url_host)-1] == ']') {
773 /* Cope with https://[IPv6]/ when the hostname is bare IPv6 */
774 url_host[strlen(url_host)-1] = 0;
778 if (strcasecmp(vpninfo->hostname, url_host2))
782 vpn_progress(vpninfo, PRG_TRACE,
783 _("URI '%s' has non-empty path; ignoring\n"),
785 goto no_uri_match_silent;
787 vpn_progress(vpninfo, PRG_TRACE,
788 _("Matched URI '%s'\n"),
794 GENERAL_NAMES_free(altnames);
798 vpn_progress(vpninfo, PRG_TRACE,
799 _("No match for URI '%s'\n"),
808 GENERAL_NAMES_free(altnames);
810 /* According to RFC2818, we don't use the legacy subject name if
811 there was an altname with DNS type. */
813 vpn_progress(vpninfo, PRG_ERR,
814 _("No altname in peer cert matched '%s'\n"),
819 subjname = X509_get_subject_name(peer_cert);
821 vpn_progress(vpninfo, PRG_ERR,
822 _("No subject name in peer cert!\n"));
826 /* Find the _last_ (most specific) commonName */
829 int j = X509_NAME_get_index_by_NID(subjname, NID_commonName, i);
836 subjasn1 = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subjname, i));
838 i = ASN1_STRING_to_UTF8((void *)&subjstr, subjasn1);
840 if (!subjstr || strlen(subjstr) != i) {
841 vpn_progress(vpninfo, PRG_ERR,
842 _("Failed to parse subject name in peer cert\n"));
847 if (match_hostname(vpninfo->hostname, subjstr)) {
848 vpn_progress(vpninfo, PRG_ERR,
849 _("Peer cert subject mismatch ('%s' != '%s')\n"),
850 subjstr, vpninfo->hostname);
853 vpn_progress(vpninfo, PRG_TRACE,
854 _("Matched peer certificate subject name '%s'\n"),
858 OPENSSL_free(subjstr);
862 static int verify_peer(struct openconnect_info *vpninfo, SSL *https_ssl)
867 peer_cert = SSL_get_peer_certificate(https_ssl);
869 if (vpninfo->servercert) {
870 /* If given a cert fingerprint on the command line, that's
872 ret = check_server_cert(vpninfo, peer_cert);
874 int vfy = SSL_get_verify_result(https_ssl);
875 const char *err_string = NULL;
877 if (vfy != X509_V_OK)
878 err_string = X509_verify_cert_error_string(vfy);
879 else if (match_cert_hostname(vpninfo, peer_cert))
880 err_string = _("certificate does not match hostname");
883 vpn_progress(vpninfo, PRG_INFO,
884 _("Server certificate verify failed: %s\n"),
887 if (vpninfo->validate_peer_cert)
888 ret = vpninfo->validate_peer_cert(vpninfo->cbdata,
897 X509_free(peer_cert);
902 static void workaround_openssl_certchain_bug(struct openconnect_info *vpninfo,
905 /* OpenSSL has problems with certificate chains -- if there are
906 multiple certs with the same name, it doesn't necessarily
907 choose the _right_ one. (RT#1942)
908 Pick the right ones for ourselves and add them manually. */
909 X509 *cert = SSL_get_certificate(ssl);
911 X509_STORE *store = SSL_CTX_get_cert_store(vpninfo->https_ctx);
917 /* If we already have 'supporting' certs, don't add them again */
918 if (vpninfo->https_ctx->extra_certs)
921 if (!X509_STORE_CTX_init(&ctx, store, NULL, NULL))
924 while (ctx.get_issuer(&cert2, &ctx, cert) == 1) {
928 if (X509_check_issued(cert2, cert2) == X509_V_OK)
931 X509_NAME_oneline(X509_get_subject_name(cert),
933 vpn_progress(vpninfo, PRG_DEBUG,
934 _("Extra cert from cafile: '%s'\n"), buf);
935 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert);
937 X509_STORE_CTX_cleanup(&ctx);
940 #if OPENSSL_VERSION_NUMBER >= 0x00908000
941 static int ssl_app_verify_callback(X509_STORE_CTX *ctx, void *arg)
943 /* We've seen certificates in the wild which don't have the
944 purpose fields filled in correctly */
945 X509_VERIFY_PARAM_set_purpose(ctx->param, X509_PURPOSE_ANY);
946 return X509_verify_cert(ctx);
950 static int check_certificate_expiry(struct openconnect_info *vpninfo)
953 const char *reason = NULL;
957 if (!vpninfo->cert_x509)
961 notAfter = X509_get_notAfter(vpninfo->cert_x509);
962 i = X509_cmp_time(notAfter, &t);
964 vpn_progress(vpninfo, PRG_ERR,
965 _("Error in client cert notAfter field\n"));
968 reason = _("Client certificate has expired at");
970 t += vpninfo->cert_expire_warning;
971 i = X509_cmp_time(notAfter, &t);
973 reason = _("Client certificate expires soon at");
977 BIO *bp = BIO_new(BIO_s_mem());
979 const char *expiry = _("<error>");
983 ASN1_TIME_print(bp, notAfter);
984 BIO_write(bp, &zero, 1);
985 BIO_get_mem_ptr(bp, &bm);
988 vpn_progress(vpninfo, PRG_ERR, "%s: %s\n", reason, expiry);
994 int openconnect_open_https(struct openconnect_info *vpninfo)
996 method_const SSL_METHOD *ssl3_method;
1002 if (vpninfo->https_ssl)
1005 if (vpninfo->peer_cert) {
1006 X509_free(vpninfo->peer_cert);
1007 vpninfo->peer_cert = NULL;
1010 ssl_sock = connect_https_socket(vpninfo);
1014 ssl3_method = TLSv1_client_method();
1015 if (!vpninfo->https_ctx) {
1016 vpninfo->https_ctx = SSL_CTX_new(ssl3_method);
1018 /* Some servers (or their firewalls) really don't like seeing
1020 #ifdef SSL_OP_NO_TICKET
1021 SSL_CTX_set_options (vpninfo->https_ctx, SSL_OP_NO_TICKET);
1024 if (vpninfo->cert) {
1025 err = load_certificate(vpninfo);
1027 vpn_progress(vpninfo, PRG_ERR,
1028 _("Loading certificate failed. Aborting.\n"));
1031 check_certificate_expiry(vpninfo);
1034 /* We just want to do:
1035 SSL_CTX_set_purpose(vpninfo->https_ctx, X509_PURPOSE_ANY);
1036 ... but it doesn't work with OpenSSL < 0.9.8k because of
1037 problems with inheritance (fixed in v1.1.4.6 of
1038 crypto/x509/x509_vpm.c) so we have to play silly buggers
1039 instead. This trick doesn't work _either_ in < 0.9.7 but
1040 I don't know of _any_ workaround which will, and can't
1041 be bothered to find out either. */
1042 #if OPENSSL_VERSION_NUMBER >= 0x00908000
1043 SSL_CTX_set_cert_verify_callback(vpninfo->https_ctx,
1044 ssl_app_verify_callback, NULL);
1046 SSL_CTX_set_default_verify_paths(vpninfo->https_ctx);
1048 if (vpninfo->cafile) {
1049 if (!SSL_CTX_load_verify_locations(vpninfo->https_ctx, vpninfo->cafile, NULL)) {
1050 vpn_progress(vpninfo, PRG_ERR,
1051 _("Failed to open CA file '%s'\n"),
1053 openconnect_report_ssl_errors(vpninfo);
1060 https_ssl = SSL_new(vpninfo->https_ctx);
1061 workaround_openssl_certchain_bug(vpninfo, https_ssl);
1063 https_bio = BIO_new_socket(ssl_sock, BIO_NOCLOSE);
1064 BIO_set_nbio(https_bio, 1);
1065 SSL_set_bio(https_ssl, https_bio, https_bio);
1067 vpn_progress(vpninfo, PRG_INFO, _("SSL negotiation with %s\n"),
1070 while ((err = SSL_connect(https_ssl)) <= 0) {
1071 fd_set wr_set, rd_set;
1072 int maxfd = ssl_sock;
1077 err = SSL_get_error(https_ssl, err);
1078 if (err == SSL_ERROR_WANT_READ)
1079 FD_SET(ssl_sock, &rd_set);
1080 else if (err == SSL_ERROR_WANT_WRITE)
1081 FD_SET(ssl_sock, &wr_set);
1083 vpn_progress(vpninfo, PRG_ERR, _("SSL connection failure\n"));
1084 openconnect_report_ssl_errors(vpninfo);
1085 SSL_free(https_ssl);
1090 if (vpninfo->cancel_fd != -1) {
1091 FD_SET(vpninfo->cancel_fd, &rd_set);
1092 if (vpninfo->cancel_fd > ssl_sock)
1093 maxfd = vpninfo->cancel_fd;
1095 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
1096 if (vpninfo->cancel_fd != -1 &&
1097 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
1098 vpn_progress(vpninfo, PRG_ERR, _("SSL connection cancelled\n"));
1099 SSL_free(https_ssl);
1105 if (verify_peer(vpninfo, https_ssl)) {
1106 SSL_free(https_ssl);
1111 vpninfo->ssl_fd = ssl_sock;
1112 vpninfo->https_ssl = https_ssl;
1114 /* Stash this now, because it might not be available later if the
1115 server has disconnected. */
1116 vpninfo->peer_cert = SSL_get_peer_certificate(vpninfo->https_ssl);
1118 vpn_progress(vpninfo, PRG_INFO, _("Connected to HTTPS on %s\n"),
1124 void openconnect_close_https(struct openconnect_info *vpninfo)
1126 if (vpninfo->peer_cert) {
1127 X509_free(vpninfo->peer_cert);
1128 vpninfo->peer_cert = NULL;
1130 if (vpninfo->https_ssl) {
1131 SSL_free(vpninfo->https_ssl);
1132 vpninfo->https_ssl = NULL;
1134 if (vpninfo->ssl_fd != -1) {
1135 close(vpninfo->ssl_fd);
1136 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds);
1137 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
1138 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds);
1139 vpninfo->ssl_fd = -1;
1143 void openconnect_init_openssl(void)
1145 SSL_library_init ();
1147 SSL_load_error_strings ();
1148 OpenSSL_add_all_algorithms ();
1151 char *openconnect_get_cert_details(struct openconnect_info *vpninfo,
1152 struct x509_st *cert)
1154 BIO *bp = BIO_new(BIO_s_mem());
1159 X509_print_ex(bp, cert, 0, 0);
1160 BIO_write(bp, &zero, 1);
1161 BIO_get_mem_ptr(bp, &certinfo);
1163 ret = strdup(certinfo->data);
1169 int openconnect_local_cert_md5(struct openconnect_info *vpninfo,
1174 if (!vpninfo->cert_x509)
1177 if (get_cert_md5_fingerprint(vpninfo, vpninfo->cert_x509, buf))