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 static int print_err(const char *str, size_t len, void *ptr)
166 struct openconnect_info *vpninfo = ptr;
168 vpn_progress(vpninfo, PRG_ERR, "%s", str);
172 void openconnect_report_ssl_errors(struct openconnect_info *vpninfo)
174 ERR_print_errors_cb(print_err, vpninfo);
177 int openconnect_SSL_gets(struct openconnect_info *vpninfo, char *buf, size_t len)
186 ret = SSL_read(vpninfo->https_ssl, buf + i, 1);
188 if (buf[i] == '\n') {
190 if (i && buf[i-1] == '\r') {
203 fd_set rd_set, wr_set;
204 int maxfd = vpninfo->ssl_fd;
209 ret = SSL_get_error(vpninfo->https_ssl, ret);
210 if (ret == SSL_ERROR_WANT_READ)
211 FD_SET(vpninfo->ssl_fd, &rd_set);
212 else if (ret == SSL_ERROR_WANT_WRITE)
213 FD_SET(vpninfo->ssl_fd, &wr_set);
215 vpn_progress(vpninfo, PRG_ERR, _("Failed to read from SSL socket\n"));
216 openconnect_report_ssl_errors(vpninfo);
220 if (vpninfo->cancel_fd != -1) {
221 FD_SET(vpninfo->cancel_fd, &rd_set);
222 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
223 maxfd = vpninfo->cancel_fd;
225 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
226 if (vpninfo->cancel_fd != -1 &&
227 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
228 vpn_progress(vpninfo, PRG_ERR, _("SSL read cancelled\n"));
238 static int pem_pw_cb(char *buf, int len, int w, void *v)
240 struct openconnect_info *vpninfo = v;
242 /* Only try the provided password once... */
243 SSL_CTX_set_default_passwd_cb(vpninfo->https_ctx, NULL);
244 SSL_CTX_set_default_passwd_cb_userdata(vpninfo->https_ctx, NULL);
246 if (len <= strlen(vpninfo->cert_password)) {
247 vpn_progress(vpninfo, PRG_ERR,
248 _("PEM password too long (%zd >= %d)\n"),
249 strlen(vpninfo->cert_password), len);
252 strcpy(buf, vpninfo->cert_password);
253 return strlen(vpninfo->cert_password);
256 static int load_pkcs12_certificate(struct openconnect_info *vpninfo, PKCS12 *p12)
258 EVP_PKEY *pkey = NULL;
262 char pass[PEM_BUFSIZE];
265 /* We do this every time round the loop, to work around a bug in
266 OpenSSL < 1.0.0-beta2 -- where the stack at *ca will be freed
267 when PKCS12_parse() returns an error, but *ca is left pointing
268 to the freed memory. */
270 if (!vpninfo->cert_password) {
271 if (EVP_read_pw_string(pass, PEM_BUFSIZE,
272 "Enter PKCS#12 pass phrase:", 0))
275 if (!PKCS12_parse(p12, vpninfo->cert_password?:pass, &pkey, &cert, &ca)) {
276 unsigned long err = ERR_peek_error();
278 openconnect_report_ssl_errors(vpninfo);
280 if (ERR_GET_LIB(err) == ERR_LIB_PKCS12 &&
281 ERR_GET_FUNC(err) == PKCS12_F_PKCS12_PARSE &&
282 ERR_GET_REASON(err) == PKCS12_R_MAC_VERIFY_FAILURE) {
283 vpn_progress(vpninfo, PRG_ERR,
284 _("Parse PKCS#12 failed (wrong passphrase?)\n"));
285 vpninfo->cert_password = NULL;
289 vpn_progress(vpninfo, PRG_ERR,
290 _("Parse PKCS#12 failed (see above errors)\n"));
295 vpninfo->cert_x509 = cert;
296 SSL_CTX_use_certificate(vpninfo->https_ctx, cert);
298 vpn_progress(vpninfo, PRG_ERR,
299 _("PKCS#12 contained no certificate!"));
304 SSL_CTX_use_PrivateKey(vpninfo->https_ctx, pkey);
307 vpn_progress(vpninfo, PRG_ERR,
308 _("PKCS#12 contained no private key!"));
312 /* Only include supporting certificates which are actually necessary */
316 for (i = 0; i < sk_X509_num(ca); i++) {
317 X509 *cert2 = sk_X509_value(ca, i);
318 if (X509_check_issued(cert2, cert) == X509_V_OK) {
324 X509_NAME_oneline(X509_get_subject_name(cert2),
326 vpn_progress(vpninfo, PRG_DEBUG,
327 _("Extra cert from PKCS#12: '%s'\n"), buf);
328 CRYPTO_add(&cert2->references, 1, CRYPTO_LOCK_X509);
329 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert2);
334 sk_X509_pop_free(ca, X509_free);
342 static int load_tpm_certificate(struct openconnect_info *vpninfo)
346 ENGINE_load_builtin_engines();
348 e = ENGINE_by_id("tpm");
350 vpn_progress(vpninfo, PRG_ERR, _("Can't load TPM engine.\n"));
351 openconnect_report_ssl_errors(vpninfo);
354 if (!ENGINE_init(e) || !ENGINE_set_default_RSA(e) ||
355 !ENGINE_set_default_RAND(e)) {
356 vpn_progress(vpninfo, PRG_ERR, _("Failed to init TPM engine\n"));
357 openconnect_report_ssl_errors(vpninfo);
362 if (vpninfo->cert_password) {
363 if (!ENGINE_ctrl_cmd(e, "PIN", strlen(vpninfo->cert_password),
364 vpninfo->cert_password, NULL, 0)) {
365 vpn_progress(vpninfo, PRG_ERR,
366 _("Failed to set TPM SRK password\n"));
367 openconnect_report_ssl_errors(vpninfo);
370 key = ENGINE_load_private_key(e, vpninfo->sslkey, NULL, NULL);
372 vpn_progress(vpninfo, PRG_ERR,
373 _("Failed to load TPM private key\n"));
374 openconnect_report_ssl_errors(vpninfo);
379 if (!SSL_CTX_use_PrivateKey(vpninfo->https_ctx, key)) {
380 vpn_progress(vpninfo, PRG_ERR, _("Add key from TPM failed\n"));
381 openconnect_report_ssl_errors(vpninfo);
389 static int load_tpm_certificate(struct openconnect_info *vpninfo)
391 vpn_progress(vpninfo, PRG_ERR,
392 _("This version of OpenConnect was built without TPM support\n"));
397 static int reload_pem_cert(struct openconnect_info *vpninfo)
399 BIO *b = BIO_new(BIO_s_file_internal());
404 if (BIO_read_filename(b, vpninfo->cert) <= 0) {
407 vpn_progress(vpninfo, PRG_ERR,
408 _("Failed to reload X509 cert for expiry check\n"));
409 openconnect_report_ssl_errors(vpninfo);
412 vpninfo->cert_x509 = PEM_read_bio_X509_AUX(b, NULL, NULL, NULL);
413 if (!vpninfo->cert_x509)
419 static int load_certificate(struct openconnect_info *vpninfo)
421 vpn_progress(vpninfo, PRG_TRACE,
422 _("Using certificate file %s\n"), vpninfo->cert);
424 if (vpninfo->cert_type == CERT_TYPE_PKCS12 ||
425 vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
429 f = fopen(vpninfo->cert, "r");
431 vpn_progress(vpninfo, PRG_ERR,
432 _("Failed to open certificate file %s: %s\n"),
433 vpninfo->cert, strerror(errno));
436 p12 = d2i_PKCS12_fp(f, NULL);
439 return load_pkcs12_certificate(vpninfo, p12);
442 if (vpninfo->cert_type == CERT_TYPE_PKCS12) {
443 vpn_progress(vpninfo, PRG_ERR, _("Read PKCS#12 failed\n"));
444 openconnect_report_ssl_errors(vpninfo);
447 /* Clear error and fall through to see if it's a PEM file... */
451 /* It's PEM or TPM now, and either way we need to load the plain cert: */
452 if (!SSL_CTX_use_certificate_chain_file(vpninfo->https_ctx,
454 vpn_progress(vpninfo, PRG_ERR,
455 _("Loading certificate failed\n"));
456 openconnect_report_ssl_errors(vpninfo);
460 /* Ew, we can't get it back from the OpenSSL CTX in any sane fashion */
461 reload_pem_cert(vpninfo);
463 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
464 FILE *f = fopen(vpninfo->sslkey, "r");
468 vpn_progress(vpninfo, PRG_ERR,
469 _("Failed to open private key file %s: %s\n"),
470 vpninfo->cert, strerror(errno));
475 while (fgets(buf, 255, f)) {
476 if (!strcmp(buf, "-----BEGIN TSS KEY BLOB-----\n")) {
477 vpninfo->cert_type = CERT_TYPE_TPM;
479 } else if (!strcmp(buf, "-----BEGIN RSA PRIVATE KEY-----\n") ||
480 !strcmp(buf, "-----BEGIN DSA PRIVATE KEY-----\n") ||
481 !strcmp(buf, "-----BEGIN ENCRYPTED PRIVATE KEY-----\n")) {
482 vpninfo->cert_type = CERT_TYPE_PEM;
487 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
488 vpn_progress(vpninfo, PRG_ERR,
489 _("Failed to identify private key type in '%s'\n"),
495 if (vpninfo->cert_type == CERT_TYPE_TPM)
496 return load_tpm_certificate(vpninfo);
498 /* Standard PEM certificate */
499 if (vpninfo->cert_password) {
500 SSL_CTX_set_default_passwd_cb(vpninfo->https_ctx,
502 SSL_CTX_set_default_passwd_cb_userdata(vpninfo->https_ctx,
506 if (!SSL_CTX_use_RSAPrivateKey_file(vpninfo->https_ctx, vpninfo->sslkey,
508 unsigned long err = ERR_peek_error();
510 openconnect_report_ssl_errors(vpninfo);
512 #ifndef EVP_F_EVP_DECRYPTFINAL_EX
513 #define EVP_F_EVP_DECRYPTFINAL_EX EVP_F_EVP_DECRYPTFINAL
515 /* If the user fat-fingered the passphrase, try again */
516 if (ERR_GET_LIB(err) == ERR_LIB_EVP &&
517 ERR_GET_FUNC(err) == EVP_F_EVP_DECRYPTFINAL_EX &&
518 ERR_GET_REASON(err) == EVP_R_BAD_DECRYPT) {
519 vpn_progress(vpninfo, PRG_ERR,
520 _("Loading private key failed (wrong passphrase?)\n"));
524 vpn_progress(vpninfo, PRG_ERR,
525 _("Loading private key failed (see above errors)\n"));
531 static int get_cert_fingerprint(struct openconnect_info *vpninfo,
532 X509 *cert, const EVP_MD *type,
535 unsigned char md[EVP_MAX_MD_SIZE];
538 if (!X509_digest(cert, type, md, &n))
541 for (i=0; i < n; i++)
542 sprintf(&buf[i*2], "%02X", md[i]);
547 int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
548 X509 *cert, char *buf)
550 return get_cert_fingerprint(vpninfo, cert, EVP_md5(), buf);
553 int openconnect_get_cert_sha1(struct openconnect_info *vpninfo,
554 X509 *cert, char *buf)
556 return get_cert_fingerprint(vpninfo, cert, EVP_sha1(), buf);
559 static int check_server_cert(struct openconnect_info *vpninfo, X509 *cert)
561 char fingerprint[EVP_MAX_MD_SIZE * 2 + 1];
564 ret = openconnect_get_cert_sha1(vpninfo, cert, fingerprint);
568 if (strcasecmp(vpninfo->servercert, fingerprint)) {
569 vpn_progress(vpninfo, PRG_ERR,
570 _("Server SSL certificate didn't match: %s\n"), fingerprint);
576 static int match_hostname_elem(const char *hostname, int helem_len,
577 const char *match, int melem_len)
579 if (!helem_len && !melem_len)
582 if (!helem_len || !melem_len)
586 if (match[0] == '*') {
589 for (i = 1 ; i <= helem_len; i++) {
590 if (!match_hostname_elem(hostname + i, helem_len - i,
591 match + 1, melem_len - 1))
597 /* From the NetBSD (5.1) man page for ctype(3):
598 Values of type char or signed char must first be cast to unsigned char,
599 to ensure that the values are within the correct range. The result
600 should then be cast to int to avoid warnings from some compilers.
601 We do indeed get warning "array subscript has type 'char'" without
603 if (toupper((int)(unsigned char)hostname[0]) ==
604 toupper((int)(unsigned char)match[0]))
605 return match_hostname_elem(hostname + 1, helem_len - 1,
606 match + 1, melem_len - 1);
611 static int match_hostname(const char *hostname, const char *match)
614 const char *h_dot, *m_dot;
615 int helem_len, melem_len;
617 h_dot = strchr(hostname, '.');
618 m_dot = strchr(match, '.');
620 if (h_dot && m_dot) {
621 helem_len = h_dot - hostname + 1;
622 melem_len = m_dot - match + 1;
623 } else if (!h_dot && !m_dot) {
624 helem_len = strlen(hostname);
625 melem_len = strlen(match);
630 if (match_hostname_elem(hostname, helem_len,
634 hostname += helem_len;
643 /* cf. RFC2818 and RFC2459 */
644 static int match_cert_hostname(struct openconnect_info *vpninfo, X509 *peer_cert)
646 STACK_OF(GENERAL_NAME) *altnames;
648 ASN1_STRING *subjasn1;
649 char *subjstr = NULL;
652 char addrbuf[sizeof(struct in6_addr)];
655 /* Allow GEN_IP in the certificate only if we actually connected
656 by IP address rather than by name. */
657 if (inet_pton(AF_INET, vpninfo->hostname, addrbuf) > 0)
659 else if (inet_pton(AF_INET6, vpninfo->hostname, addrbuf) > 0)
661 else if (vpninfo->hostname[0] == '[' &&
662 vpninfo->hostname[strlen(vpninfo->hostname)-1] == ']') {
663 char *p = &vpninfo->hostname[strlen(vpninfo->hostname)-1];
665 if (inet_pton(AF_INET6, vpninfo->hostname + 1, addrbuf) > 0)
670 altnames = X509_get_ext_d2i(peer_cert, NID_subject_alt_name,
672 for (i = 0; i < sk_GENERAL_NAME_num(altnames); i++) {
673 const GENERAL_NAME *this = sk_GENERAL_NAME_value(altnames, i);
675 if (this->type == GEN_DNS) {
678 int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
684 /* We don't like names with embedded NUL */
685 if (strlen(str) != len)
688 if (!match_hostname(vpninfo->hostname, str)) {
689 vpn_progress(vpninfo, PRG_TRACE,
690 _("Matched DNS altname '%s'\n"),
692 GENERAL_NAMES_free(altnames);
696 vpn_progress(vpninfo, PRG_TRACE,
697 _("No match for altname '%s'\n"),
701 } else if (this->type == GEN_IPADD && addrlen) {
705 if (this->d.ip->length == 4) {
707 } else if (this->d.ip->length == 16) {
710 vpn_progress(vpninfo, PRG_ERR,
711 _("Certificate has GEN_IPADD altname with bogus length %d\n"),
716 /* We only do this for the debug messages */
717 inet_ntop(family, this->d.ip->data, host, sizeof(host));
719 if (this->d.ip->length == addrlen &&
720 !memcmp(addrbuf, this->d.ip->data, addrlen)) {
721 vpn_progress(vpninfo, PRG_TRACE,
722 _("Matched %s address '%s'\n"),
723 (family == AF_INET6)?"IPv6":"IPv4",
725 GENERAL_NAMES_free(altnames);
728 vpn_progress(vpninfo, PRG_TRACE,
729 _("No match for %s address '%s'\n"),
730 (family == AF_INET6)?"IPv6":"IPv4",
733 } else if (this->type == GEN_URI) {
735 char *url_proto, *url_host, *url_path, *url_host2;
737 int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
742 /* We don't like names with embedded NUL */
743 if (strlen(str) != len)
746 if (internal_parse_url(str, &url_proto, &url_host, &url_port, &url_path, 0)) {
751 if (!url_proto || strcasecmp(url_proto, "https"))
754 if (url_port != vpninfo->port)
757 /* Leave url_host as it was so that it can be freed */
758 url_host2 = url_host;
759 if (addrlen == 16 && vpninfo->hostname[0] != '[' &&
760 url_host[0] == '[' && url_host[strlen(url_host)-1] == ']') {
761 /* Cope with https://[IPv6]/ when the hostname is bare IPv6 */
762 url_host[strlen(url_host)-1] = 0;
766 if (strcasecmp(vpninfo->hostname, url_host2))
770 vpn_progress(vpninfo, PRG_TRACE,
771 _("URI '%s' has non-empty path; ignoring\n"),
773 goto no_uri_match_silent;
775 vpn_progress(vpninfo, PRG_TRACE,
776 _("Matched URI '%s'\n"),
782 GENERAL_NAMES_free(altnames);
786 vpn_progress(vpninfo, PRG_TRACE,
787 _("No match for URI '%s'\n"),
796 GENERAL_NAMES_free(altnames);
798 /* According to RFC2818, we don't use the legacy subject name if
799 there was an altname with DNS type. */
801 vpn_progress(vpninfo, PRG_ERR,
802 _("No altname in peer cert matched '%s'\n"),
807 subjname = X509_get_subject_name(peer_cert);
809 vpn_progress(vpninfo, PRG_ERR,
810 _("No subject name in peer cert!\n"));
814 /* Find the _last_ (most specific) commonName */
817 int j = X509_NAME_get_index_by_NID(subjname, NID_commonName, i);
824 subjasn1 = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subjname, i));
826 i = ASN1_STRING_to_UTF8((void *)&subjstr, subjasn1);
828 if (!subjstr || strlen(subjstr) != i) {
829 vpn_progress(vpninfo, PRG_ERR,
830 _("Failed to parse subject name in peer cert\n"));
835 if (match_hostname(vpninfo->hostname, subjstr)) {
836 vpn_progress(vpninfo, PRG_ERR,
837 _("Peer cert subject mismatch ('%s' != '%s')\n"),
838 subjstr, vpninfo->hostname);
841 vpn_progress(vpninfo, PRG_TRACE,
842 _("Matched peer certificate subject name '%s'\n"),
846 OPENSSL_free(subjstr);
850 static int verify_peer(struct openconnect_info *vpninfo, SSL *https_ssl)
855 peer_cert = SSL_get_peer_certificate(https_ssl);
857 if (vpninfo->servercert) {
858 /* If given a cert fingerprint on the command line, that's
860 ret = check_server_cert(vpninfo, peer_cert);
862 int vfy = SSL_get_verify_result(https_ssl);
863 const char *err_string = NULL;
865 if (vfy != X509_V_OK)
866 err_string = X509_verify_cert_error_string(vfy);
867 else if (match_cert_hostname(vpninfo, peer_cert))
868 err_string = _("certificate does not match hostname");
871 vpn_progress(vpninfo, PRG_INFO,
872 _("Server certificate verify failed: %s\n"),
875 if (vpninfo->validate_peer_cert)
876 ret = vpninfo->validate_peer_cert(vpninfo->cbdata,
885 X509_free(peer_cert);
890 static void workaround_openssl_certchain_bug(struct openconnect_info *vpninfo,
893 /* OpenSSL has problems with certificate chains -- if there are
894 multiple certs with the same name, it doesn't necessarily
895 choose the _right_ one. (RT#1942)
896 Pick the right ones for ourselves and add them manually. */
897 X509 *cert = SSL_get_certificate(ssl);
899 X509_STORE *store = SSL_CTX_get_cert_store(vpninfo->https_ctx);
905 /* If we already have 'supporting' certs, don't add them again */
906 if (vpninfo->https_ctx->extra_certs)
909 if (!X509_STORE_CTX_init(&ctx, store, NULL, NULL))
912 while (ctx.get_issuer(&cert2, &ctx, cert) == 1) {
917 X509_NAME_oneline(X509_get_subject_name(cert),
919 vpn_progress(vpninfo, PRG_DEBUG,
920 _("Extra cert from cafile: '%s'\n"), buf);
921 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert);
923 X509_STORE_CTX_cleanup(&ctx);
926 #if OPENSSL_VERSION_NUMBER >= 0x00908000
927 static int ssl_app_verify_callback(X509_STORE_CTX *ctx, void *arg)
929 /* We've seen certificates in the wild which don't have the
930 purpose fields filled in correctly */
931 X509_VERIFY_PARAM_set_purpose(ctx->param, X509_PURPOSE_ANY);
932 return X509_verify_cert(ctx);
936 static int check_certificate_expiry(struct openconnect_info *vpninfo)
939 const char *reason = NULL;
943 if (!vpninfo->cert_x509)
947 notAfter = X509_get_notAfter(vpninfo->cert_x509);
948 i = X509_cmp_time(notAfter, &t);
950 vpn_progress(vpninfo, PRG_ERR,
951 _("Error in client cert notAfter field\n"));
954 reason = _("Client certificate has expired at");
956 t += vpninfo->cert_expire_warning;
957 i = X509_cmp_time(notAfter, &t);
959 reason = _("Client certificate expires soon at");
963 BIO *bp = BIO_new(BIO_s_mem());
965 const char *expiry = _("<error>");
969 ASN1_TIME_print(bp, notAfter);
970 BIO_write(bp, &zero, 1);
971 BIO_get_mem_ptr(bp, &bm);
974 vpn_progress(vpninfo, PRG_ERR, "%s: %s\n", reason, expiry);
980 int openconnect_open_https(struct openconnect_info *vpninfo)
982 method_const SSL_METHOD *ssl3_method;
988 if (vpninfo->https_ssl)
991 if (vpninfo->peer_cert) {
992 X509_free(vpninfo->peer_cert);
993 vpninfo->peer_cert = NULL;
996 ssl_sock = connect_https_socket(vpninfo);
1000 ssl3_method = TLSv1_client_method();
1001 if (!vpninfo->https_ctx) {
1002 vpninfo->https_ctx = SSL_CTX_new(ssl3_method);
1004 /* Some servers (or their firewalls) really don't like seeing
1006 #ifdef SSL_OP_NO_TICKET
1007 SSL_CTX_set_options (vpninfo->https_ctx, SSL_OP_NO_TICKET);
1010 if (vpninfo->cert) {
1011 err = load_certificate(vpninfo);
1013 vpn_progress(vpninfo, PRG_ERR,
1014 _("Loading certificate failed. Aborting.\n"));
1017 check_certificate_expiry(vpninfo);
1020 /* We just want to do:
1021 SSL_CTX_set_purpose(vpninfo->https_ctx, X509_PURPOSE_ANY);
1022 ... but it doesn't work with OpenSSL < 0.9.8k because of
1023 problems with inheritance (fixed in v1.1.4.6 of
1024 crypto/x509/x509_vpm.c) so we have to play silly buggers
1025 instead. This trick doesn't work _either_ in < 0.9.7 but
1026 I don't know of _any_ workaround which will, and can't
1027 be bothered to find out either. */
1028 #if OPENSSL_VERSION_NUMBER >= 0x00908000
1029 SSL_CTX_set_cert_verify_callback(vpninfo->https_ctx,
1030 ssl_app_verify_callback, NULL);
1032 SSL_CTX_set_default_verify_paths(vpninfo->https_ctx);
1034 if (vpninfo->cafile) {
1035 if (!SSL_CTX_load_verify_locations(vpninfo->https_ctx, vpninfo->cafile, NULL)) {
1036 vpn_progress(vpninfo, PRG_ERR,
1037 _("Failed to open CA file '%s'\n"),
1039 openconnect_report_ssl_errors(vpninfo);
1046 https_ssl = SSL_new(vpninfo->https_ctx);
1047 workaround_openssl_certchain_bug(vpninfo, https_ssl);
1049 https_bio = BIO_new_socket(ssl_sock, BIO_NOCLOSE);
1050 BIO_set_nbio(https_bio, 1);
1051 SSL_set_bio(https_ssl, https_bio, https_bio);
1053 vpn_progress(vpninfo, PRG_INFO, _("SSL negotiation with %s\n"),
1056 while ((err = SSL_connect(https_ssl)) <= 0) {
1057 fd_set wr_set, rd_set;
1058 int maxfd = ssl_sock;
1063 err = SSL_get_error(https_ssl, err);
1064 if (err == SSL_ERROR_WANT_READ)
1065 FD_SET(ssl_sock, &rd_set);
1066 else if (err == SSL_ERROR_WANT_WRITE)
1067 FD_SET(ssl_sock, &wr_set);
1069 vpn_progress(vpninfo, PRG_ERR, _("SSL connection failure\n"));
1070 openconnect_report_ssl_errors(vpninfo);
1071 SSL_free(https_ssl);
1076 if (vpninfo->cancel_fd != -1) {
1077 FD_SET(vpninfo->cancel_fd, &rd_set);
1078 if (vpninfo->cancel_fd > ssl_sock)
1079 maxfd = vpninfo->cancel_fd;
1081 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
1082 if (vpninfo->cancel_fd != -1 &&
1083 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
1084 vpn_progress(vpninfo, PRG_ERR, _("SSL connection cancelled\n"));
1085 SSL_free(https_ssl);
1091 if (verify_peer(vpninfo, https_ssl)) {
1092 SSL_free(https_ssl);
1097 vpninfo->ssl_fd = ssl_sock;
1098 vpninfo->https_ssl = https_ssl;
1100 /* Stash this now, because it might not be available later if the
1101 server has disconnected. */
1102 vpninfo->peer_cert = SSL_get_peer_certificate(vpninfo->https_ssl);
1104 vpn_progress(vpninfo, PRG_INFO, _("Connected to HTTPS on %s\n"),
1110 void openconnect_close_https(struct openconnect_info *vpninfo)
1112 if (vpninfo->peer_cert) {
1113 X509_free(vpninfo->peer_cert);
1114 vpninfo->peer_cert = NULL;
1116 if (vpninfo->https_ssl) {
1117 SSL_free(vpninfo->https_ssl);
1118 vpninfo->https_ssl = NULL;
1120 if (vpninfo->ssl_fd != -1) {
1121 close(vpninfo->ssl_fd);
1122 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds);
1123 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
1124 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds);
1125 vpninfo->ssl_fd = -1;
1129 void openconnect_init_openssl(void)
1131 SSL_library_init ();
1133 SSL_load_error_strings ();
1134 OpenSSL_add_all_algorithms ();
1137 char *openconnect_get_cert_details(struct openconnect_info *vpninfo,
1138 struct x509_st *cert)
1140 BIO *bp = BIO_new(BIO_s_mem());
1145 X509_print_ex(bp, cert, 0, 0);
1146 BIO_write(bp, &zero, 1);
1147 BIO_get_mem_ptr(bp, &certinfo);
1149 ret = strdup(certinfo->data);
1155 int openconnect_local_cert_md5(struct openconnect_info *vpninfo,
1160 if (!vpninfo->cert_x509)
1163 if (get_cert_md5_fingerprint(vpninfo, vpninfo->cert_x509, buf))