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"));
240 /* UI handling. All this just to handle the PIN callback from the TPM ENGINE,
241 and turn it into a call to our ->process_auth_form function */
244 struct openconnect_info *vpninfo;
245 struct oc_form_opt **last_opt;
246 struct oc_auth_form form;
250 struct oc_form_opt opt;
254 /* Ick. But there is no way to pass this sanely through OpenSSL */
255 static struct openconnect_info *ui_vpninfo;
257 static int ui_open(UI *ui)
259 struct openconnect_info *vpninfo = ui_vpninfo; /* Ick */
260 struct ui_data *ui_data;
262 if (!vpninfo || !vpninfo->process_auth_form)
265 ui_data = malloc(sizeof(*ui_data));
269 memset(ui_data, 0, sizeof(*ui_data));
270 ui_data->last_opt = &ui_data->form.opts;
271 ui_data->vpninfo = vpninfo;
272 UI_add_user_data(ui, ui_data);
277 static int ui_write(UI *ui, UI_STRING *uis)
279 struct ui_data *ui_data = UI_get0_user_data(ui);
280 struct ui_form_opt *opt;
282 switch(UI_get_string_type(uis)) {
284 ui_data->form.error = (char *)UI_get0_output_string(uis);
287 ui_data->form.message = (char *)UI_get0_output_string(uis);
290 opt = malloc(sizeof(*opt));
293 memset(opt, 0, sizeof(*opt));
295 opt->opt.label = opt->opt.name = (char *)UI_get0_output_string(uis);
296 if (UI_get_input_flags(uis) & UI_INPUT_FLAG_ECHO)
297 opt->opt.type = OC_FORM_OPT_TEXT;
299 opt->opt.type = OC_FORM_OPT_PASSWORD;
300 *(ui_data->last_opt) = &opt->opt;
301 ui_data->last_opt = &opt->opt.next;
305 fprintf(stderr, "Unhandled SSL UI request type %d\n",
306 UI_get_string_type(uis));
312 static int ui_flush(UI *ui)
314 struct ui_data *ui_data = UI_get0_user_data(ui);
315 struct openconnect_info *vpninfo = ui_data->vpninfo;
316 struct ui_form_opt *opt;
319 ret = vpninfo->process_auth_form(vpninfo, &ui_data->form);
323 for (opt = (struct ui_form_opt *)ui_data->form.opts; opt;
324 opt = (struct ui_form_opt *)opt->opt.next) {
325 if (opt->opt.value && opt->uis)
326 UI_set_result(ui, opt->uis, opt->opt.value);
331 static int ui_close(UI *ui)
333 struct ui_data *ui_data = UI_get0_user_data(ui);
334 struct ui_form_opt *opt, *next_opt;
336 opt = (struct ui_form_opt *)ui_data->form.opts;
338 next_opt = (struct ui_form_opt *)opt->opt.next;
340 free(opt->opt.value);
345 UI_add_user_data(ui, NULL);
350 static UI_METHOD *create_openssl_ui(struct openconnect_info *vpninfo)
352 UI_METHOD *ui_method = UI_create_method((char *)"AnyConnect VPN UI");
354 /* There is a race condition here because of the use of the
355 static ui_vpninfo pointer. This sucks, but it's OpenSSL's
356 fault and in practice it's *never* going to hurt us.
358 This UI is only used for loading certificates from a TPM; for
359 PKCS#12 and PEM files we hook the passphrase request differently.
360 The ui_vpninfo variable is set here, and is used from ui_open()
361 when the TPM ENGINE decides it needs to ask the user for a PIN.
363 The race condition exists because theoretically, there
364 could be more than one thread using libopenconnect and
365 trying to authenticate to a VPN server, within the *same*
366 process. And if *both* are using certificates from the TPM,
367 and *both* manage to be within that short window of time
368 between setting ui_vpninfo and invoking ui_open() to fetch
369 the PIN, then one connection's ->process_auth_form() could
370 get a PIN request for the *other* connection.
372 However, the only thing that ever does run libopenconnect more
373 than once from the same process is KDE's NetworkManager support,
374 and NetworkManager doesn't *support* having more than one VPN
375 connected anyway, so first that would have to be fixed and then
376 you'd have to connect to two VPNs simultaneously by clicking
377 'connect' on both at *exactly* the same time and then getting
380 Oh, and the KDE support won't be using OpenSSL anyway because of
381 licensing conflicts... so although this sucks, I'm not going to
384 ui_vpninfo = vpninfo;
386 /* Set up a UI method of our own for password/passphrase requests */
387 UI_method_set_opener(ui_method, ui_open);
388 UI_method_set_writer(ui_method, ui_write);
389 UI_method_set_flusher(ui_method, ui_flush);
390 UI_method_set_closer(ui_method, ui_close);
395 static int pem_pw_cb(char *buf, int len, int w, void *v)
397 struct openconnect_info *vpninfo = v;
401 if (vpninfo->cert_password) {
402 pass = vpninfo->cert_password;
403 vpninfo->cert_password = NULL;
404 } else if (request_passphrase(vpninfo, &pass,
405 _("Enter PEM pass phrase:")))
411 vpn_progress(vpninfo, PRG_ERR,
412 _("PEM password too long (%d >= %d)\n"),
418 memcpy(buf, pass, plen+1);
423 static int load_pkcs12_certificate(struct openconnect_info *vpninfo, PKCS12 *p12)
425 EVP_PKEY *pkey = NULL;
431 pass = vpninfo->cert_password;
432 vpninfo->cert_password = NULL;
434 /* We do this every time round the loop, to work around a bug in
435 OpenSSL < 1.0.0-beta2 -- where the stack at *ca will be freed
436 when PKCS12_parse() returns an error, but *ca is left pointing
437 to the freed memory. */
439 if (!pass && request_passphrase(vpninfo, &pass,
440 _("Enter PKCS#12 pass phrase:")) < 0) {
444 if (!PKCS12_parse(p12, pass, &pkey, &cert, &ca)) {
445 unsigned long err = ERR_peek_error();
447 openconnect_report_ssl_errors(vpninfo);
449 if (ERR_GET_LIB(err) == ERR_LIB_PKCS12 &&
450 ERR_GET_FUNC(err) == PKCS12_F_PKCS12_PARSE &&
451 ERR_GET_REASON(err) == PKCS12_R_MAC_VERIFY_FAILURE) {
452 vpn_progress(vpninfo, PRG_ERR,
453 _("Parse PKCS#12 failed (wrong passphrase?)\n"));
459 vpn_progress(vpninfo, PRG_ERR,
460 _("Parse PKCS#12 failed (see above errors)\n"));
465 vpninfo->cert_x509 = cert;
466 SSL_CTX_use_certificate(vpninfo->https_ctx, cert);
468 vpn_progress(vpninfo, PRG_ERR,
469 _("PKCS#12 contained no certificate!"));
474 SSL_CTX_use_PrivateKey(vpninfo->https_ctx, pkey);
477 vpn_progress(vpninfo, PRG_ERR,
478 _("PKCS#12 contained no private key!"));
482 /* Only include supporting certificates which are actually necessary */
486 for (i = 0; i < sk_X509_num(ca); i++) {
487 X509 *cert2 = sk_X509_value(ca, i);
488 if (X509_check_issued(cert2, cert) == X509_V_OK) {
493 if (X509_check_issued(cert2, cert2) == X509_V_OK)
496 X509_NAME_oneline(X509_get_subject_name(cert2),
498 vpn_progress(vpninfo, PRG_DEBUG,
499 _("Extra cert from PKCS#12: '%s'\n"), buf);
500 CRYPTO_add(&cert2->references, 1, CRYPTO_LOCK_X509);
501 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert2);
506 sk_X509_pop_free(ca, X509_free);
514 static int load_tpm_certificate(struct openconnect_info *vpninfo)
518 UI_METHOD *meth = NULL;
519 ENGINE_load_builtin_engines();
521 e = ENGINE_by_id("tpm");
523 vpn_progress(vpninfo, PRG_ERR, _("Can't load TPM engine.\n"));
524 openconnect_report_ssl_errors(vpninfo);
527 if (!ENGINE_init(e) || !ENGINE_set_default_RSA(e) ||
528 !ENGINE_set_default_RAND(e)) {
529 vpn_progress(vpninfo, PRG_ERR, _("Failed to init TPM engine\n"));
530 openconnect_report_ssl_errors(vpninfo);
535 if (vpninfo->cert_password) {
536 if (!ENGINE_ctrl_cmd(e, "PIN", strlen(vpninfo->cert_password),
537 vpninfo->cert_password, NULL, 0)) {
538 vpn_progress(vpninfo, PRG_ERR,
539 _("Failed to set TPM SRK password\n"));
540 openconnect_report_ssl_errors(vpninfo);
543 /* Provide our own UI method to handle the PIN callback. */
544 meth = create_openssl_ui(vpninfo);
546 key = ENGINE_load_private_key(e, vpninfo->sslkey, meth, NULL);
548 UI_destroy_method(meth);
550 vpn_progress(vpninfo, PRG_ERR,
551 _("Failed to load TPM private key\n"));
552 openconnect_report_ssl_errors(vpninfo);
557 if (!SSL_CTX_use_PrivateKey(vpninfo->https_ctx, key)) {
558 vpn_progress(vpninfo, PRG_ERR, _("Add key from TPM failed\n"));
559 openconnect_report_ssl_errors(vpninfo);
567 static int load_tpm_certificate(struct openconnect_info *vpninfo)
569 vpn_progress(vpninfo, PRG_ERR,
570 _("This version of OpenConnect was built without TPM support\n"));
575 static int reload_pem_cert(struct openconnect_info *vpninfo)
577 BIO *b = BIO_new(BIO_s_file_internal());
582 if (BIO_read_filename(b, vpninfo->cert) <= 0) {
585 vpn_progress(vpninfo, PRG_ERR,
586 _("Failed to reload X509 cert for expiry check\n"));
587 openconnect_report_ssl_errors(vpninfo);
590 vpninfo->cert_x509 = PEM_read_bio_X509_AUX(b, NULL, NULL, NULL);
591 if (!vpninfo->cert_x509)
597 static int load_certificate(struct openconnect_info *vpninfo)
599 vpn_progress(vpninfo, PRG_TRACE,
600 _("Using certificate file %s\n"), vpninfo->cert);
602 if (vpninfo->cert_type == CERT_TYPE_PKCS12 ||
603 vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
607 f = fopen(vpninfo->cert, "r");
609 vpn_progress(vpninfo, PRG_ERR,
610 _("Failed to open certificate file %s: %s\n"),
611 vpninfo->cert, strerror(errno));
614 p12 = d2i_PKCS12_fp(f, NULL);
617 return load_pkcs12_certificate(vpninfo, p12);
620 if (vpninfo->cert_type == CERT_TYPE_PKCS12) {
621 vpn_progress(vpninfo, PRG_ERR, _("Read PKCS#12 failed\n"));
622 openconnect_report_ssl_errors(vpninfo);
625 /* Clear error and fall through to see if it's a PEM file... */
629 /* It's PEM or TPM now, and either way we need to load the plain cert: */
630 if (!SSL_CTX_use_certificate_chain_file(vpninfo->https_ctx,
632 vpn_progress(vpninfo, PRG_ERR,
633 _("Loading certificate failed\n"));
634 openconnect_report_ssl_errors(vpninfo);
638 /* Ew, we can't get it back from the OpenSSL CTX in any sane fashion */
639 reload_pem_cert(vpninfo);
641 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
642 FILE *f = fopen(vpninfo->sslkey, "r");
646 vpn_progress(vpninfo, PRG_ERR,
647 _("Failed to open private key file %s: %s\n"),
648 vpninfo->cert, strerror(errno));
653 while (fgets(buf, 255, f)) {
654 if (!strcmp(buf, "-----BEGIN TSS KEY BLOB-----\n")) {
655 vpninfo->cert_type = CERT_TYPE_TPM;
657 } else if (!strcmp(buf, "-----BEGIN RSA PRIVATE KEY-----\n") ||
658 !strcmp(buf, "-----BEGIN DSA PRIVATE KEY-----\n") ||
659 !strcmp(buf, "-----BEGIN ENCRYPTED PRIVATE KEY-----\n")) {
660 vpninfo->cert_type = CERT_TYPE_PEM;
665 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
666 vpn_progress(vpninfo, PRG_ERR,
667 _("Failed to identify private key type in '%s'\n"),
673 if (vpninfo->cert_type == CERT_TYPE_TPM)
674 return load_tpm_certificate(vpninfo);
676 /* Standard PEM certificate */
677 SSL_CTX_set_default_passwd_cb(vpninfo->https_ctx, pem_pw_cb);
678 SSL_CTX_set_default_passwd_cb_userdata(vpninfo->https_ctx, vpninfo);
680 if (!SSL_CTX_use_RSAPrivateKey_file(vpninfo->https_ctx, vpninfo->sslkey,
682 unsigned long err = ERR_peek_error();
684 openconnect_report_ssl_errors(vpninfo);
686 #ifndef EVP_F_EVP_DECRYPTFINAL_EX
687 #define EVP_F_EVP_DECRYPTFINAL_EX EVP_F_EVP_DECRYPTFINAL
689 /* If the user fat-fingered the passphrase, try again */
690 if (ERR_GET_LIB(err) == ERR_LIB_EVP &&
691 ERR_GET_FUNC(err) == EVP_F_EVP_DECRYPTFINAL_EX &&
692 ERR_GET_REASON(err) == EVP_R_BAD_DECRYPT) {
693 vpn_progress(vpninfo, PRG_ERR,
694 _("Loading private key failed (wrong passphrase?)\n"));
698 vpn_progress(vpninfo, PRG_ERR,
699 _("Loading private key failed (see above errors)\n"));
705 static int get_cert_fingerprint(struct openconnect_info *vpninfo,
706 X509 *cert, const EVP_MD *type,
709 unsigned char md[EVP_MAX_MD_SIZE];
712 if (!X509_digest(cert, type, md, &n))
715 for (i=0; i < n; i++)
716 sprintf(&buf[i*2], "%02X", md[i]);
721 int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
722 X509 *cert, char *buf)
724 return get_cert_fingerprint(vpninfo, cert, EVP_md5(), buf);
727 int openconnect_get_cert_sha1(struct openconnect_info *vpninfo,
728 X509 *cert, char *buf)
730 return get_cert_fingerprint(vpninfo, cert, EVP_sha1(), buf);
733 static int check_server_cert(struct openconnect_info *vpninfo, X509 *cert)
735 char fingerprint[EVP_MAX_MD_SIZE * 2 + 1];
738 ret = openconnect_get_cert_sha1(vpninfo, cert, fingerprint);
742 if (strcasecmp(vpninfo->servercert, fingerprint)) {
743 vpn_progress(vpninfo, PRG_ERR,
744 _("Server SSL certificate didn't match: %s\n"), fingerprint);
750 static int match_hostname_elem(const char *hostname, int helem_len,
751 const char *match, int melem_len)
753 if (!helem_len && !melem_len)
756 if (!helem_len || !melem_len)
760 if (match[0] == '*') {
763 for (i = 1 ; i <= helem_len; i++) {
764 if (!match_hostname_elem(hostname + i, helem_len - i,
765 match + 1, melem_len - 1))
771 /* From the NetBSD (5.1) man page for ctype(3):
772 Values of type char or signed char must first be cast to unsigned char,
773 to ensure that the values are within the correct range. The result
774 should then be cast to int to avoid warnings from some compilers.
775 We do indeed get warning "array subscript has type 'char'" without
777 if (toupper((int)(unsigned char)hostname[0]) ==
778 toupper((int)(unsigned char)match[0]))
779 return match_hostname_elem(hostname + 1, helem_len - 1,
780 match + 1, melem_len - 1);
785 static int match_hostname(const char *hostname, const char *match)
788 const char *h_dot, *m_dot;
789 int helem_len, melem_len;
791 h_dot = strchr(hostname, '.');
792 m_dot = strchr(match, '.');
794 if (h_dot && m_dot) {
795 helem_len = h_dot - hostname + 1;
796 melem_len = m_dot - match + 1;
797 } else if (!h_dot && !m_dot) {
798 helem_len = strlen(hostname);
799 melem_len = strlen(match);
804 if (match_hostname_elem(hostname, helem_len,
808 hostname += helem_len;
817 /* cf. RFC2818 and RFC2459 */
818 static int match_cert_hostname(struct openconnect_info *vpninfo, X509 *peer_cert)
820 STACK_OF(GENERAL_NAME) *altnames;
822 ASN1_STRING *subjasn1;
823 char *subjstr = NULL;
826 char addrbuf[sizeof(struct in6_addr)];
829 /* Allow GEN_IP in the certificate only if we actually connected
830 by IP address rather than by name. */
831 if (inet_pton(AF_INET, vpninfo->hostname, addrbuf) > 0)
833 else if (inet_pton(AF_INET6, vpninfo->hostname, addrbuf) > 0)
835 else if (vpninfo->hostname[0] == '[' &&
836 vpninfo->hostname[strlen(vpninfo->hostname)-1] == ']') {
837 char *p = &vpninfo->hostname[strlen(vpninfo->hostname)-1];
839 if (inet_pton(AF_INET6, vpninfo->hostname + 1, addrbuf) > 0)
844 altnames = X509_get_ext_d2i(peer_cert, NID_subject_alt_name,
846 for (i = 0; i < sk_GENERAL_NAME_num(altnames); i++) {
847 const GENERAL_NAME *this = sk_GENERAL_NAME_value(altnames, i);
849 if (this->type == GEN_DNS) {
852 int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
858 /* We don't like names with embedded NUL */
859 if (strlen(str) != len)
862 if (!match_hostname(vpninfo->hostname, str)) {
863 vpn_progress(vpninfo, PRG_TRACE,
864 _("Matched DNS altname '%s'\n"),
866 GENERAL_NAMES_free(altnames);
870 vpn_progress(vpninfo, PRG_TRACE,
871 _("No match for altname '%s'\n"),
875 } else if (this->type == GEN_IPADD && addrlen) {
879 if (this->d.ip->length == 4) {
881 } else if (this->d.ip->length == 16) {
884 vpn_progress(vpninfo, PRG_ERR,
885 _("Certificate has GEN_IPADD altname with bogus length %d\n"),
890 /* We only do this for the debug messages */
891 inet_ntop(family, this->d.ip->data, host, sizeof(host));
893 if (this->d.ip->length == addrlen &&
894 !memcmp(addrbuf, this->d.ip->data, addrlen)) {
895 vpn_progress(vpninfo, PRG_TRACE,
896 _("Matched %s address '%s'\n"),
897 (family == AF_INET6)?"IPv6":"IPv4",
899 GENERAL_NAMES_free(altnames);
902 vpn_progress(vpninfo, PRG_TRACE,
903 _("No match for %s address '%s'\n"),
904 (family == AF_INET6)?"IPv6":"IPv4",
907 } else if (this->type == GEN_URI) {
909 char *url_proto, *url_host, *url_path, *url_host2;
911 int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
916 /* We don't like names with embedded NUL */
917 if (strlen(str) != len)
920 if (internal_parse_url(str, &url_proto, &url_host, &url_port, &url_path, 0)) {
925 if (!url_proto || strcasecmp(url_proto, "https"))
928 if (url_port != vpninfo->port)
931 /* Leave url_host as it was so that it can be freed */
932 url_host2 = url_host;
933 if (addrlen == 16 && vpninfo->hostname[0] != '[' &&
934 url_host[0] == '[' && url_host[strlen(url_host)-1] == ']') {
935 /* Cope with https://[IPv6]/ when the hostname is bare IPv6 */
936 url_host[strlen(url_host)-1] = 0;
940 if (strcasecmp(vpninfo->hostname, url_host2))
944 vpn_progress(vpninfo, PRG_TRACE,
945 _("URI '%s' has non-empty path; ignoring\n"),
947 goto no_uri_match_silent;
949 vpn_progress(vpninfo, PRG_TRACE,
950 _("Matched URI '%s'\n"),
956 GENERAL_NAMES_free(altnames);
960 vpn_progress(vpninfo, PRG_TRACE,
961 _("No match for URI '%s'\n"),
970 GENERAL_NAMES_free(altnames);
972 /* According to RFC2818, we don't use the legacy subject name if
973 there was an altname with DNS type. */
975 vpn_progress(vpninfo, PRG_ERR,
976 _("No altname in peer cert matched '%s'\n"),
981 subjname = X509_get_subject_name(peer_cert);
983 vpn_progress(vpninfo, PRG_ERR,
984 _("No subject name in peer cert!\n"));
988 /* Find the _last_ (most specific) commonName */
991 int j = X509_NAME_get_index_by_NID(subjname, NID_commonName, i);
998 subjasn1 = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subjname, i));
1000 i = ASN1_STRING_to_UTF8((void *)&subjstr, subjasn1);
1002 if (!subjstr || strlen(subjstr) != i) {
1003 vpn_progress(vpninfo, PRG_ERR,
1004 _("Failed to parse subject name in peer cert\n"));
1009 if (match_hostname(vpninfo->hostname, subjstr)) {
1010 vpn_progress(vpninfo, PRG_ERR,
1011 _("Peer cert subject mismatch ('%s' != '%s')\n"),
1012 subjstr, vpninfo->hostname);
1015 vpn_progress(vpninfo, PRG_TRACE,
1016 _("Matched peer certificate subject name '%s'\n"),
1020 OPENSSL_free(subjstr);
1024 static int verify_peer(struct openconnect_info *vpninfo, SSL *https_ssl)
1029 peer_cert = SSL_get_peer_certificate(https_ssl);
1031 if (vpninfo->servercert) {
1032 /* If given a cert fingerprint on the command line, that's
1034 ret = check_server_cert(vpninfo, peer_cert);
1036 int vfy = SSL_get_verify_result(https_ssl);
1037 const char *err_string = NULL;
1039 if (vfy != X509_V_OK)
1040 err_string = X509_verify_cert_error_string(vfy);
1041 else if (match_cert_hostname(vpninfo, peer_cert))
1042 err_string = _("certificate does not match hostname");
1045 vpn_progress(vpninfo, PRG_INFO,
1046 _("Server certificate verify failed: %s\n"),
1049 if (vpninfo->validate_peer_cert)
1050 ret = vpninfo->validate_peer_cert(vpninfo->cbdata,
1059 X509_free(peer_cert);
1064 static void workaround_openssl_certchain_bug(struct openconnect_info *vpninfo,
1067 /* OpenSSL has problems with certificate chains -- if there are
1068 multiple certs with the same name, it doesn't necessarily
1069 choose the _right_ one. (RT#1942)
1070 Pick the right ones for ourselves and add them manually. */
1071 X509 *cert = SSL_get_certificate(ssl);
1073 X509_STORE *store = SSL_CTX_get_cert_store(vpninfo->https_ctx);
1076 if (!cert || !store)
1079 /* If we already have 'supporting' certs, don't add them again */
1080 if (vpninfo->https_ctx->extra_certs)
1083 if (!X509_STORE_CTX_init(&ctx, store, NULL, NULL))
1086 while (ctx.get_issuer(&cert2, &ctx, cert) == 1) {
1090 if (X509_check_issued(cert2, cert2) == X509_V_OK)
1093 X509_NAME_oneline(X509_get_subject_name(cert),
1095 vpn_progress(vpninfo, PRG_DEBUG,
1096 _("Extra cert from cafile: '%s'\n"), buf);
1097 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert);
1099 X509_STORE_CTX_cleanup(&ctx);
1102 #if OPENSSL_VERSION_NUMBER >= 0x00908000
1103 static int ssl_app_verify_callback(X509_STORE_CTX *ctx, void *arg)
1105 /* We've seen certificates in the wild which don't have the
1106 purpose fields filled in correctly */
1107 X509_VERIFY_PARAM_set_purpose(ctx->param, X509_PURPOSE_ANY);
1108 return X509_verify_cert(ctx);
1112 static int check_certificate_expiry(struct openconnect_info *vpninfo)
1114 ASN1_TIME *notAfter;
1115 const char *reason = NULL;
1119 if (!vpninfo->cert_x509)
1123 notAfter = X509_get_notAfter(vpninfo->cert_x509);
1124 i = X509_cmp_time(notAfter, &t);
1126 vpn_progress(vpninfo, PRG_ERR,
1127 _("Error in client cert notAfter field\n"));
1130 reason = _("Client certificate has expired at");
1132 t += vpninfo->cert_expire_warning;
1133 i = X509_cmp_time(notAfter, &t);
1135 reason = _("Client certificate expires soon at");
1139 BIO *bp = BIO_new(BIO_s_mem());
1141 const char *expiry = _("<error>");
1145 ASN1_TIME_print(bp, notAfter);
1146 BIO_write(bp, &zero, 1);
1147 BIO_get_mem_ptr(bp, &bm);
1150 vpn_progress(vpninfo, PRG_ERR, "%s: %s\n", reason, expiry);
1156 int openconnect_open_https(struct openconnect_info *vpninfo)
1158 method_const SSL_METHOD *ssl3_method;
1164 if (vpninfo->https_ssl)
1167 if (vpninfo->peer_cert) {
1168 X509_free(vpninfo->peer_cert);
1169 vpninfo->peer_cert = NULL;
1172 ssl_sock = connect_https_socket(vpninfo);
1176 ssl3_method = TLSv1_client_method();
1177 if (!vpninfo->https_ctx) {
1178 vpninfo->https_ctx = SSL_CTX_new(ssl3_method);
1180 /* Some servers (or their firewalls) really don't like seeing
1182 #ifdef SSL_OP_NO_TICKET
1183 SSL_CTX_set_options (vpninfo->https_ctx, SSL_OP_NO_TICKET);
1186 if (vpninfo->cert) {
1187 err = load_certificate(vpninfo);
1189 vpn_progress(vpninfo, PRG_ERR,
1190 _("Loading certificate failed. Aborting.\n"));
1193 check_certificate_expiry(vpninfo);
1196 /* We just want to do:
1197 SSL_CTX_set_purpose(vpninfo->https_ctx, X509_PURPOSE_ANY);
1198 ... but it doesn't work with OpenSSL < 0.9.8k because of
1199 problems with inheritance (fixed in v1.1.4.6 of
1200 crypto/x509/x509_vpm.c) so we have to play silly buggers
1201 instead. This trick doesn't work _either_ in < 0.9.7 but
1202 I don't know of _any_ workaround which will, and can't
1203 be bothered to find out either. */
1204 #if OPENSSL_VERSION_NUMBER >= 0x00908000
1205 SSL_CTX_set_cert_verify_callback(vpninfo->https_ctx,
1206 ssl_app_verify_callback, NULL);
1208 SSL_CTX_set_default_verify_paths(vpninfo->https_ctx);
1210 if (vpninfo->cafile) {
1211 if (!SSL_CTX_load_verify_locations(vpninfo->https_ctx, vpninfo->cafile, NULL)) {
1212 vpn_progress(vpninfo, PRG_ERR,
1213 _("Failed to open CA file '%s'\n"),
1215 openconnect_report_ssl_errors(vpninfo);
1222 https_ssl = SSL_new(vpninfo->https_ctx);
1223 workaround_openssl_certchain_bug(vpninfo, https_ssl);
1225 https_bio = BIO_new_socket(ssl_sock, BIO_NOCLOSE);
1226 BIO_set_nbio(https_bio, 1);
1227 SSL_set_bio(https_ssl, https_bio, https_bio);
1229 vpn_progress(vpninfo, PRG_INFO, _("SSL negotiation with %s\n"),
1232 while ((err = SSL_connect(https_ssl)) <= 0) {
1233 fd_set wr_set, rd_set;
1234 int maxfd = ssl_sock;
1239 err = SSL_get_error(https_ssl, err);
1240 if (err == SSL_ERROR_WANT_READ)
1241 FD_SET(ssl_sock, &rd_set);
1242 else if (err == SSL_ERROR_WANT_WRITE)
1243 FD_SET(ssl_sock, &wr_set);
1245 vpn_progress(vpninfo, PRG_ERR, _("SSL connection failure\n"));
1246 openconnect_report_ssl_errors(vpninfo);
1247 SSL_free(https_ssl);
1252 if (vpninfo->cancel_fd != -1) {
1253 FD_SET(vpninfo->cancel_fd, &rd_set);
1254 if (vpninfo->cancel_fd > ssl_sock)
1255 maxfd = vpninfo->cancel_fd;
1257 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
1258 if (vpninfo->cancel_fd != -1 &&
1259 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
1260 vpn_progress(vpninfo, PRG_ERR, _("SSL connection cancelled\n"));
1261 SSL_free(https_ssl);
1267 if (verify_peer(vpninfo, https_ssl)) {
1268 SSL_free(https_ssl);
1273 vpninfo->ssl_fd = ssl_sock;
1274 vpninfo->https_ssl = https_ssl;
1276 /* Stash this now, because it might not be available later if the
1277 server has disconnected. */
1278 vpninfo->peer_cert = SSL_get_peer_certificate(vpninfo->https_ssl);
1280 vpn_progress(vpninfo, PRG_INFO, _("Connected to HTTPS on %s\n"),
1286 void openconnect_close_https(struct openconnect_info *vpninfo)
1288 if (vpninfo->peer_cert) {
1289 X509_free(vpninfo->peer_cert);
1290 vpninfo->peer_cert = NULL;
1292 if (vpninfo->https_ssl) {
1293 SSL_free(vpninfo->https_ssl);
1294 vpninfo->https_ssl = NULL;
1296 if (vpninfo->ssl_fd != -1) {
1297 close(vpninfo->ssl_fd);
1298 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds);
1299 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
1300 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds);
1301 vpninfo->ssl_fd = -1;
1305 void openconnect_init_openssl(void)
1307 SSL_library_init ();
1309 SSL_load_error_strings ();
1310 OpenSSL_add_all_algorithms ();
1313 char *openconnect_get_cert_details(struct openconnect_info *vpninfo,
1314 struct x509_st *cert)
1316 BIO *bp = BIO_new(BIO_s_mem());
1321 X509_print_ex(bp, cert, 0, 0);
1322 BIO_write(bp, &zero, 1);
1323 BIO_get_mem_ptr(bp, &certinfo);
1325 ret = strdup(certinfo->data);
1331 int openconnect_local_cert_md5(struct openconnect_info *vpninfo,
1336 if (!vpninfo->cert_x509)
1339 if (get_cert_md5_fingerprint(vpninfo, vpninfo->cert_x509, buf))