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;
263 char pass[PEM_BUFSIZE];
266 /* We do this every time round the loop, to work around a bug in
267 OpenSSL < 1.0.0-beta2 -- where the stack at *ca will be freed
268 when PKCS12_parse() returns an error, but *ca is left pointing
269 to the freed memory. */
271 if (!vpninfo->cert_password) {
272 if (EVP_read_pw_string(pass, PEM_BUFSIZE,
273 "Enter PKCS#12 pass phrase:", 0))
276 if (!PKCS12_parse(p12, vpninfo->cert_password?:pass, &pkey, &cert, &ca)) {
277 unsigned long err = ERR_peek_error();
279 openconnect_report_ssl_errors(vpninfo);
281 if (ERR_GET_LIB(err) == ERR_LIB_PKCS12 &&
282 ERR_GET_FUNC(err) == PKCS12_F_PKCS12_PARSE &&
283 ERR_GET_REASON(err) == PKCS12_R_MAC_VERIFY_FAILURE) {
284 vpn_progress(vpninfo, PRG_ERR,
285 _("Parse PKCS#12 failed (wrong passphrase?)\n"));
286 vpninfo->cert_password = NULL;
290 vpn_progress(vpninfo, PRG_ERR,
291 _("Parse PKCS#12 failed (see above errors)\n"));
296 vpninfo->cert_x509 = cert;
297 SSL_CTX_use_certificate(vpninfo->https_ctx, cert);
299 vpn_progress(vpninfo, PRG_ERR,
300 _("PKCS#12 contained no certificate!"));
305 SSL_CTX_use_PrivateKey(vpninfo->https_ctx, pkey);
308 vpn_progress(vpninfo, PRG_ERR,
309 _("PKCS#12 contained no private key!"));
313 /* Only include supporting certificates which are actually necessary */
317 for (i = 0; i < sk_X509_num(ca); i++) {
318 X509 *cert2 = sk_X509_value(ca, i);
319 if (X509_check_issued(cert2, cert) == X509_V_OK) {
324 if (X509_check_issued(cert2, cert2) == X509_V_OK)
327 X509_NAME_oneline(X509_get_subject_name(cert2),
329 vpn_progress(vpninfo, PRG_DEBUG,
330 _("Extra cert from PKCS#12: '%s'\n"), buf);
331 CRYPTO_add(&cert2->references, 1, CRYPTO_LOCK_X509);
332 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert2);
337 sk_X509_pop_free(ca, X509_free);
345 static int load_tpm_certificate(struct openconnect_info *vpninfo)
349 ENGINE_load_builtin_engines();
351 e = ENGINE_by_id("tpm");
353 vpn_progress(vpninfo, PRG_ERR, _("Can't load TPM engine.\n"));
354 openconnect_report_ssl_errors(vpninfo);
357 if (!ENGINE_init(e) || !ENGINE_set_default_RSA(e) ||
358 !ENGINE_set_default_RAND(e)) {
359 vpn_progress(vpninfo, PRG_ERR, _("Failed to init TPM engine\n"));
360 openconnect_report_ssl_errors(vpninfo);
365 if (vpninfo->cert_password) {
366 if (!ENGINE_ctrl_cmd(e, "PIN", strlen(vpninfo->cert_password),
367 vpninfo->cert_password, NULL, 0)) {
368 vpn_progress(vpninfo, PRG_ERR,
369 _("Failed to set TPM SRK password\n"));
370 openconnect_report_ssl_errors(vpninfo);
373 key = ENGINE_load_private_key(e, vpninfo->sslkey, NULL, NULL);
375 vpn_progress(vpninfo, PRG_ERR,
376 _("Failed to load TPM private key\n"));
377 openconnect_report_ssl_errors(vpninfo);
382 if (!SSL_CTX_use_PrivateKey(vpninfo->https_ctx, key)) {
383 vpn_progress(vpninfo, PRG_ERR, _("Add key from TPM failed\n"));
384 openconnect_report_ssl_errors(vpninfo);
392 static int load_tpm_certificate(struct openconnect_info *vpninfo)
394 vpn_progress(vpninfo, PRG_ERR,
395 _("This version of OpenConnect was built without TPM support\n"));
400 static int reload_pem_cert(struct openconnect_info *vpninfo)
402 BIO *b = BIO_new(BIO_s_file_internal());
407 if (BIO_read_filename(b, vpninfo->cert) <= 0) {
410 vpn_progress(vpninfo, PRG_ERR,
411 _("Failed to reload X509 cert for expiry check\n"));
412 openconnect_report_ssl_errors(vpninfo);
415 vpninfo->cert_x509 = PEM_read_bio_X509_AUX(b, NULL, NULL, NULL);
416 if (!vpninfo->cert_x509)
422 static int load_certificate(struct openconnect_info *vpninfo)
424 vpn_progress(vpninfo, PRG_TRACE,
425 _("Using certificate file %s\n"), vpninfo->cert);
427 if (vpninfo->cert_type == CERT_TYPE_PKCS12 ||
428 vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
432 f = fopen(vpninfo->cert, "r");
434 vpn_progress(vpninfo, PRG_ERR,
435 _("Failed to open certificate file %s: %s\n"),
436 vpninfo->cert, strerror(errno));
439 p12 = d2i_PKCS12_fp(f, NULL);
442 return load_pkcs12_certificate(vpninfo, p12);
445 if (vpninfo->cert_type == CERT_TYPE_PKCS12) {
446 vpn_progress(vpninfo, PRG_ERR, _("Read PKCS#12 failed\n"));
447 openconnect_report_ssl_errors(vpninfo);
450 /* Clear error and fall through to see if it's a PEM file... */
454 /* It's PEM or TPM now, and either way we need to load the plain cert: */
455 if (!SSL_CTX_use_certificate_chain_file(vpninfo->https_ctx,
457 vpn_progress(vpninfo, PRG_ERR,
458 _("Loading certificate failed\n"));
459 openconnect_report_ssl_errors(vpninfo);
463 /* Ew, we can't get it back from the OpenSSL CTX in any sane fashion */
464 reload_pem_cert(vpninfo);
466 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
467 FILE *f = fopen(vpninfo->sslkey, "r");
471 vpn_progress(vpninfo, PRG_ERR,
472 _("Failed to open private key file %s: %s\n"),
473 vpninfo->cert, strerror(errno));
478 while (fgets(buf, 255, f)) {
479 if (!strcmp(buf, "-----BEGIN TSS KEY BLOB-----\n")) {
480 vpninfo->cert_type = CERT_TYPE_TPM;
482 } else if (!strcmp(buf, "-----BEGIN RSA PRIVATE KEY-----\n") ||
483 !strcmp(buf, "-----BEGIN DSA PRIVATE KEY-----\n") ||
484 !strcmp(buf, "-----BEGIN ENCRYPTED PRIVATE KEY-----\n")) {
485 vpninfo->cert_type = CERT_TYPE_PEM;
490 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
491 vpn_progress(vpninfo, PRG_ERR,
492 _("Failed to identify private key type in '%s'\n"),
498 if (vpninfo->cert_type == CERT_TYPE_TPM)
499 return load_tpm_certificate(vpninfo);
501 /* Standard PEM certificate */
502 if (vpninfo->cert_password) {
503 SSL_CTX_set_default_passwd_cb(vpninfo->https_ctx,
505 SSL_CTX_set_default_passwd_cb_userdata(vpninfo->https_ctx,
509 if (!SSL_CTX_use_RSAPrivateKey_file(vpninfo->https_ctx, vpninfo->sslkey,
511 unsigned long err = ERR_peek_error();
513 openconnect_report_ssl_errors(vpninfo);
515 #ifndef EVP_F_EVP_DECRYPTFINAL_EX
516 #define EVP_F_EVP_DECRYPTFINAL_EX EVP_F_EVP_DECRYPTFINAL
518 /* If the user fat-fingered the passphrase, try again */
519 if (ERR_GET_LIB(err) == ERR_LIB_EVP &&
520 ERR_GET_FUNC(err) == EVP_F_EVP_DECRYPTFINAL_EX &&
521 ERR_GET_REASON(err) == EVP_R_BAD_DECRYPT) {
522 vpn_progress(vpninfo, PRG_ERR,
523 _("Loading private key failed (wrong passphrase?)\n"));
527 vpn_progress(vpninfo, PRG_ERR,
528 _("Loading private key failed (see above errors)\n"));
534 static int get_cert_fingerprint(struct openconnect_info *vpninfo,
535 X509 *cert, const EVP_MD *type,
538 unsigned char md[EVP_MAX_MD_SIZE];
541 if (!X509_digest(cert, type, md, &n))
544 for (i=0; i < n; i++)
545 sprintf(&buf[i*2], "%02X", md[i]);
550 int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
551 X509 *cert, char *buf)
553 return get_cert_fingerprint(vpninfo, cert, EVP_md5(), buf);
556 int openconnect_get_cert_sha1(struct openconnect_info *vpninfo,
557 X509 *cert, char *buf)
559 return get_cert_fingerprint(vpninfo, cert, EVP_sha1(), buf);
562 static int check_server_cert(struct openconnect_info *vpninfo, X509 *cert)
564 char fingerprint[EVP_MAX_MD_SIZE * 2 + 1];
567 ret = openconnect_get_cert_sha1(vpninfo, cert, fingerprint);
571 if (strcasecmp(vpninfo->servercert, fingerprint)) {
572 vpn_progress(vpninfo, PRG_ERR,
573 _("Server SSL certificate didn't match: %s\n"), fingerprint);
579 static int match_hostname_elem(const char *hostname, int helem_len,
580 const char *match, int melem_len)
582 if (!helem_len && !melem_len)
585 if (!helem_len || !melem_len)
589 if (match[0] == '*') {
592 for (i = 1 ; i <= helem_len; i++) {
593 if (!match_hostname_elem(hostname + i, helem_len - i,
594 match + 1, melem_len - 1))
600 /* From the NetBSD (5.1) man page for ctype(3):
601 Values of type char or signed char must first be cast to unsigned char,
602 to ensure that the values are within the correct range. The result
603 should then be cast to int to avoid warnings from some compilers.
604 We do indeed get warning "array subscript has type 'char'" without
606 if (toupper((int)(unsigned char)hostname[0]) ==
607 toupper((int)(unsigned char)match[0]))
608 return match_hostname_elem(hostname + 1, helem_len - 1,
609 match + 1, melem_len - 1);
614 static int match_hostname(const char *hostname, const char *match)
617 const char *h_dot, *m_dot;
618 int helem_len, melem_len;
620 h_dot = strchr(hostname, '.');
621 m_dot = strchr(match, '.');
623 if (h_dot && m_dot) {
624 helem_len = h_dot - hostname + 1;
625 melem_len = m_dot - match + 1;
626 } else if (!h_dot && !m_dot) {
627 helem_len = strlen(hostname);
628 melem_len = strlen(match);
633 if (match_hostname_elem(hostname, helem_len,
637 hostname += helem_len;
646 /* cf. RFC2818 and RFC2459 */
647 static int match_cert_hostname(struct openconnect_info *vpninfo, X509 *peer_cert)
649 STACK_OF(GENERAL_NAME) *altnames;
651 ASN1_STRING *subjasn1;
652 char *subjstr = NULL;
655 char addrbuf[sizeof(struct in6_addr)];
658 /* Allow GEN_IP in the certificate only if we actually connected
659 by IP address rather than by name. */
660 if (inet_pton(AF_INET, vpninfo->hostname, addrbuf) > 0)
662 else if (inet_pton(AF_INET6, vpninfo->hostname, addrbuf) > 0)
664 else if (vpninfo->hostname[0] == '[' &&
665 vpninfo->hostname[strlen(vpninfo->hostname)-1] == ']') {
666 char *p = &vpninfo->hostname[strlen(vpninfo->hostname)-1];
668 if (inet_pton(AF_INET6, vpninfo->hostname + 1, addrbuf) > 0)
673 altnames = X509_get_ext_d2i(peer_cert, NID_subject_alt_name,
675 for (i = 0; i < sk_GENERAL_NAME_num(altnames); i++) {
676 const GENERAL_NAME *this = sk_GENERAL_NAME_value(altnames, i);
678 if (this->type == GEN_DNS) {
681 int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
687 /* We don't like names with embedded NUL */
688 if (strlen(str) != len)
691 if (!match_hostname(vpninfo->hostname, str)) {
692 vpn_progress(vpninfo, PRG_TRACE,
693 _("Matched DNS altname '%s'\n"),
695 GENERAL_NAMES_free(altnames);
699 vpn_progress(vpninfo, PRG_TRACE,
700 _("No match for altname '%s'\n"),
704 } else if (this->type == GEN_IPADD && addrlen) {
708 if (this->d.ip->length == 4) {
710 } else if (this->d.ip->length == 16) {
713 vpn_progress(vpninfo, PRG_ERR,
714 _("Certificate has GEN_IPADD altname with bogus length %d\n"),
719 /* We only do this for the debug messages */
720 inet_ntop(family, this->d.ip->data, host, sizeof(host));
722 if (this->d.ip->length == addrlen &&
723 !memcmp(addrbuf, this->d.ip->data, addrlen)) {
724 vpn_progress(vpninfo, PRG_TRACE,
725 _("Matched %s address '%s'\n"),
726 (family == AF_INET6)?"IPv6":"IPv4",
728 GENERAL_NAMES_free(altnames);
731 vpn_progress(vpninfo, PRG_TRACE,
732 _("No match for %s address '%s'\n"),
733 (family == AF_INET6)?"IPv6":"IPv4",
736 } else if (this->type == GEN_URI) {
738 char *url_proto, *url_host, *url_path, *url_host2;
740 int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
745 /* We don't like names with embedded NUL */
746 if (strlen(str) != len)
749 if (internal_parse_url(str, &url_proto, &url_host, &url_port, &url_path, 0)) {
754 if (!url_proto || strcasecmp(url_proto, "https"))
757 if (url_port != vpninfo->port)
760 /* Leave url_host as it was so that it can be freed */
761 url_host2 = url_host;
762 if (addrlen == 16 && vpninfo->hostname[0] != '[' &&
763 url_host[0] == '[' && url_host[strlen(url_host)-1] == ']') {
764 /* Cope with https://[IPv6]/ when the hostname is bare IPv6 */
765 url_host[strlen(url_host)-1] = 0;
769 if (strcasecmp(vpninfo->hostname, url_host2))
773 vpn_progress(vpninfo, PRG_TRACE,
774 _("URI '%s' has non-empty path; ignoring\n"),
776 goto no_uri_match_silent;
778 vpn_progress(vpninfo, PRG_TRACE,
779 _("Matched URI '%s'\n"),
785 GENERAL_NAMES_free(altnames);
789 vpn_progress(vpninfo, PRG_TRACE,
790 _("No match for URI '%s'\n"),
799 GENERAL_NAMES_free(altnames);
801 /* According to RFC2818, we don't use the legacy subject name if
802 there was an altname with DNS type. */
804 vpn_progress(vpninfo, PRG_ERR,
805 _("No altname in peer cert matched '%s'\n"),
810 subjname = X509_get_subject_name(peer_cert);
812 vpn_progress(vpninfo, PRG_ERR,
813 _("No subject name in peer cert!\n"));
817 /* Find the _last_ (most specific) commonName */
820 int j = X509_NAME_get_index_by_NID(subjname, NID_commonName, i);
827 subjasn1 = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subjname, i));
829 i = ASN1_STRING_to_UTF8((void *)&subjstr, subjasn1);
831 if (!subjstr || strlen(subjstr) != i) {
832 vpn_progress(vpninfo, PRG_ERR,
833 _("Failed to parse subject name in peer cert\n"));
838 if (match_hostname(vpninfo->hostname, subjstr)) {
839 vpn_progress(vpninfo, PRG_ERR,
840 _("Peer cert subject mismatch ('%s' != '%s')\n"),
841 subjstr, vpninfo->hostname);
844 vpn_progress(vpninfo, PRG_TRACE,
845 _("Matched peer certificate subject name '%s'\n"),
849 OPENSSL_free(subjstr);
853 static int verify_peer(struct openconnect_info *vpninfo, SSL *https_ssl)
858 peer_cert = SSL_get_peer_certificate(https_ssl);
860 if (vpninfo->servercert) {
861 /* If given a cert fingerprint on the command line, that's
863 ret = check_server_cert(vpninfo, peer_cert);
865 int vfy = SSL_get_verify_result(https_ssl);
866 const char *err_string = NULL;
868 if (vfy != X509_V_OK)
869 err_string = X509_verify_cert_error_string(vfy);
870 else if (match_cert_hostname(vpninfo, peer_cert))
871 err_string = _("certificate does not match hostname");
874 vpn_progress(vpninfo, PRG_INFO,
875 _("Server certificate verify failed: %s\n"),
878 if (vpninfo->validate_peer_cert)
879 ret = vpninfo->validate_peer_cert(vpninfo->cbdata,
888 X509_free(peer_cert);
893 static void workaround_openssl_certchain_bug(struct openconnect_info *vpninfo,
896 /* OpenSSL has problems with certificate chains -- if there are
897 multiple certs with the same name, it doesn't necessarily
898 choose the _right_ one. (RT#1942)
899 Pick the right ones for ourselves and add them manually. */
900 X509 *cert = SSL_get_certificate(ssl);
902 X509_STORE *store = SSL_CTX_get_cert_store(vpninfo->https_ctx);
908 /* If we already have 'supporting' certs, don't add them again */
909 if (vpninfo->https_ctx->extra_certs)
912 if (!X509_STORE_CTX_init(&ctx, store, NULL, NULL))
915 while (ctx.get_issuer(&cert2, &ctx, cert) == 1) {
919 if (X509_check_issued(cert2, cert2) == X509_V_OK)
922 X509_NAME_oneline(X509_get_subject_name(cert),
924 vpn_progress(vpninfo, PRG_DEBUG,
925 _("Extra cert from cafile: '%s'\n"), buf);
926 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert);
928 X509_STORE_CTX_cleanup(&ctx);
931 #if OPENSSL_VERSION_NUMBER >= 0x00908000
932 static int ssl_app_verify_callback(X509_STORE_CTX *ctx, void *arg)
934 /* We've seen certificates in the wild which don't have the
935 purpose fields filled in correctly */
936 X509_VERIFY_PARAM_set_purpose(ctx->param, X509_PURPOSE_ANY);
937 return X509_verify_cert(ctx);
941 static int check_certificate_expiry(struct openconnect_info *vpninfo)
944 const char *reason = NULL;
948 if (!vpninfo->cert_x509)
952 notAfter = X509_get_notAfter(vpninfo->cert_x509);
953 i = X509_cmp_time(notAfter, &t);
955 vpn_progress(vpninfo, PRG_ERR,
956 _("Error in client cert notAfter field\n"));
959 reason = _("Client certificate has expired at");
961 t += vpninfo->cert_expire_warning;
962 i = X509_cmp_time(notAfter, &t);
964 reason = _("Client certificate expires soon at");
968 BIO *bp = BIO_new(BIO_s_mem());
970 const char *expiry = _("<error>");
974 ASN1_TIME_print(bp, notAfter);
975 BIO_write(bp, &zero, 1);
976 BIO_get_mem_ptr(bp, &bm);
979 vpn_progress(vpninfo, PRG_ERR, "%s: %s\n", reason, expiry);
985 int openconnect_open_https(struct openconnect_info *vpninfo)
987 method_const SSL_METHOD *ssl3_method;
993 if (vpninfo->https_ssl)
996 if (vpninfo->peer_cert) {
997 X509_free(vpninfo->peer_cert);
998 vpninfo->peer_cert = NULL;
1001 ssl_sock = connect_https_socket(vpninfo);
1005 ssl3_method = TLSv1_client_method();
1006 if (!vpninfo->https_ctx) {
1007 vpninfo->https_ctx = SSL_CTX_new(ssl3_method);
1009 /* Some servers (or their firewalls) really don't like seeing
1011 #ifdef SSL_OP_NO_TICKET
1012 SSL_CTX_set_options (vpninfo->https_ctx, SSL_OP_NO_TICKET);
1015 if (vpninfo->cert) {
1016 err = load_certificate(vpninfo);
1018 vpn_progress(vpninfo, PRG_ERR,
1019 _("Loading certificate failed. Aborting.\n"));
1022 check_certificate_expiry(vpninfo);
1025 /* We just want to do:
1026 SSL_CTX_set_purpose(vpninfo->https_ctx, X509_PURPOSE_ANY);
1027 ... but it doesn't work with OpenSSL < 0.9.8k because of
1028 problems with inheritance (fixed in v1.1.4.6 of
1029 crypto/x509/x509_vpm.c) so we have to play silly buggers
1030 instead. This trick doesn't work _either_ in < 0.9.7 but
1031 I don't know of _any_ workaround which will, and can't
1032 be bothered to find out either. */
1033 #if OPENSSL_VERSION_NUMBER >= 0x00908000
1034 SSL_CTX_set_cert_verify_callback(vpninfo->https_ctx,
1035 ssl_app_verify_callback, NULL);
1037 SSL_CTX_set_default_verify_paths(vpninfo->https_ctx);
1039 if (vpninfo->cafile) {
1040 if (!SSL_CTX_load_verify_locations(vpninfo->https_ctx, vpninfo->cafile, NULL)) {
1041 vpn_progress(vpninfo, PRG_ERR,
1042 _("Failed to open CA file '%s'\n"),
1044 openconnect_report_ssl_errors(vpninfo);
1051 https_ssl = SSL_new(vpninfo->https_ctx);
1052 workaround_openssl_certchain_bug(vpninfo, https_ssl);
1054 https_bio = BIO_new_socket(ssl_sock, BIO_NOCLOSE);
1055 BIO_set_nbio(https_bio, 1);
1056 SSL_set_bio(https_ssl, https_bio, https_bio);
1058 vpn_progress(vpninfo, PRG_INFO, _("SSL negotiation with %s\n"),
1061 while ((err = SSL_connect(https_ssl)) <= 0) {
1062 fd_set wr_set, rd_set;
1063 int maxfd = ssl_sock;
1068 err = SSL_get_error(https_ssl, err);
1069 if (err == SSL_ERROR_WANT_READ)
1070 FD_SET(ssl_sock, &rd_set);
1071 else if (err == SSL_ERROR_WANT_WRITE)
1072 FD_SET(ssl_sock, &wr_set);
1074 vpn_progress(vpninfo, PRG_ERR, _("SSL connection failure\n"));
1075 openconnect_report_ssl_errors(vpninfo);
1076 SSL_free(https_ssl);
1081 if (vpninfo->cancel_fd != -1) {
1082 FD_SET(vpninfo->cancel_fd, &rd_set);
1083 if (vpninfo->cancel_fd > ssl_sock)
1084 maxfd = vpninfo->cancel_fd;
1086 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
1087 if (vpninfo->cancel_fd != -1 &&
1088 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
1089 vpn_progress(vpninfo, PRG_ERR, _("SSL connection cancelled\n"));
1090 SSL_free(https_ssl);
1096 if (verify_peer(vpninfo, https_ssl)) {
1097 SSL_free(https_ssl);
1102 vpninfo->ssl_fd = ssl_sock;
1103 vpninfo->https_ssl = https_ssl;
1105 /* Stash this now, because it might not be available later if the
1106 server has disconnected. */
1107 vpninfo->peer_cert = SSL_get_peer_certificate(vpninfo->https_ssl);
1109 vpn_progress(vpninfo, PRG_INFO, _("Connected to HTTPS on %s\n"),
1115 void openconnect_close_https(struct openconnect_info *vpninfo)
1117 if (vpninfo->peer_cert) {
1118 X509_free(vpninfo->peer_cert);
1119 vpninfo->peer_cert = NULL;
1121 if (vpninfo->https_ssl) {
1122 SSL_free(vpninfo->https_ssl);
1123 vpninfo->https_ssl = NULL;
1125 if (vpninfo->ssl_fd != -1) {
1126 close(vpninfo->ssl_fd);
1127 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds);
1128 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
1129 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds);
1130 vpninfo->ssl_fd = -1;
1134 void openconnect_init_openssl(void)
1136 SSL_library_init ();
1138 SSL_load_error_strings ();
1139 OpenSSL_add_all_algorithms ();
1142 char *openconnect_get_cert_details(struct openconnect_info *vpninfo,
1143 struct x509_st *cert)
1145 BIO *bp = BIO_new(BIO_s_mem());
1150 X509_print_ex(bp, cert, 0, 0);
1151 BIO_write(bp, &zero, 1);
1152 BIO_get_mem_ptr(bp, &certinfo);
1154 ret = strdup(certinfo->data);
1160 int openconnect_local_cert_md5(struct openconnect_info *vpninfo,
1165 if (!vpninfo->cert_x509)
1168 if (get_cert_md5_fingerprint(vpninfo, vpninfo->cert_x509, buf))