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>
29 #include <openssl/ssl.h>
30 #include <openssl/err.h>
31 #include <openssl/engine.h>
32 #include <openssl/evp.h>
33 #include <openssl/rand.h>
34 #include <openssl/pkcs12.h>
35 #include <openssl/x509v3.h>
36 #include <openssl/x509.h>
37 #include <openssl/bio.h>
39 #include "openconnect-internal.h"
41 int openconnect_sha1(unsigned char *result, void *data, int len)
46 EVP_Digest(data, len, result, NULL, EVP_sha1(), NULL);
47 EVP_MD_CTX_cleanup(&c);
52 int openconnect_get_cert_DER(struct openconnect_info *vpninfo,
53 struct x509_st *cert, unsigned char **buf)
55 BIO *bp = BIO_new(BIO_s_mem());
59 if (!i2d_X509_bio(bp, cert)) {
64 BIO_get_mem_ptr(bp, &certinfo);
71 memcpy(*buf, certinfo->data, l);
76 int openconnect_random(void *bytes, int len)
78 if (RAND_bytes(bytes, len) != 1)
83 /* Helper functions for reading/writing lines over SSL.
84 We could use cURL for the HTTP stuff, but it's overkill */
86 int openconnect_SSL_write(struct openconnect_info *vpninfo, char *buf, size_t len)
88 size_t orig_len = len;
91 int done = SSL_write(vpninfo->https_ssl, buf, len);
96 int err = SSL_get_error(vpninfo->https_ssl, done);
97 fd_set wr_set, rd_set;
98 int maxfd = vpninfo->ssl_fd;
103 if (err == SSL_ERROR_WANT_READ)
104 FD_SET(vpninfo->ssl_fd, &rd_set);
105 else if (err == SSL_ERROR_WANT_WRITE)
106 FD_SET(vpninfo->ssl_fd, &wr_set);
108 vpn_progress(vpninfo, PRG_ERR, _("Failed to write to SSL socket"));
109 openconnect_report_ssl_errors(vpninfo);
112 if (vpninfo->cancel_fd != -1) {
113 FD_SET(vpninfo->cancel_fd, &rd_set);
114 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
115 maxfd = vpninfo->cancel_fd;
117 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
118 if (vpninfo->cancel_fd != -1 &&
119 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
120 vpn_progress(vpninfo, PRG_ERR, _("SSL write cancelled\n"));
128 int openconnect_SSL_read(struct openconnect_info *vpninfo, char *buf, size_t len)
132 while ((done = SSL_read(vpninfo->https_ssl, buf, len)) == -1) {
133 int err = SSL_get_error(vpninfo->https_ssl, done);
134 fd_set wr_set, rd_set;
135 int maxfd = vpninfo->ssl_fd;
140 if (err == SSL_ERROR_WANT_READ)
141 FD_SET(vpninfo->ssl_fd, &rd_set);
142 else if (err == SSL_ERROR_WANT_WRITE)
143 FD_SET(vpninfo->ssl_fd, &wr_set);
145 vpn_progress(vpninfo, PRG_ERR, _("Failed to read from SSL socket"));
146 openconnect_report_ssl_errors(vpninfo);
149 if (vpninfo->cancel_fd != -1) {
150 FD_SET(vpninfo->cancel_fd, &rd_set);
151 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
152 maxfd = vpninfo->cancel_fd;
154 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
155 if (vpninfo->cancel_fd != -1 &&
156 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
157 vpn_progress(vpninfo, PRG_ERR, _("SSL read cancelled\n"));
164 int __attribute__ ((format (printf, 2, 3)))
165 openconnect_SSL_printf(struct openconnect_info *vpninfo, const char *fmt, ...)
173 vsnprintf(buf, 1023, fmt, args);
175 return openconnect_SSL_write(vpninfo, buf, strlen(buf));
179 static int print_err(const char *str, size_t len, void *ptr)
181 struct openconnect_info *vpninfo = ptr;
183 vpn_progress(vpninfo, PRG_ERR, "%s", str);
187 void openconnect_report_ssl_errors(struct openconnect_info *vpninfo)
189 ERR_print_errors_cb(print_err, vpninfo);
192 int openconnect_SSL_gets(struct openconnect_info *vpninfo, char *buf, size_t len)
201 ret = SSL_read(vpninfo->https_ssl, buf + i, 1);
203 if (buf[i] == '\n') {
205 if (i && buf[i-1] == '\r') {
218 fd_set rd_set, wr_set;
219 int maxfd = vpninfo->ssl_fd;
224 ret = SSL_get_error(vpninfo->https_ssl, ret);
225 if (ret == SSL_ERROR_WANT_READ)
226 FD_SET(vpninfo->ssl_fd, &rd_set);
227 else if (ret == SSL_ERROR_WANT_WRITE)
228 FD_SET(vpninfo->ssl_fd, &wr_set);
230 vpn_progress(vpninfo, PRG_ERR, _("Failed to read from SSL socket\n"));
231 openconnect_report_ssl_errors(vpninfo);
235 if (vpninfo->cancel_fd != -1) {
236 FD_SET(vpninfo->cancel_fd, &rd_set);
237 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
238 maxfd = vpninfo->cancel_fd;
240 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
241 if (vpninfo->cancel_fd != -1 &&
242 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
243 vpn_progress(vpninfo, PRG_ERR, _("SSL read cancelled\n"));
253 static int pem_pw_cb(char *buf, int len, int w, void *v)
255 struct openconnect_info *vpninfo = v;
257 /* Only try the provided password once... */
258 SSL_CTX_set_default_passwd_cb(vpninfo->https_ctx, NULL);
259 SSL_CTX_set_default_passwd_cb_userdata(vpninfo->https_ctx, NULL);
261 if (len <= strlen(vpninfo->cert_password)) {
262 vpn_progress(vpninfo, PRG_ERR,
263 _("PEM password too long (%zd >= %d)\n"),
264 strlen(vpninfo->cert_password), len);
267 strcpy(buf, vpninfo->cert_password);
268 return strlen(vpninfo->cert_password);
271 static int load_pkcs12_certificate(struct openconnect_info *vpninfo, PKCS12 *p12)
273 EVP_PKEY *pkey = NULL;
277 char pass[PEM_BUFSIZE];
280 /* We do this every time round the loop, to work around a bug in
281 OpenSSL < 1.0.0-beta2 -- where the stack at *ca will be freed
282 when PKCS12_parse() returns an error, but *ca is left pointing
283 to the freed memory. */
285 if (!vpninfo->cert_password) {
286 if (EVP_read_pw_string(pass, PEM_BUFSIZE,
287 "Enter PKCS#12 pass phrase:", 0))
290 if (!PKCS12_parse(p12, vpninfo->cert_password?:pass, &pkey, &cert, &ca)) {
291 unsigned long err = ERR_peek_error();
293 openconnect_report_ssl_errors(vpninfo);
295 if (ERR_GET_LIB(err) == ERR_LIB_PKCS12 &&
296 ERR_GET_FUNC(err) == PKCS12_F_PKCS12_PARSE &&
297 ERR_GET_REASON(err) == PKCS12_R_MAC_VERIFY_FAILURE) {
298 vpn_progress(vpninfo, PRG_ERR,
299 _("Parse PKCS#12 failed (wrong passphrase?)\n"));
300 vpninfo->cert_password = NULL;
304 vpn_progress(vpninfo, PRG_ERR,
305 _("Parse PKCS#12 failed (see above errors)\n"));
310 vpninfo->cert_x509 = cert;
311 SSL_CTX_use_certificate(vpninfo->https_ctx, cert);
313 vpn_progress(vpninfo, PRG_ERR,
314 _("PKCS#12 contained no certificate!"));
319 SSL_CTX_use_PrivateKey(vpninfo->https_ctx, pkey);
322 vpn_progress(vpninfo, PRG_ERR,
323 _("PKCS#12 contained no private key!"));
327 /* Only include supporting certificates which are actually necessary */
331 for (i = 0; i < sk_X509_num(ca); i++) {
332 X509 *cert2 = sk_X509_value(ca, i);
333 if (X509_check_issued(cert2, cert) == X509_V_OK) {
339 X509_NAME_oneline(X509_get_subject_name(cert2),
341 vpn_progress(vpninfo, PRG_DEBUG,
342 _("Extra cert from PKCS#12: '%s'\n"), buf);
343 CRYPTO_add(&cert2->references, 1, CRYPTO_LOCK_X509);
344 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert2);
349 sk_X509_pop_free(ca, X509_free);
357 static int load_tpm_certificate(struct openconnect_info *vpninfo)
361 ENGINE_load_builtin_engines();
363 e = ENGINE_by_id("tpm");
365 vpn_progress(vpninfo, PRG_ERR, _("Can't load TPM engine.\n"));
366 openconnect_report_ssl_errors(vpninfo);
369 if (!ENGINE_init(e) || !ENGINE_set_default_RSA(e) ||
370 !ENGINE_set_default_RAND(e)) {
371 vpn_progress(vpninfo, PRG_ERR, _("Failed to init TPM engine\n"));
372 openconnect_report_ssl_errors(vpninfo);
377 if (vpninfo->cert_password) {
378 if (!ENGINE_ctrl_cmd(e, "PIN", strlen(vpninfo->cert_password),
379 vpninfo->cert_password, NULL, 0)) {
380 vpn_progress(vpninfo, PRG_ERR,
381 _("Failed to set TPM SRK password\n"));
382 openconnect_report_ssl_errors(vpninfo);
385 key = ENGINE_load_private_key(e, vpninfo->sslkey, NULL, NULL);
387 vpn_progress(vpninfo, PRG_ERR,
388 _("Failed to load TPM private key\n"));
389 openconnect_report_ssl_errors(vpninfo);
394 if (!SSL_CTX_use_PrivateKey(vpninfo->https_ctx, key)) {
395 vpn_progress(vpninfo, PRG_ERR, _("Add key from TPM failed\n"));
396 openconnect_report_ssl_errors(vpninfo);
404 static int load_tpm_certificate(struct openconnect_info *vpninfo)
406 vpn_progress(vpninfo, PRG_ERR,
407 _("This version of OpenConnect was built without TPM support\n"));
412 static int reload_pem_cert(struct openconnect_info *vpninfo)
414 BIO *b = BIO_new(BIO_s_file_internal());
419 if (BIO_read_filename(b, vpninfo->cert) <= 0) {
422 vpn_progress(vpninfo, PRG_ERR,
423 _("Failed to reload X509 cert for expiry check\n"));
424 openconnect_report_ssl_errors(vpninfo);
427 vpninfo->cert_x509 = PEM_read_bio_X509_AUX(b, NULL, NULL, NULL);
428 if (!vpninfo->cert_x509)
434 static int load_certificate(struct openconnect_info *vpninfo)
436 vpn_progress(vpninfo, PRG_TRACE,
437 _("Using certificate file %s\n"), vpninfo->cert);
439 if (vpninfo->cert_type == CERT_TYPE_PKCS12 ||
440 vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
444 f = fopen(vpninfo->cert, "r");
446 vpn_progress(vpninfo, PRG_ERR,
447 _("Failed to open certificate file %s: %s\n"),
448 vpninfo->cert, strerror(errno));
451 p12 = d2i_PKCS12_fp(f, NULL);
454 return load_pkcs12_certificate(vpninfo, p12);
457 if (vpninfo->cert_type == CERT_TYPE_PKCS12) {
458 vpn_progress(vpninfo, PRG_ERR, _("Read PKCS#12 failed\n"));
459 openconnect_report_ssl_errors(vpninfo);
462 /* Clear error and fall through to see if it's a PEM file... */
466 /* It's PEM or TPM now, and either way we need to load the plain cert: */
467 if (!SSL_CTX_use_certificate_chain_file(vpninfo->https_ctx,
469 vpn_progress(vpninfo, PRG_ERR,
470 _("Loading certificate failed\n"));
471 openconnect_report_ssl_errors(vpninfo);
475 /* Ew, we can't get it back from the OpenSSL CTX in any sane fashion */
476 reload_pem_cert(vpninfo);
478 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
479 FILE *f = fopen(vpninfo->sslkey, "r");
483 vpn_progress(vpninfo, PRG_ERR,
484 _("Failed to open private key file %s: %s\n"),
485 vpninfo->cert, strerror(errno));
490 while (fgets(buf, 255, f)) {
491 if (!strcmp(buf, "-----BEGIN TSS KEY BLOB-----\n")) {
492 vpninfo->cert_type = CERT_TYPE_TPM;
494 } else if (!strcmp(buf, "-----BEGIN RSA PRIVATE KEY-----\n") ||
495 !strcmp(buf, "-----BEGIN DSA PRIVATE KEY-----\n") ||
496 !strcmp(buf, "-----BEGIN ENCRYPTED PRIVATE KEY-----\n")) {
497 vpninfo->cert_type = CERT_TYPE_PEM;
502 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
503 vpn_progress(vpninfo, PRG_ERR,
504 _("Failed to identify private key type in '%s'\n"),
510 if (vpninfo->cert_type == CERT_TYPE_TPM)
511 return load_tpm_certificate(vpninfo);
513 /* Standard PEM certificate */
514 if (vpninfo->cert_password) {
515 SSL_CTX_set_default_passwd_cb(vpninfo->https_ctx,
517 SSL_CTX_set_default_passwd_cb_userdata(vpninfo->https_ctx,
521 if (!SSL_CTX_use_RSAPrivateKey_file(vpninfo->https_ctx, vpninfo->sslkey,
523 unsigned long err = ERR_peek_error();
525 openconnect_report_ssl_errors(vpninfo);
527 #ifndef EVP_F_EVP_DECRYPTFINAL_EX
528 #define EVP_F_EVP_DECRYPTFINAL_EX EVP_F_EVP_DECRYPTFINAL
530 /* If the user fat-fingered the passphrase, try again */
531 if (ERR_GET_LIB(err) == ERR_LIB_EVP &&
532 ERR_GET_FUNC(err) == EVP_F_EVP_DECRYPTFINAL_EX &&
533 ERR_GET_REASON(err) == EVP_R_BAD_DECRYPT) {
534 vpn_progress(vpninfo, PRG_ERR,
535 _("Loading private key failed (wrong passphrase?)\n"));
539 vpn_progress(vpninfo, PRG_ERR,
540 _("Loading private key failed (see above errors)\n"));
546 static int get_cert_fingerprint(struct openconnect_info *vpninfo,
547 X509 *cert, const EVP_MD *type,
550 unsigned char md[EVP_MAX_MD_SIZE];
553 if (!X509_digest(cert, type, md, &n))
556 for (i=0; i < n; i++)
557 sprintf(&buf[i*2], "%02X", md[i]);
562 int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
563 X509 *cert, char *buf)
565 return get_cert_fingerprint(vpninfo, cert, EVP_md5(), buf);
568 int openconnect_get_cert_sha1(struct openconnect_info *vpninfo,
569 X509 *cert, char *buf)
571 return get_cert_fingerprint(vpninfo, cert, EVP_sha1(), buf);
574 static int check_server_cert(struct openconnect_info *vpninfo, X509 *cert)
576 char fingerprint[EVP_MAX_MD_SIZE * 2 + 1];
579 ret = openconnect_get_cert_sha1(vpninfo, cert, fingerprint);
583 if (strcasecmp(vpninfo->servercert, fingerprint)) {
584 vpn_progress(vpninfo, PRG_ERR,
585 _("Server SSL certificate didn't match: %s\n"), fingerprint);
591 static int match_hostname_elem(const char *hostname, int helem_len,
592 const char *match, int melem_len)
594 if (!helem_len && !melem_len)
597 if (!helem_len || !melem_len)
601 if (match[0] == '*') {
604 for (i = 1 ; i <= helem_len; i++) {
605 if (!match_hostname_elem(hostname + i, helem_len - i,
606 match + 1, melem_len - 1))
612 /* From the NetBSD (5.1) man page for ctype(3):
613 Values of type char or signed char must first be cast to unsigned char,
614 to ensure that the values are within the correct range. The result
615 should then be cast to int to avoid warnings from some compilers.
616 We do indeed get warning "array subscript has type 'char'" without
618 if (toupper((int)(unsigned char)hostname[0]) ==
619 toupper((int)(unsigned char)match[0]))
620 return match_hostname_elem(hostname + 1, helem_len - 1,
621 match + 1, melem_len - 1);
626 static int match_hostname(const char *hostname, const char *match)
629 const char *h_dot, *m_dot;
630 int helem_len, melem_len;
632 h_dot = strchr(hostname, '.');
633 m_dot = strchr(match, '.');
635 if (h_dot && m_dot) {
636 helem_len = h_dot - hostname + 1;
637 melem_len = m_dot - match + 1;
638 } else if (!h_dot && !m_dot) {
639 helem_len = strlen(hostname);
640 melem_len = strlen(match);
645 if (match_hostname_elem(hostname, helem_len,
649 hostname += helem_len;
658 /* cf. RFC2818 and RFC2459 */
659 static int match_cert_hostname(struct openconnect_info *vpninfo, X509 *peer_cert)
661 STACK_OF(GENERAL_NAME) *altnames;
663 ASN1_STRING *subjasn1;
664 char *subjstr = NULL;
667 char addrbuf[sizeof(struct in6_addr)];
670 /* Allow GEN_IP in the certificate only if we actually connected
671 by IP address rather than by name. */
672 if (inet_pton(AF_INET, vpninfo->hostname, addrbuf) > 0)
674 else if (inet_pton(AF_INET6, vpninfo->hostname, addrbuf) > 0)
676 else if (vpninfo->hostname[0] == '[' &&
677 vpninfo->hostname[strlen(vpninfo->hostname)-1] == ']') {
678 char *p = &vpninfo->hostname[strlen(vpninfo->hostname)-1];
680 if (inet_pton(AF_INET6, vpninfo->hostname + 1, addrbuf) > 0)
685 altnames = X509_get_ext_d2i(peer_cert, NID_subject_alt_name,
687 for (i = 0; i < sk_GENERAL_NAME_num(altnames); i++) {
688 const GENERAL_NAME *this = sk_GENERAL_NAME_value(altnames, i);
690 if (this->type == GEN_DNS) {
693 int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
699 /* We don't like names with embedded NUL */
700 if (strlen(str) != len)
703 if (!match_hostname(vpninfo->hostname, str)) {
704 vpn_progress(vpninfo, PRG_TRACE,
705 _("Matched DNS altname '%s'\n"),
707 GENERAL_NAMES_free(altnames);
711 vpn_progress(vpninfo, PRG_TRACE,
712 _("No match for altname '%s'\n"),
716 } else if (this->type == GEN_IPADD && addrlen) {
720 if (this->d.ip->length == 4) {
722 } else if (this->d.ip->length == 16) {
725 vpn_progress(vpninfo, PRG_ERR,
726 _("Certificate has GEN_IPADD altname with bogus length %d\n"),
731 /* We only do this for the debug messages */
732 inet_ntop(family, this->d.ip->data, host, sizeof(host));
734 if (this->d.ip->length == addrlen &&
735 !memcmp(addrbuf, this->d.ip->data, addrlen)) {
736 vpn_progress(vpninfo, PRG_TRACE,
737 _("Matched %s address '%s'\n"),
738 (family == AF_INET6)?"IPv6":"IPv4",
740 GENERAL_NAMES_free(altnames);
743 vpn_progress(vpninfo, PRG_TRACE,
744 _("No match for %s address '%s'\n"),
745 (family == AF_INET6)?"IPv6":"IPv4",
748 } else if (this->type == GEN_URI) {
750 char *url_proto, *url_host, *url_path, *url_host2;
752 int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
757 /* We don't like names with embedded NUL */
758 if (strlen(str) != len)
761 if (internal_parse_url(str, &url_proto, &url_host, &url_port, &url_path, 0)) {
766 if (!url_proto || strcasecmp(url_proto, "https"))
769 if (url_port != vpninfo->port)
772 /* Leave url_host as it was so that it can be freed */
773 url_host2 = url_host;
774 if (addrlen == 16 && vpninfo->hostname[0] != '[' &&
775 url_host[0] == '[' && url_host[strlen(url_host)-1] == ']') {
776 /* Cope with https://[IPv6]/ when the hostname is bare IPv6 */
777 url_host[strlen(url_host)-1] = 0;
781 if (strcasecmp(vpninfo->hostname, url_host2))
785 vpn_progress(vpninfo, PRG_TRACE,
786 _("URI '%s' has non-empty path; ignoring\n"),
788 goto no_uri_match_silent;
790 vpn_progress(vpninfo, PRG_TRACE,
791 _("Matched URI '%s'\n"),
797 GENERAL_NAMES_free(altnames);
801 vpn_progress(vpninfo, PRG_TRACE,
802 _("No match for URI '%s'\n"),
811 GENERAL_NAMES_free(altnames);
813 /* According to RFC2818, we don't use the legacy subject name if
814 there was an altname with DNS type. */
816 vpn_progress(vpninfo, PRG_ERR,
817 _("No altname in peer cert matched '%s'\n"),
822 subjname = X509_get_subject_name(peer_cert);
824 vpn_progress(vpninfo, PRG_ERR,
825 _("No subject name in peer cert!\n"));
829 /* Find the _last_ (most specific) commonName */
832 int j = X509_NAME_get_index_by_NID(subjname, NID_commonName, i);
839 subjasn1 = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subjname, i));
841 i = ASN1_STRING_to_UTF8((void *)&subjstr, subjasn1);
843 if (!subjstr || strlen(subjstr) != i) {
844 vpn_progress(vpninfo, PRG_ERR,
845 _("Failed to parse subject name in peer cert\n"));
850 if (match_hostname(vpninfo->hostname, subjstr)) {
851 vpn_progress(vpninfo, PRG_ERR,
852 _("Peer cert subject mismatch ('%s' != '%s')\n"),
853 subjstr, vpninfo->hostname);
856 vpn_progress(vpninfo, PRG_TRACE,
857 _("Matched peer certificate subject name '%s'\n"),
861 OPENSSL_free(subjstr);
865 static int verify_peer(struct openconnect_info *vpninfo, SSL *https_ssl)
870 peer_cert = SSL_get_peer_certificate(https_ssl);
872 if (vpninfo->servercert) {
873 /* If given a cert fingerprint on the command line, that's
875 ret = check_server_cert(vpninfo, peer_cert);
877 int vfy = SSL_get_verify_result(https_ssl);
878 const char *err_string = NULL;
880 if (vfy != X509_V_OK)
881 err_string = X509_verify_cert_error_string(vfy);
882 else if (match_cert_hostname(vpninfo, peer_cert))
883 err_string = _("certificate does not match hostname");
886 vpn_progress(vpninfo, PRG_INFO,
887 _("Server certificate verify failed: %s\n"),
890 if (vpninfo->validate_peer_cert)
891 ret = vpninfo->validate_peer_cert(vpninfo->cbdata,
900 X509_free(peer_cert);
905 static void workaround_openssl_certchain_bug(struct openconnect_info *vpninfo,
908 /* OpenSSL has problems with certificate chains -- if there are
909 multiple certs with the same name, it doesn't necessarily
910 choose the _right_ one. (RT#1942)
911 Pick the right ones for ourselves and add them manually. */
912 X509 *cert = SSL_get_certificate(ssl);
914 X509_STORE *store = SSL_CTX_get_cert_store(vpninfo->https_ctx);
920 /* If we already have 'supporting' certs, don't add them again */
921 if (vpninfo->https_ctx->extra_certs)
924 if (!X509_STORE_CTX_init(&ctx, store, NULL, NULL))
927 while (ctx.get_issuer(&cert2, &ctx, cert) == 1) {
932 X509_NAME_oneline(X509_get_subject_name(cert),
934 vpn_progress(vpninfo, PRG_DEBUG,
935 _("Extra cert from cafile: '%s'\n"), buf);
936 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert);
938 X509_STORE_CTX_cleanup(&ctx);
941 #if OPENSSL_VERSION_NUMBER >= 0x00908000
942 static int ssl_app_verify_callback(X509_STORE_CTX *ctx, void *arg)
944 /* We've seen certificates in the wild which don't have the
945 purpose fields filled in correctly */
946 X509_VERIFY_PARAM_set_purpose(ctx->param, X509_PURPOSE_ANY);
947 return X509_verify_cert(ctx);
951 static int check_certificate_expiry(struct openconnect_info *vpninfo)
954 const char *reason = NULL;
958 if (!vpninfo->cert_x509)
962 notAfter = X509_get_notAfter(vpninfo->cert_x509);
963 i = X509_cmp_time(notAfter, &t);
965 vpn_progress(vpninfo, PRG_ERR,
966 _("Error in client cert notAfter field\n"));
969 reason = _("Client certificate has expired at");
971 t += vpninfo->cert_expire_warning;
972 i = X509_cmp_time(notAfter, &t);
974 reason = _("Client certificate expires soon at");
978 BIO *bp = BIO_new(BIO_s_mem());
980 const char *expiry = _("<error>");
984 ASN1_TIME_print(bp, notAfter);
985 BIO_write(bp, &zero, 1);
986 BIO_get_mem_ptr(bp, &bm);
989 vpn_progress(vpninfo, PRG_ERR, "%s: %s\n", reason, expiry);
995 int openconnect_open_https(struct openconnect_info *vpninfo)
997 method_const SSL_METHOD *ssl3_method;
1003 if (vpninfo->https_ssl)
1006 if (vpninfo->peer_cert) {
1007 X509_free(vpninfo->peer_cert);
1008 vpninfo->peer_cert = NULL;
1011 ssl_sock = connect_https_socket(vpninfo);
1015 ssl3_method = TLSv1_client_method();
1016 if (!vpninfo->https_ctx) {
1017 vpninfo->https_ctx = SSL_CTX_new(ssl3_method);
1019 /* Some servers (or their firewalls) really don't like seeing
1021 #ifdef SSL_OP_NO_TICKET
1022 SSL_CTX_set_options (vpninfo->https_ctx, SSL_OP_NO_TICKET);
1025 if (vpninfo->cert) {
1026 err = load_certificate(vpninfo);
1028 vpn_progress(vpninfo, PRG_ERR,
1029 _("Loading certificate failed. Aborting.\n"));
1032 check_certificate_expiry(vpninfo);
1035 /* We just want to do:
1036 SSL_CTX_set_purpose(vpninfo->https_ctx, X509_PURPOSE_ANY);
1037 ... but it doesn't work with OpenSSL < 0.9.8k because of
1038 problems with inheritance (fixed in v1.1.4.6 of
1039 crypto/x509/x509_vpm.c) so we have to play silly buggers
1040 instead. This trick doesn't work _either_ in < 0.9.7 but
1041 I don't know of _any_ workaround which will, and can't
1042 be bothered to find out either. */
1043 #if OPENSSL_VERSION_NUMBER >= 0x00908000
1044 SSL_CTX_set_cert_verify_callback(vpninfo->https_ctx,
1045 ssl_app_verify_callback, NULL);
1047 SSL_CTX_set_default_verify_paths(vpninfo->https_ctx);
1049 if (vpninfo->cafile) {
1050 if (!SSL_CTX_load_verify_locations(vpninfo->https_ctx, vpninfo->cafile, NULL)) {
1051 vpn_progress(vpninfo, PRG_ERR,
1052 _("Failed to open CA file '%s'\n"),
1054 openconnect_report_ssl_errors(vpninfo);
1061 https_ssl = SSL_new(vpninfo->https_ctx);
1062 workaround_openssl_certchain_bug(vpninfo, https_ssl);
1064 https_bio = BIO_new_socket(ssl_sock, BIO_NOCLOSE);
1065 BIO_set_nbio(https_bio, 1);
1066 SSL_set_bio(https_ssl, https_bio, https_bio);
1068 vpn_progress(vpninfo, PRG_INFO, _("SSL negotiation with %s\n"),
1071 while ((err = SSL_connect(https_ssl)) <= 0) {
1072 fd_set wr_set, rd_set;
1073 int maxfd = ssl_sock;
1078 err = SSL_get_error(https_ssl, err);
1079 if (err == SSL_ERROR_WANT_READ)
1080 FD_SET(ssl_sock, &rd_set);
1081 else if (err == SSL_ERROR_WANT_WRITE)
1082 FD_SET(ssl_sock, &wr_set);
1084 vpn_progress(vpninfo, PRG_ERR, _("SSL connection failure\n"));
1085 openconnect_report_ssl_errors(vpninfo);
1086 SSL_free(https_ssl);
1091 if (vpninfo->cancel_fd != -1) {
1092 FD_SET(vpninfo->cancel_fd, &rd_set);
1093 if (vpninfo->cancel_fd > ssl_sock)
1094 maxfd = vpninfo->cancel_fd;
1096 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
1097 if (vpninfo->cancel_fd != -1 &&
1098 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
1099 vpn_progress(vpninfo, PRG_ERR, _("SSL connection cancelled\n"));
1100 SSL_free(https_ssl);
1106 if (verify_peer(vpninfo, https_ssl)) {
1107 SSL_free(https_ssl);
1112 vpninfo->ssl_fd = ssl_sock;
1113 vpninfo->https_ssl = https_ssl;
1115 /* Stash this now, because it might not be available later if the
1116 server has disconnected. */
1117 vpninfo->peer_cert = SSL_get_peer_certificate(vpninfo->https_ssl);
1119 vpn_progress(vpninfo, PRG_INFO, _("Connected to HTTPS on %s\n"),
1125 void openconnect_close_https(struct openconnect_info *vpninfo)
1127 if (vpninfo->peer_cert) {
1128 X509_free(vpninfo->peer_cert);
1129 vpninfo->peer_cert = NULL;
1131 if (vpninfo->https_ssl) {
1132 SSL_free(vpninfo->https_ssl);
1133 vpninfo->https_ssl = NULL;
1135 if (vpninfo->ssl_fd != -1) {
1136 close(vpninfo->ssl_fd);
1137 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds);
1138 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
1139 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds);
1140 vpninfo->ssl_fd = -1;
1144 void openconnect_init_openssl(void)
1146 SSL_library_init ();
1148 SSL_load_error_strings ();
1149 OpenSSL_add_all_algorithms ();
1152 char *openconnect_get_cert_details(struct openconnect_info *vpninfo,
1153 struct x509_st *cert)
1155 BIO *bp = BIO_new(BIO_s_mem());
1160 X509_print_ex(bp, cert, 0, 0);
1161 BIO_write(bp, &zero, 1);
1162 BIO_get_mem_ptr(bp, &certinfo);
1164 ret = strdup(certinfo->data);