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) {
323 if (X509_check_issued(cert2, cert2) == X509_V_OK)
326 X509_NAME_oneline(X509_get_subject_name(cert2),
328 vpn_progress(vpninfo, PRG_DEBUG,
329 _("Extra cert from PKCS#12: '%s'\n"), buf);
330 CRYPTO_add(&cert2->references, 1, CRYPTO_LOCK_X509);
331 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert2);
336 sk_X509_pop_free(ca, X509_free);
344 static int load_tpm_certificate(struct openconnect_info *vpninfo)
348 ENGINE_load_builtin_engines();
350 e = ENGINE_by_id("tpm");
352 vpn_progress(vpninfo, PRG_ERR, _("Can't load TPM engine.\n"));
353 openconnect_report_ssl_errors(vpninfo);
356 if (!ENGINE_init(e) || !ENGINE_set_default_RSA(e) ||
357 !ENGINE_set_default_RAND(e)) {
358 vpn_progress(vpninfo, PRG_ERR, _("Failed to init TPM engine\n"));
359 openconnect_report_ssl_errors(vpninfo);
364 if (vpninfo->cert_password) {
365 if (!ENGINE_ctrl_cmd(e, "PIN", strlen(vpninfo->cert_password),
366 vpninfo->cert_password, NULL, 0)) {
367 vpn_progress(vpninfo, PRG_ERR,
368 _("Failed to set TPM SRK password\n"));
369 openconnect_report_ssl_errors(vpninfo);
372 key = ENGINE_load_private_key(e, vpninfo->sslkey, NULL, NULL);
374 vpn_progress(vpninfo, PRG_ERR,
375 _("Failed to load TPM private key\n"));
376 openconnect_report_ssl_errors(vpninfo);
381 if (!SSL_CTX_use_PrivateKey(vpninfo->https_ctx, key)) {
382 vpn_progress(vpninfo, PRG_ERR, _("Add key from TPM failed\n"));
383 openconnect_report_ssl_errors(vpninfo);
391 static int load_tpm_certificate(struct openconnect_info *vpninfo)
393 vpn_progress(vpninfo, PRG_ERR,
394 _("This version of OpenConnect was built without TPM support\n"));
399 static int reload_pem_cert(struct openconnect_info *vpninfo)
401 BIO *b = BIO_new(BIO_s_file_internal());
406 if (BIO_read_filename(b, vpninfo->cert) <= 0) {
409 vpn_progress(vpninfo, PRG_ERR,
410 _("Failed to reload X509 cert for expiry check\n"));
411 openconnect_report_ssl_errors(vpninfo);
414 vpninfo->cert_x509 = PEM_read_bio_X509_AUX(b, NULL, NULL, NULL);
415 if (!vpninfo->cert_x509)
421 static int load_certificate(struct openconnect_info *vpninfo)
423 vpn_progress(vpninfo, PRG_TRACE,
424 _("Using certificate file %s\n"), vpninfo->cert);
426 if (vpninfo->cert_type == CERT_TYPE_PKCS12 ||
427 vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
431 f = fopen(vpninfo->cert, "r");
433 vpn_progress(vpninfo, PRG_ERR,
434 _("Failed to open certificate file %s: %s\n"),
435 vpninfo->cert, strerror(errno));
438 p12 = d2i_PKCS12_fp(f, NULL);
441 return load_pkcs12_certificate(vpninfo, p12);
444 if (vpninfo->cert_type == CERT_TYPE_PKCS12) {
445 vpn_progress(vpninfo, PRG_ERR, _("Read PKCS#12 failed\n"));
446 openconnect_report_ssl_errors(vpninfo);
449 /* Clear error and fall through to see if it's a PEM file... */
453 /* It's PEM or TPM now, and either way we need to load the plain cert: */
454 if (!SSL_CTX_use_certificate_chain_file(vpninfo->https_ctx,
456 vpn_progress(vpninfo, PRG_ERR,
457 _("Loading certificate failed\n"));
458 openconnect_report_ssl_errors(vpninfo);
462 /* Ew, we can't get it back from the OpenSSL CTX in any sane fashion */
463 reload_pem_cert(vpninfo);
465 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
466 FILE *f = fopen(vpninfo->sslkey, "r");
470 vpn_progress(vpninfo, PRG_ERR,
471 _("Failed to open private key file %s: %s\n"),
472 vpninfo->cert, strerror(errno));
477 while (fgets(buf, 255, f)) {
478 if (!strcmp(buf, "-----BEGIN TSS KEY BLOB-----\n")) {
479 vpninfo->cert_type = CERT_TYPE_TPM;
481 } else if (!strcmp(buf, "-----BEGIN RSA PRIVATE KEY-----\n") ||
482 !strcmp(buf, "-----BEGIN DSA PRIVATE KEY-----\n") ||
483 !strcmp(buf, "-----BEGIN ENCRYPTED PRIVATE KEY-----\n")) {
484 vpninfo->cert_type = CERT_TYPE_PEM;
489 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
490 vpn_progress(vpninfo, PRG_ERR,
491 _("Failed to identify private key type in '%s'\n"),
497 if (vpninfo->cert_type == CERT_TYPE_TPM)
498 return load_tpm_certificate(vpninfo);
500 /* Standard PEM certificate */
501 if (vpninfo->cert_password) {
502 SSL_CTX_set_default_passwd_cb(vpninfo->https_ctx,
504 SSL_CTX_set_default_passwd_cb_userdata(vpninfo->https_ctx,
508 if (!SSL_CTX_use_RSAPrivateKey_file(vpninfo->https_ctx, vpninfo->sslkey,
510 unsigned long err = ERR_peek_error();
512 openconnect_report_ssl_errors(vpninfo);
514 #ifndef EVP_F_EVP_DECRYPTFINAL_EX
515 #define EVP_F_EVP_DECRYPTFINAL_EX EVP_F_EVP_DECRYPTFINAL
517 /* If the user fat-fingered the passphrase, try again */
518 if (ERR_GET_LIB(err) == ERR_LIB_EVP &&
519 ERR_GET_FUNC(err) == EVP_F_EVP_DECRYPTFINAL_EX &&
520 ERR_GET_REASON(err) == EVP_R_BAD_DECRYPT) {
521 vpn_progress(vpninfo, PRG_ERR,
522 _("Loading private key failed (wrong passphrase?)\n"));
526 vpn_progress(vpninfo, PRG_ERR,
527 _("Loading private key failed (see above errors)\n"));
533 static int get_cert_fingerprint(struct openconnect_info *vpninfo,
534 X509 *cert, const EVP_MD *type,
537 unsigned char md[EVP_MAX_MD_SIZE];
540 if (!X509_digest(cert, type, md, &n))
543 for (i=0; i < n; i++)
544 sprintf(&buf[i*2], "%02X", md[i]);
549 int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
550 X509 *cert, char *buf)
552 return get_cert_fingerprint(vpninfo, cert, EVP_md5(), buf);
555 int openconnect_get_cert_sha1(struct openconnect_info *vpninfo,
556 X509 *cert, char *buf)
558 return get_cert_fingerprint(vpninfo, cert, EVP_sha1(), buf);
561 static int check_server_cert(struct openconnect_info *vpninfo, X509 *cert)
563 char fingerprint[EVP_MAX_MD_SIZE * 2 + 1];
566 ret = openconnect_get_cert_sha1(vpninfo, cert, fingerprint);
570 if (strcasecmp(vpninfo->servercert, fingerprint)) {
571 vpn_progress(vpninfo, PRG_ERR,
572 _("Server SSL certificate didn't match: %s\n"), fingerprint);
578 static int match_hostname_elem(const char *hostname, int helem_len,
579 const char *match, int melem_len)
581 if (!helem_len && !melem_len)
584 if (!helem_len || !melem_len)
588 if (match[0] == '*') {
591 for (i = 1 ; i <= helem_len; i++) {
592 if (!match_hostname_elem(hostname + i, helem_len - i,
593 match + 1, melem_len - 1))
599 /* From the NetBSD (5.1) man page for ctype(3):
600 Values of type char or signed char must first be cast to unsigned char,
601 to ensure that the values are within the correct range. The result
602 should then be cast to int to avoid warnings from some compilers.
603 We do indeed get warning "array subscript has type 'char'" without
605 if (toupper((int)(unsigned char)hostname[0]) ==
606 toupper((int)(unsigned char)match[0]))
607 return match_hostname_elem(hostname + 1, helem_len - 1,
608 match + 1, melem_len - 1);
613 static int match_hostname(const char *hostname, const char *match)
616 const char *h_dot, *m_dot;
617 int helem_len, melem_len;
619 h_dot = strchr(hostname, '.');
620 m_dot = strchr(match, '.');
622 if (h_dot && m_dot) {
623 helem_len = h_dot - hostname + 1;
624 melem_len = m_dot - match + 1;
625 } else if (!h_dot && !m_dot) {
626 helem_len = strlen(hostname);
627 melem_len = strlen(match);
632 if (match_hostname_elem(hostname, helem_len,
636 hostname += helem_len;
645 /* cf. RFC2818 and RFC2459 */
646 static int match_cert_hostname(struct openconnect_info *vpninfo, X509 *peer_cert)
648 STACK_OF(GENERAL_NAME) *altnames;
650 ASN1_STRING *subjasn1;
651 char *subjstr = NULL;
654 char addrbuf[sizeof(struct in6_addr)];
657 /* Allow GEN_IP in the certificate only if we actually connected
658 by IP address rather than by name. */
659 if (inet_pton(AF_INET, vpninfo->hostname, addrbuf) > 0)
661 else if (inet_pton(AF_INET6, vpninfo->hostname, addrbuf) > 0)
663 else if (vpninfo->hostname[0] == '[' &&
664 vpninfo->hostname[strlen(vpninfo->hostname)-1] == ']') {
665 char *p = &vpninfo->hostname[strlen(vpninfo->hostname)-1];
667 if (inet_pton(AF_INET6, vpninfo->hostname + 1, addrbuf) > 0)
672 altnames = X509_get_ext_d2i(peer_cert, NID_subject_alt_name,
674 for (i = 0; i < sk_GENERAL_NAME_num(altnames); i++) {
675 const GENERAL_NAME *this = sk_GENERAL_NAME_value(altnames, i);
677 if (this->type == GEN_DNS) {
680 int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
686 /* We don't like names with embedded NUL */
687 if (strlen(str) != len)
690 if (!match_hostname(vpninfo->hostname, str)) {
691 vpn_progress(vpninfo, PRG_TRACE,
692 _("Matched DNS altname '%s'\n"),
694 GENERAL_NAMES_free(altnames);
698 vpn_progress(vpninfo, PRG_TRACE,
699 _("No match for altname '%s'\n"),
703 } else if (this->type == GEN_IPADD && addrlen) {
707 if (this->d.ip->length == 4) {
709 } else if (this->d.ip->length == 16) {
712 vpn_progress(vpninfo, PRG_ERR,
713 _("Certificate has GEN_IPADD altname with bogus length %d\n"),
718 /* We only do this for the debug messages */
719 inet_ntop(family, this->d.ip->data, host, sizeof(host));
721 if (this->d.ip->length == addrlen &&
722 !memcmp(addrbuf, this->d.ip->data, addrlen)) {
723 vpn_progress(vpninfo, PRG_TRACE,
724 _("Matched %s address '%s'\n"),
725 (family == AF_INET6)?"IPv6":"IPv4",
727 GENERAL_NAMES_free(altnames);
730 vpn_progress(vpninfo, PRG_TRACE,
731 _("No match for %s address '%s'\n"),
732 (family == AF_INET6)?"IPv6":"IPv4",
735 } else if (this->type == GEN_URI) {
737 char *url_proto, *url_host, *url_path, *url_host2;
739 int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
744 /* We don't like names with embedded NUL */
745 if (strlen(str) != len)
748 if (internal_parse_url(str, &url_proto, &url_host, &url_port, &url_path, 0)) {
753 if (!url_proto || strcasecmp(url_proto, "https"))
756 if (url_port != vpninfo->port)
759 /* Leave url_host as it was so that it can be freed */
760 url_host2 = url_host;
761 if (addrlen == 16 && vpninfo->hostname[0] != '[' &&
762 url_host[0] == '[' && url_host[strlen(url_host)-1] == ']') {
763 /* Cope with https://[IPv6]/ when the hostname is bare IPv6 */
764 url_host[strlen(url_host)-1] = 0;
768 if (strcasecmp(vpninfo->hostname, url_host2))
772 vpn_progress(vpninfo, PRG_TRACE,
773 _("URI '%s' has non-empty path; ignoring\n"),
775 goto no_uri_match_silent;
777 vpn_progress(vpninfo, PRG_TRACE,
778 _("Matched URI '%s'\n"),
784 GENERAL_NAMES_free(altnames);
788 vpn_progress(vpninfo, PRG_TRACE,
789 _("No match for URI '%s'\n"),
798 GENERAL_NAMES_free(altnames);
800 /* According to RFC2818, we don't use the legacy subject name if
801 there was an altname with DNS type. */
803 vpn_progress(vpninfo, PRG_ERR,
804 _("No altname in peer cert matched '%s'\n"),
809 subjname = X509_get_subject_name(peer_cert);
811 vpn_progress(vpninfo, PRG_ERR,
812 _("No subject name in peer cert!\n"));
816 /* Find the _last_ (most specific) commonName */
819 int j = X509_NAME_get_index_by_NID(subjname, NID_commonName, i);
826 subjasn1 = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subjname, i));
828 i = ASN1_STRING_to_UTF8((void *)&subjstr, subjasn1);
830 if (!subjstr || strlen(subjstr) != i) {
831 vpn_progress(vpninfo, PRG_ERR,
832 _("Failed to parse subject name in peer cert\n"));
837 if (match_hostname(vpninfo->hostname, subjstr)) {
838 vpn_progress(vpninfo, PRG_ERR,
839 _("Peer cert subject mismatch ('%s' != '%s')\n"),
840 subjstr, vpninfo->hostname);
843 vpn_progress(vpninfo, PRG_TRACE,
844 _("Matched peer certificate subject name '%s'\n"),
848 OPENSSL_free(subjstr);
852 static int verify_peer(struct openconnect_info *vpninfo, SSL *https_ssl)
857 peer_cert = SSL_get_peer_certificate(https_ssl);
859 if (vpninfo->servercert) {
860 /* If given a cert fingerprint on the command line, that's
862 ret = check_server_cert(vpninfo, peer_cert);
864 int vfy = SSL_get_verify_result(https_ssl);
865 const char *err_string = NULL;
867 if (vfy != X509_V_OK)
868 err_string = X509_verify_cert_error_string(vfy);
869 else if (match_cert_hostname(vpninfo, peer_cert))
870 err_string = _("certificate does not match hostname");
873 vpn_progress(vpninfo, PRG_INFO,
874 _("Server certificate verify failed: %s\n"),
877 if (vpninfo->validate_peer_cert)
878 ret = vpninfo->validate_peer_cert(vpninfo->cbdata,
887 X509_free(peer_cert);
892 static void workaround_openssl_certchain_bug(struct openconnect_info *vpninfo,
895 /* OpenSSL has problems with certificate chains -- if there are
896 multiple certs with the same name, it doesn't necessarily
897 choose the _right_ one. (RT#1942)
898 Pick the right ones for ourselves and add them manually. */
899 X509 *cert = SSL_get_certificate(ssl);
901 X509_STORE *store = SSL_CTX_get_cert_store(vpninfo->https_ctx);
907 /* If we already have 'supporting' certs, don't add them again */
908 if (vpninfo->https_ctx->extra_certs)
911 if (!X509_STORE_CTX_init(&ctx, store, NULL, NULL))
914 while (ctx.get_issuer(&cert2, &ctx, cert) == 1) {
918 if (X509_check_issued(cert2, cert2) == X509_V_OK)
921 X509_NAME_oneline(X509_get_subject_name(cert),
923 vpn_progress(vpninfo, PRG_DEBUG,
924 _("Extra cert from cafile: '%s'\n"), buf);
925 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert);
927 X509_STORE_CTX_cleanup(&ctx);
930 #if OPENSSL_VERSION_NUMBER >= 0x00908000
931 static int ssl_app_verify_callback(X509_STORE_CTX *ctx, void *arg)
933 /* We've seen certificates in the wild which don't have the
934 purpose fields filled in correctly */
935 X509_VERIFY_PARAM_set_purpose(ctx->param, X509_PURPOSE_ANY);
936 return X509_verify_cert(ctx);
940 static int check_certificate_expiry(struct openconnect_info *vpninfo)
943 const char *reason = NULL;
947 if (!vpninfo->cert_x509)
951 notAfter = X509_get_notAfter(vpninfo->cert_x509);
952 i = X509_cmp_time(notAfter, &t);
954 vpn_progress(vpninfo, PRG_ERR,
955 _("Error in client cert notAfter field\n"));
958 reason = _("Client certificate has expired at");
960 t += vpninfo->cert_expire_warning;
961 i = X509_cmp_time(notAfter, &t);
963 reason = _("Client certificate expires soon at");
967 BIO *bp = BIO_new(BIO_s_mem());
969 const char *expiry = _("<error>");
973 ASN1_TIME_print(bp, notAfter);
974 BIO_write(bp, &zero, 1);
975 BIO_get_mem_ptr(bp, &bm);
978 vpn_progress(vpninfo, PRG_ERR, "%s: %s\n", reason, expiry);
984 int openconnect_open_https(struct openconnect_info *vpninfo)
986 method_const SSL_METHOD *ssl3_method;
992 if (vpninfo->https_ssl)
995 if (vpninfo->peer_cert) {
996 X509_free(vpninfo->peer_cert);
997 vpninfo->peer_cert = NULL;
1000 ssl_sock = connect_https_socket(vpninfo);
1004 ssl3_method = TLSv1_client_method();
1005 if (!vpninfo->https_ctx) {
1006 vpninfo->https_ctx = SSL_CTX_new(ssl3_method);
1008 /* Some servers (or their firewalls) really don't like seeing
1010 #ifdef SSL_OP_NO_TICKET
1011 SSL_CTX_set_options (vpninfo->https_ctx, SSL_OP_NO_TICKET);
1014 if (vpninfo->cert) {
1015 err = load_certificate(vpninfo);
1017 vpn_progress(vpninfo, PRG_ERR,
1018 _("Loading certificate failed. Aborting.\n"));
1021 check_certificate_expiry(vpninfo);
1024 /* We just want to do:
1025 SSL_CTX_set_purpose(vpninfo->https_ctx, X509_PURPOSE_ANY);
1026 ... but it doesn't work with OpenSSL < 0.9.8k because of
1027 problems with inheritance (fixed in v1.1.4.6 of
1028 crypto/x509/x509_vpm.c) so we have to play silly buggers
1029 instead. This trick doesn't work _either_ in < 0.9.7 but
1030 I don't know of _any_ workaround which will, and can't
1031 be bothered to find out either. */
1032 #if OPENSSL_VERSION_NUMBER >= 0x00908000
1033 SSL_CTX_set_cert_verify_callback(vpninfo->https_ctx,
1034 ssl_app_verify_callback, NULL);
1036 SSL_CTX_set_default_verify_paths(vpninfo->https_ctx);
1038 if (vpninfo->cafile) {
1039 if (!SSL_CTX_load_verify_locations(vpninfo->https_ctx, vpninfo->cafile, NULL)) {
1040 vpn_progress(vpninfo, PRG_ERR,
1041 _("Failed to open CA file '%s'\n"),
1043 openconnect_report_ssl_errors(vpninfo);
1050 https_ssl = SSL_new(vpninfo->https_ctx);
1051 workaround_openssl_certchain_bug(vpninfo, https_ssl);
1053 https_bio = BIO_new_socket(ssl_sock, BIO_NOCLOSE);
1054 BIO_set_nbio(https_bio, 1);
1055 SSL_set_bio(https_ssl, https_bio, https_bio);
1057 vpn_progress(vpninfo, PRG_INFO, _("SSL negotiation with %s\n"),
1060 while ((err = SSL_connect(https_ssl)) <= 0) {
1061 fd_set wr_set, rd_set;
1062 int maxfd = ssl_sock;
1067 err = SSL_get_error(https_ssl, err);
1068 if (err == SSL_ERROR_WANT_READ)
1069 FD_SET(ssl_sock, &rd_set);
1070 else if (err == SSL_ERROR_WANT_WRITE)
1071 FD_SET(ssl_sock, &wr_set);
1073 vpn_progress(vpninfo, PRG_ERR, _("SSL connection failure\n"));
1074 openconnect_report_ssl_errors(vpninfo);
1075 SSL_free(https_ssl);
1080 if (vpninfo->cancel_fd != -1) {
1081 FD_SET(vpninfo->cancel_fd, &rd_set);
1082 if (vpninfo->cancel_fd > ssl_sock)
1083 maxfd = vpninfo->cancel_fd;
1085 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
1086 if (vpninfo->cancel_fd != -1 &&
1087 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
1088 vpn_progress(vpninfo, PRG_ERR, _("SSL connection cancelled\n"));
1089 SSL_free(https_ssl);
1095 if (verify_peer(vpninfo, https_ssl)) {
1096 SSL_free(https_ssl);
1101 vpninfo->ssl_fd = ssl_sock;
1102 vpninfo->https_ssl = https_ssl;
1104 /* Stash this now, because it might not be available later if the
1105 server has disconnected. */
1106 vpninfo->peer_cert = SSL_get_peer_certificate(vpninfo->https_ssl);
1108 vpn_progress(vpninfo, PRG_INFO, _("Connected to HTTPS on %s\n"),
1114 void openconnect_close_https(struct openconnect_info *vpninfo)
1116 if (vpninfo->peer_cert) {
1117 X509_free(vpninfo->peer_cert);
1118 vpninfo->peer_cert = NULL;
1120 if (vpninfo->https_ssl) {
1121 SSL_free(vpninfo->https_ssl);
1122 vpninfo->https_ssl = NULL;
1124 if (vpninfo->ssl_fd != -1) {
1125 close(vpninfo->ssl_fd);
1126 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds);
1127 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
1128 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds);
1129 vpninfo->ssl_fd = -1;
1133 void openconnect_init_openssl(void)
1135 SSL_library_init ();
1137 SSL_load_error_strings ();
1138 OpenSSL_add_all_algorithms ();
1141 char *openconnect_get_cert_details(struct openconnect_info *vpninfo,
1142 struct x509_st *cert)
1144 BIO *bp = BIO_new(BIO_s_mem());
1149 X509_print_ex(bp, cert, 0, 0);
1150 BIO_write(bp, &zero, 1);
1151 BIO_get_mem_ptr(bp, &certinfo);
1153 ret = strdup(certinfo->data);
1159 int openconnect_local_cert_md5(struct openconnect_info *vpninfo,
1164 if (!vpninfo->cert_x509)
1167 if (get_cert_md5_fingerprint(vpninfo, vpninfo->cert_x509, buf))