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;
243 /* Only try the provided password once... */
244 SSL_CTX_set_default_passwd_cb(vpninfo->https_ctx, NULL);
245 SSL_CTX_set_default_passwd_cb_userdata(vpninfo->https_ctx, NULL);
247 if (len <= strlen(vpninfo->cert_password)) {
248 vpn_progress(vpninfo, PRG_ERR,
249 _("PEM password too long (%zd >= %d)\n"),
250 strlen(vpninfo->cert_password), len);
253 strcpy(buf, vpninfo->cert_password);
254 return strlen(vpninfo->cert_password);
257 static int load_pkcs12_certificate(struct openconnect_info *vpninfo, PKCS12 *p12)
259 EVP_PKEY *pkey = NULL;
265 pass = vpninfo->cert_password;
266 vpninfo->cert_password = NULL;
268 /* We do this every time round the loop, to work around a bug in
269 OpenSSL < 1.0.0-beta2 -- where the stack at *ca will be freed
270 when PKCS12_parse() returns an error, but *ca is left pointing
271 to the freed memory. */
273 if (!pass && request_passphrase(vpninfo, &pass,
274 _("Enter PKCS#12 pass phrase:")) < 0) {
278 if (!PKCS12_parse(p12, pass, &pkey, &cert, &ca)) {
279 unsigned long err = ERR_peek_error();
281 openconnect_report_ssl_errors(vpninfo);
283 if (ERR_GET_LIB(err) == ERR_LIB_PKCS12 &&
284 ERR_GET_FUNC(err) == PKCS12_F_PKCS12_PARSE &&
285 ERR_GET_REASON(err) == PKCS12_R_MAC_VERIFY_FAILURE) {
286 vpn_progress(vpninfo, PRG_ERR,
287 _("Parse PKCS#12 failed (wrong passphrase?)\n"));
293 vpn_progress(vpninfo, PRG_ERR,
294 _("Parse PKCS#12 failed (see above errors)\n"));
299 vpninfo->cert_x509 = cert;
300 SSL_CTX_use_certificate(vpninfo->https_ctx, cert);
302 vpn_progress(vpninfo, PRG_ERR,
303 _("PKCS#12 contained no certificate!"));
308 SSL_CTX_use_PrivateKey(vpninfo->https_ctx, pkey);
311 vpn_progress(vpninfo, PRG_ERR,
312 _("PKCS#12 contained no private key!"));
316 /* Only include supporting certificates which are actually necessary */
320 for (i = 0; i < sk_X509_num(ca); i++) {
321 X509 *cert2 = sk_X509_value(ca, i);
322 if (X509_check_issued(cert2, cert) == X509_V_OK) {
327 if (X509_check_issued(cert2, cert2) == X509_V_OK)
330 X509_NAME_oneline(X509_get_subject_name(cert2),
332 vpn_progress(vpninfo, PRG_DEBUG,
333 _("Extra cert from PKCS#12: '%s'\n"), buf);
334 CRYPTO_add(&cert2->references, 1, CRYPTO_LOCK_X509);
335 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert2);
340 sk_X509_pop_free(ca, X509_free);
348 static int load_tpm_certificate(struct openconnect_info *vpninfo)
352 ENGINE_load_builtin_engines();
354 e = ENGINE_by_id("tpm");
356 vpn_progress(vpninfo, PRG_ERR, _("Can't load TPM engine.\n"));
357 openconnect_report_ssl_errors(vpninfo);
360 if (!ENGINE_init(e) || !ENGINE_set_default_RSA(e) ||
361 !ENGINE_set_default_RAND(e)) {
362 vpn_progress(vpninfo, PRG_ERR, _("Failed to init TPM engine\n"));
363 openconnect_report_ssl_errors(vpninfo);
368 if (vpninfo->cert_password) {
369 if (!ENGINE_ctrl_cmd(e, "PIN", strlen(vpninfo->cert_password),
370 vpninfo->cert_password, NULL, 0)) {
371 vpn_progress(vpninfo, PRG_ERR,
372 _("Failed to set TPM SRK password\n"));
373 openconnect_report_ssl_errors(vpninfo);
376 key = ENGINE_load_private_key(e, vpninfo->sslkey, NULL, NULL);
378 vpn_progress(vpninfo, PRG_ERR,
379 _("Failed to load TPM private key\n"));
380 openconnect_report_ssl_errors(vpninfo);
385 if (!SSL_CTX_use_PrivateKey(vpninfo->https_ctx, key)) {
386 vpn_progress(vpninfo, PRG_ERR, _("Add key from TPM failed\n"));
387 openconnect_report_ssl_errors(vpninfo);
395 static int load_tpm_certificate(struct openconnect_info *vpninfo)
397 vpn_progress(vpninfo, PRG_ERR,
398 _("This version of OpenConnect was built without TPM support\n"));
403 static int reload_pem_cert(struct openconnect_info *vpninfo)
405 BIO *b = BIO_new(BIO_s_file_internal());
410 if (BIO_read_filename(b, vpninfo->cert) <= 0) {
413 vpn_progress(vpninfo, PRG_ERR,
414 _("Failed to reload X509 cert for expiry check\n"));
415 openconnect_report_ssl_errors(vpninfo);
418 vpninfo->cert_x509 = PEM_read_bio_X509_AUX(b, NULL, NULL, NULL);
419 if (!vpninfo->cert_x509)
425 static int load_certificate(struct openconnect_info *vpninfo)
427 vpn_progress(vpninfo, PRG_TRACE,
428 _("Using certificate file %s\n"), vpninfo->cert);
430 if (vpninfo->cert_type == CERT_TYPE_PKCS12 ||
431 vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
435 f = fopen(vpninfo->cert, "r");
437 vpn_progress(vpninfo, PRG_ERR,
438 _("Failed to open certificate file %s: %s\n"),
439 vpninfo->cert, strerror(errno));
442 p12 = d2i_PKCS12_fp(f, NULL);
445 return load_pkcs12_certificate(vpninfo, p12);
448 if (vpninfo->cert_type == CERT_TYPE_PKCS12) {
449 vpn_progress(vpninfo, PRG_ERR, _("Read PKCS#12 failed\n"));
450 openconnect_report_ssl_errors(vpninfo);
453 /* Clear error and fall through to see if it's a PEM file... */
457 /* It's PEM or TPM now, and either way we need to load the plain cert: */
458 if (!SSL_CTX_use_certificate_chain_file(vpninfo->https_ctx,
460 vpn_progress(vpninfo, PRG_ERR,
461 _("Loading certificate failed\n"));
462 openconnect_report_ssl_errors(vpninfo);
466 /* Ew, we can't get it back from the OpenSSL CTX in any sane fashion */
467 reload_pem_cert(vpninfo);
469 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
470 FILE *f = fopen(vpninfo->sslkey, "r");
474 vpn_progress(vpninfo, PRG_ERR,
475 _("Failed to open private key file %s: %s\n"),
476 vpninfo->cert, strerror(errno));
481 while (fgets(buf, 255, f)) {
482 if (!strcmp(buf, "-----BEGIN TSS KEY BLOB-----\n")) {
483 vpninfo->cert_type = CERT_TYPE_TPM;
485 } else if (!strcmp(buf, "-----BEGIN RSA PRIVATE KEY-----\n") ||
486 !strcmp(buf, "-----BEGIN DSA PRIVATE KEY-----\n") ||
487 !strcmp(buf, "-----BEGIN ENCRYPTED PRIVATE KEY-----\n")) {
488 vpninfo->cert_type = CERT_TYPE_PEM;
493 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
494 vpn_progress(vpninfo, PRG_ERR,
495 _("Failed to identify private key type in '%s'\n"),
501 if (vpninfo->cert_type == CERT_TYPE_TPM)
502 return load_tpm_certificate(vpninfo);
504 /* Standard PEM certificate */
505 if (vpninfo->cert_password) {
506 SSL_CTX_set_default_passwd_cb(vpninfo->https_ctx,
508 SSL_CTX_set_default_passwd_cb_userdata(vpninfo->https_ctx,
512 if (!SSL_CTX_use_RSAPrivateKey_file(vpninfo->https_ctx, vpninfo->sslkey,
514 unsigned long err = ERR_peek_error();
516 openconnect_report_ssl_errors(vpninfo);
518 #ifndef EVP_F_EVP_DECRYPTFINAL_EX
519 #define EVP_F_EVP_DECRYPTFINAL_EX EVP_F_EVP_DECRYPTFINAL
521 /* If the user fat-fingered the passphrase, try again */
522 if (ERR_GET_LIB(err) == ERR_LIB_EVP &&
523 ERR_GET_FUNC(err) == EVP_F_EVP_DECRYPTFINAL_EX &&
524 ERR_GET_REASON(err) == EVP_R_BAD_DECRYPT) {
525 vpn_progress(vpninfo, PRG_ERR,
526 _("Loading private key failed (wrong passphrase?)\n"));
530 vpn_progress(vpninfo, PRG_ERR,
531 _("Loading private key failed (see above errors)\n"));
537 static int get_cert_fingerprint(struct openconnect_info *vpninfo,
538 X509 *cert, const EVP_MD *type,
541 unsigned char md[EVP_MAX_MD_SIZE];
544 if (!X509_digest(cert, type, md, &n))
547 for (i=0; i < n; i++)
548 sprintf(&buf[i*2], "%02X", md[i]);
553 int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
554 X509 *cert, char *buf)
556 return get_cert_fingerprint(vpninfo, cert, EVP_md5(), buf);
559 int openconnect_get_cert_sha1(struct openconnect_info *vpninfo,
560 X509 *cert, char *buf)
562 return get_cert_fingerprint(vpninfo, cert, EVP_sha1(), buf);
565 static int check_server_cert(struct openconnect_info *vpninfo, X509 *cert)
567 char fingerprint[EVP_MAX_MD_SIZE * 2 + 1];
570 ret = openconnect_get_cert_sha1(vpninfo, cert, fingerprint);
574 if (strcasecmp(vpninfo->servercert, fingerprint)) {
575 vpn_progress(vpninfo, PRG_ERR,
576 _("Server SSL certificate didn't match: %s\n"), fingerprint);
582 static int match_hostname_elem(const char *hostname, int helem_len,
583 const char *match, int melem_len)
585 if (!helem_len && !melem_len)
588 if (!helem_len || !melem_len)
592 if (match[0] == '*') {
595 for (i = 1 ; i <= helem_len; i++) {
596 if (!match_hostname_elem(hostname + i, helem_len - i,
597 match + 1, melem_len - 1))
603 /* From the NetBSD (5.1) man page for ctype(3):
604 Values of type char or signed char must first be cast to unsigned char,
605 to ensure that the values are within the correct range. The result
606 should then be cast to int to avoid warnings from some compilers.
607 We do indeed get warning "array subscript has type 'char'" without
609 if (toupper((int)(unsigned char)hostname[0]) ==
610 toupper((int)(unsigned char)match[0]))
611 return match_hostname_elem(hostname + 1, helem_len - 1,
612 match + 1, melem_len - 1);
617 static int match_hostname(const char *hostname, const char *match)
620 const char *h_dot, *m_dot;
621 int helem_len, melem_len;
623 h_dot = strchr(hostname, '.');
624 m_dot = strchr(match, '.');
626 if (h_dot && m_dot) {
627 helem_len = h_dot - hostname + 1;
628 melem_len = m_dot - match + 1;
629 } else if (!h_dot && !m_dot) {
630 helem_len = strlen(hostname);
631 melem_len = strlen(match);
636 if (match_hostname_elem(hostname, helem_len,
640 hostname += helem_len;
649 /* cf. RFC2818 and RFC2459 */
650 static int match_cert_hostname(struct openconnect_info *vpninfo, X509 *peer_cert)
652 STACK_OF(GENERAL_NAME) *altnames;
654 ASN1_STRING *subjasn1;
655 char *subjstr = NULL;
658 char addrbuf[sizeof(struct in6_addr)];
661 /* Allow GEN_IP in the certificate only if we actually connected
662 by IP address rather than by name. */
663 if (inet_pton(AF_INET, vpninfo->hostname, addrbuf) > 0)
665 else if (inet_pton(AF_INET6, vpninfo->hostname, addrbuf) > 0)
667 else if (vpninfo->hostname[0] == '[' &&
668 vpninfo->hostname[strlen(vpninfo->hostname)-1] == ']') {
669 char *p = &vpninfo->hostname[strlen(vpninfo->hostname)-1];
671 if (inet_pton(AF_INET6, vpninfo->hostname + 1, addrbuf) > 0)
676 altnames = X509_get_ext_d2i(peer_cert, NID_subject_alt_name,
678 for (i = 0; i < sk_GENERAL_NAME_num(altnames); i++) {
679 const GENERAL_NAME *this = sk_GENERAL_NAME_value(altnames, i);
681 if (this->type == GEN_DNS) {
684 int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
690 /* We don't like names with embedded NUL */
691 if (strlen(str) != len)
694 if (!match_hostname(vpninfo->hostname, str)) {
695 vpn_progress(vpninfo, PRG_TRACE,
696 _("Matched DNS altname '%s'\n"),
698 GENERAL_NAMES_free(altnames);
702 vpn_progress(vpninfo, PRG_TRACE,
703 _("No match for altname '%s'\n"),
707 } else if (this->type == GEN_IPADD && addrlen) {
711 if (this->d.ip->length == 4) {
713 } else if (this->d.ip->length == 16) {
716 vpn_progress(vpninfo, PRG_ERR,
717 _("Certificate has GEN_IPADD altname with bogus length %d\n"),
722 /* We only do this for the debug messages */
723 inet_ntop(family, this->d.ip->data, host, sizeof(host));
725 if (this->d.ip->length == addrlen &&
726 !memcmp(addrbuf, this->d.ip->data, addrlen)) {
727 vpn_progress(vpninfo, PRG_TRACE,
728 _("Matched %s address '%s'\n"),
729 (family == AF_INET6)?"IPv6":"IPv4",
731 GENERAL_NAMES_free(altnames);
734 vpn_progress(vpninfo, PRG_TRACE,
735 _("No match for %s address '%s'\n"),
736 (family == AF_INET6)?"IPv6":"IPv4",
739 } else if (this->type == GEN_URI) {
741 char *url_proto, *url_host, *url_path, *url_host2;
743 int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
748 /* We don't like names with embedded NUL */
749 if (strlen(str) != len)
752 if (internal_parse_url(str, &url_proto, &url_host, &url_port, &url_path, 0)) {
757 if (!url_proto || strcasecmp(url_proto, "https"))
760 if (url_port != vpninfo->port)
763 /* Leave url_host as it was so that it can be freed */
764 url_host2 = url_host;
765 if (addrlen == 16 && vpninfo->hostname[0] != '[' &&
766 url_host[0] == '[' && url_host[strlen(url_host)-1] == ']') {
767 /* Cope with https://[IPv6]/ when the hostname is bare IPv6 */
768 url_host[strlen(url_host)-1] = 0;
772 if (strcasecmp(vpninfo->hostname, url_host2))
776 vpn_progress(vpninfo, PRG_TRACE,
777 _("URI '%s' has non-empty path; ignoring\n"),
779 goto no_uri_match_silent;
781 vpn_progress(vpninfo, PRG_TRACE,
782 _("Matched URI '%s'\n"),
788 GENERAL_NAMES_free(altnames);
792 vpn_progress(vpninfo, PRG_TRACE,
793 _("No match for URI '%s'\n"),
802 GENERAL_NAMES_free(altnames);
804 /* According to RFC2818, we don't use the legacy subject name if
805 there was an altname with DNS type. */
807 vpn_progress(vpninfo, PRG_ERR,
808 _("No altname in peer cert matched '%s'\n"),
813 subjname = X509_get_subject_name(peer_cert);
815 vpn_progress(vpninfo, PRG_ERR,
816 _("No subject name in peer cert!\n"));
820 /* Find the _last_ (most specific) commonName */
823 int j = X509_NAME_get_index_by_NID(subjname, NID_commonName, i);
830 subjasn1 = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subjname, i));
832 i = ASN1_STRING_to_UTF8((void *)&subjstr, subjasn1);
834 if (!subjstr || strlen(subjstr) != i) {
835 vpn_progress(vpninfo, PRG_ERR,
836 _("Failed to parse subject name in peer cert\n"));
841 if (match_hostname(vpninfo->hostname, subjstr)) {
842 vpn_progress(vpninfo, PRG_ERR,
843 _("Peer cert subject mismatch ('%s' != '%s')\n"),
844 subjstr, vpninfo->hostname);
847 vpn_progress(vpninfo, PRG_TRACE,
848 _("Matched peer certificate subject name '%s'\n"),
852 OPENSSL_free(subjstr);
856 static int verify_peer(struct openconnect_info *vpninfo, SSL *https_ssl)
861 peer_cert = SSL_get_peer_certificate(https_ssl);
863 if (vpninfo->servercert) {
864 /* If given a cert fingerprint on the command line, that's
866 ret = check_server_cert(vpninfo, peer_cert);
868 int vfy = SSL_get_verify_result(https_ssl);
869 const char *err_string = NULL;
871 if (vfy != X509_V_OK)
872 err_string = X509_verify_cert_error_string(vfy);
873 else if (match_cert_hostname(vpninfo, peer_cert))
874 err_string = _("certificate does not match hostname");
877 vpn_progress(vpninfo, PRG_INFO,
878 _("Server certificate verify failed: %s\n"),
881 if (vpninfo->validate_peer_cert)
882 ret = vpninfo->validate_peer_cert(vpninfo->cbdata,
891 X509_free(peer_cert);
896 static void workaround_openssl_certchain_bug(struct openconnect_info *vpninfo,
899 /* OpenSSL has problems with certificate chains -- if there are
900 multiple certs with the same name, it doesn't necessarily
901 choose the _right_ one. (RT#1942)
902 Pick the right ones for ourselves and add them manually. */
903 X509 *cert = SSL_get_certificate(ssl);
905 X509_STORE *store = SSL_CTX_get_cert_store(vpninfo->https_ctx);
911 /* If we already have 'supporting' certs, don't add them again */
912 if (vpninfo->https_ctx->extra_certs)
915 if (!X509_STORE_CTX_init(&ctx, store, NULL, NULL))
918 while (ctx.get_issuer(&cert2, &ctx, cert) == 1) {
922 if (X509_check_issued(cert2, cert2) == X509_V_OK)
925 X509_NAME_oneline(X509_get_subject_name(cert),
927 vpn_progress(vpninfo, PRG_DEBUG,
928 _("Extra cert from cafile: '%s'\n"), buf);
929 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert);
931 X509_STORE_CTX_cleanup(&ctx);
934 #if OPENSSL_VERSION_NUMBER >= 0x00908000
935 static int ssl_app_verify_callback(X509_STORE_CTX *ctx, void *arg)
937 /* We've seen certificates in the wild which don't have the
938 purpose fields filled in correctly */
939 X509_VERIFY_PARAM_set_purpose(ctx->param, X509_PURPOSE_ANY);
940 return X509_verify_cert(ctx);
944 static int check_certificate_expiry(struct openconnect_info *vpninfo)
947 const char *reason = NULL;
951 if (!vpninfo->cert_x509)
955 notAfter = X509_get_notAfter(vpninfo->cert_x509);
956 i = X509_cmp_time(notAfter, &t);
958 vpn_progress(vpninfo, PRG_ERR,
959 _("Error in client cert notAfter field\n"));
962 reason = _("Client certificate has expired at");
964 t += vpninfo->cert_expire_warning;
965 i = X509_cmp_time(notAfter, &t);
967 reason = _("Client certificate expires soon at");
971 BIO *bp = BIO_new(BIO_s_mem());
973 const char *expiry = _("<error>");
977 ASN1_TIME_print(bp, notAfter);
978 BIO_write(bp, &zero, 1);
979 BIO_get_mem_ptr(bp, &bm);
982 vpn_progress(vpninfo, PRG_ERR, "%s: %s\n", reason, expiry);
988 int openconnect_open_https(struct openconnect_info *vpninfo)
990 method_const SSL_METHOD *ssl3_method;
996 if (vpninfo->https_ssl)
999 if (vpninfo->peer_cert) {
1000 X509_free(vpninfo->peer_cert);
1001 vpninfo->peer_cert = NULL;
1004 ssl_sock = connect_https_socket(vpninfo);
1008 ssl3_method = TLSv1_client_method();
1009 if (!vpninfo->https_ctx) {
1010 vpninfo->https_ctx = SSL_CTX_new(ssl3_method);
1012 /* Some servers (or their firewalls) really don't like seeing
1014 #ifdef SSL_OP_NO_TICKET
1015 SSL_CTX_set_options (vpninfo->https_ctx, SSL_OP_NO_TICKET);
1018 if (vpninfo->cert) {
1019 err = load_certificate(vpninfo);
1021 vpn_progress(vpninfo, PRG_ERR,
1022 _("Loading certificate failed. Aborting.\n"));
1025 check_certificate_expiry(vpninfo);
1028 /* We just want to do:
1029 SSL_CTX_set_purpose(vpninfo->https_ctx, X509_PURPOSE_ANY);
1030 ... but it doesn't work with OpenSSL < 0.9.8k because of
1031 problems with inheritance (fixed in v1.1.4.6 of
1032 crypto/x509/x509_vpm.c) so we have to play silly buggers
1033 instead. This trick doesn't work _either_ in < 0.9.7 but
1034 I don't know of _any_ workaround which will, and can't
1035 be bothered to find out either. */
1036 #if OPENSSL_VERSION_NUMBER >= 0x00908000
1037 SSL_CTX_set_cert_verify_callback(vpninfo->https_ctx,
1038 ssl_app_verify_callback, NULL);
1040 SSL_CTX_set_default_verify_paths(vpninfo->https_ctx);
1042 if (vpninfo->cafile) {
1043 if (!SSL_CTX_load_verify_locations(vpninfo->https_ctx, vpninfo->cafile, NULL)) {
1044 vpn_progress(vpninfo, PRG_ERR,
1045 _("Failed to open CA file '%s'\n"),
1047 openconnect_report_ssl_errors(vpninfo);
1054 https_ssl = SSL_new(vpninfo->https_ctx);
1055 workaround_openssl_certchain_bug(vpninfo, https_ssl);
1057 https_bio = BIO_new_socket(ssl_sock, BIO_NOCLOSE);
1058 BIO_set_nbio(https_bio, 1);
1059 SSL_set_bio(https_ssl, https_bio, https_bio);
1061 vpn_progress(vpninfo, PRG_INFO, _("SSL negotiation with %s\n"),
1064 while ((err = SSL_connect(https_ssl)) <= 0) {
1065 fd_set wr_set, rd_set;
1066 int maxfd = ssl_sock;
1071 err = SSL_get_error(https_ssl, err);
1072 if (err == SSL_ERROR_WANT_READ)
1073 FD_SET(ssl_sock, &rd_set);
1074 else if (err == SSL_ERROR_WANT_WRITE)
1075 FD_SET(ssl_sock, &wr_set);
1077 vpn_progress(vpninfo, PRG_ERR, _("SSL connection failure\n"));
1078 openconnect_report_ssl_errors(vpninfo);
1079 SSL_free(https_ssl);
1084 if (vpninfo->cancel_fd != -1) {
1085 FD_SET(vpninfo->cancel_fd, &rd_set);
1086 if (vpninfo->cancel_fd > ssl_sock)
1087 maxfd = vpninfo->cancel_fd;
1089 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
1090 if (vpninfo->cancel_fd != -1 &&
1091 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
1092 vpn_progress(vpninfo, PRG_ERR, _("SSL connection cancelled\n"));
1093 SSL_free(https_ssl);
1099 if (verify_peer(vpninfo, https_ssl)) {
1100 SSL_free(https_ssl);
1105 vpninfo->ssl_fd = ssl_sock;
1106 vpninfo->https_ssl = https_ssl;
1108 /* Stash this now, because it might not be available later if the
1109 server has disconnected. */
1110 vpninfo->peer_cert = SSL_get_peer_certificate(vpninfo->https_ssl);
1112 vpn_progress(vpninfo, PRG_INFO, _("Connected to HTTPS on %s\n"),
1118 void openconnect_close_https(struct openconnect_info *vpninfo)
1120 if (vpninfo->peer_cert) {
1121 X509_free(vpninfo->peer_cert);
1122 vpninfo->peer_cert = NULL;
1124 if (vpninfo->https_ssl) {
1125 SSL_free(vpninfo->https_ssl);
1126 vpninfo->https_ssl = NULL;
1128 if (vpninfo->ssl_fd != -1) {
1129 close(vpninfo->ssl_fd);
1130 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds);
1131 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
1132 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds);
1133 vpninfo->ssl_fd = -1;
1137 void openconnect_init_openssl(void)
1139 SSL_library_init ();
1141 SSL_load_error_strings ();
1142 OpenSSL_add_all_algorithms ();
1145 char *openconnect_get_cert_details(struct openconnect_info *vpninfo,
1146 struct x509_st *cert)
1148 BIO *bp = BIO_new(BIO_s_mem());
1153 X509_print_ex(bp, cert, 0, 0);
1154 BIO_write(bp, &zero, 1);
1155 BIO_get_mem_ptr(bp, &certinfo);
1157 ret = strdup(certinfo->data);
1163 int openconnect_local_cert_md5(struct openconnect_info *vpninfo,
1168 if (!vpninfo->cert_x509)
1171 if (get_cert_md5_fingerprint(vpninfo, vpninfo->cert_x509, buf))