2 * OpenConnect (SSL + DTLS) VPN client
4 * Copyright © 2008-2010 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 <sys/types.h>
27 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 #if defined(__linux__)
38 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__APPLE__)
39 #include <sys/param.h>
40 #include <sys/mount.h>
41 #elif defined (__sun__) || defined(__NetBSD__) || defined(__DragonFly__)
42 #include <sys/statvfs.h>
45 #include <openssl/ssl.h>
46 #include <openssl/err.h>
47 #include <openssl/engine.h>
48 #include <openssl/evp.h>
49 #include <openssl/pkcs12.h>
50 #include <openssl/x509v3.h>
52 #include "openconnect-internal.h"
54 /* OSX < 1.6 doesn't have AI_NUMERICSERV */
55 #ifndef AI_NUMERICSERV
56 #define AI_NUMERICSERV 0
59 /* Helper functions for reading/writing lines over SSL.
60 We could use cURL for the HTTP stuff, but it's overkill */
62 int __attribute__ ((format (printf, 2, 3)))
63 openconnect_SSL_printf(SSL *ssl, const char *fmt, ...)
71 vsnprintf(buf, 1023, fmt, args);
73 return SSL_write(ssl, buf, strlen(buf));
77 static int print_err(const char *str, size_t len, void *ptr)
79 struct openconnect_info *vpninfo = ptr;
81 vpninfo->progress(vpninfo, PRG_ERR, "%s", str);
85 void report_ssl_errors(struct openconnect_info *vpninfo)
87 ERR_print_errors_cb(print_err, vpninfo);
90 int openconnect_SSL_gets(SSL *ssl, char *buf, size_t len)
98 while ( (ret = SSL_read(ssl, buf + i, 1)) == 1) {
101 if (i && buf[i-1] == '\r') {
115 ret = -SSL_get_error(ssl, ret);
121 static int pem_pw_cb(char *buf, int len, int w, void *v)
123 struct openconnect_info *vpninfo = v;
125 /* Only try the provided password once... */
126 SSL_CTX_set_default_passwd_cb(vpninfo->https_ctx, NULL);
127 SSL_CTX_set_default_passwd_cb_userdata(vpninfo->https_ctx, NULL);
129 if (len <= strlen(vpninfo->cert_password)) {
130 vpninfo->progress(vpninfo, PRG_ERR,
131 "PEM password too long (%zd >= %d)\n",
132 strlen(vpninfo->cert_password), len);
135 strcpy(buf, vpninfo->cert_password);
136 return strlen(vpninfo->cert_password);
139 static int load_pkcs12_certificate(struct openconnect_info *vpninfo, PKCS12 *p12)
141 EVP_PKEY *pkey = NULL;
145 char pass[PEM_BUFSIZE];
148 /* We do this every time round the loop, to work around a bug in
149 OpenSSL < 1.0.0-beta2 -- where the stack at *ca will be freed
150 when PKCS12_parse() returns an error, but *ca is left pointing
151 to the freed memory. */
153 if (!vpninfo->cert_password) {
154 if (EVP_read_pw_string(pass, PEM_BUFSIZE,
155 "Enter PKCS#12 pass phrase:", 0))
158 if (!PKCS12_parse(p12, vpninfo->cert_password?:pass, &pkey, &cert, &ca)) {
159 unsigned long err = ERR_peek_error();
161 report_ssl_errors(vpninfo);
163 if (ERR_GET_LIB(err) == ERR_LIB_PKCS12 &&
164 ERR_GET_FUNC(err) == PKCS12_F_PKCS12_PARSE &&
165 ERR_GET_REASON(err) == PKCS12_R_MAC_VERIFY_FAILURE) {
166 vpninfo->progress(vpninfo, PRG_ERR, "Parse PKCS#12 failed (wrong passphrase?)\n");
167 vpninfo->cert_password = NULL;
171 vpninfo->progress(vpninfo, PRG_ERR, "Parse PKCS#12 failed (see above errors)\n");
176 vpninfo->cert_x509 = cert;
177 SSL_CTX_use_certificate(vpninfo->https_ctx, cert);
179 vpninfo->progress(vpninfo, PRG_ERR,
180 "PKCS#12 contained no certificate!");
185 SSL_CTX_use_PrivateKey(vpninfo->https_ctx, pkey);
188 vpninfo->progress(vpninfo, PRG_ERR,
189 "PKCS#12 contained no private key!");
193 /* Only include supporting certificates which are actually necessary */
197 for (i = 0; i < sk_X509_num(ca); i++) {
198 X509 *cert2 = sk_X509_value(ca, i);
199 if (X509_check_issued(cert2, cert) == X509_V_OK) {
205 X509_NAME_oneline(X509_get_subject_name(cert2),
207 vpninfo->progress(vpninfo, PRG_DEBUG,
208 "Extra cert from PKCS#12: '%s'\n", buf);
209 CRYPTO_add(&cert2->references, 1, CRYPTO_LOCK_X509);
210 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert2);
215 sk_X509_pop_free(ca, X509_free);
222 static int load_tpm_certificate(struct openconnect_info *vpninfo)
226 ENGINE_load_builtin_engines();
228 e = ENGINE_by_id("tpm");
230 vpninfo->progress(vpninfo, PRG_ERR, "Can't load TPM engine.\n");
231 report_ssl_errors(vpninfo);
234 if (!ENGINE_init(e) || !ENGINE_set_default_RSA(e) ||
235 !ENGINE_set_default_RAND(e)) {
236 vpninfo->progress(vpninfo, PRG_ERR, "Failed to init TPM engine\n");
237 report_ssl_errors(vpninfo);
242 if (vpninfo->cert_password) {
243 if (!ENGINE_ctrl_cmd(e, "PIN", strlen(vpninfo->cert_password),
244 vpninfo->cert_password, NULL, 0)) {
245 vpninfo->progress(vpninfo, PRG_ERR, "Failed to set TPM SRK password\n");
246 report_ssl_errors(vpninfo);
249 key = ENGINE_load_private_key(e, vpninfo->sslkey, NULL, NULL);
251 vpninfo->progress(vpninfo, PRG_ERR,
252 "Failed to load TPM private key\n");
253 report_ssl_errors(vpninfo);
258 if (!SSL_CTX_use_PrivateKey(vpninfo->https_ctx, key)) {
259 vpninfo->progress(vpninfo, PRG_ERR, "Add key from TPM failed\n");
260 report_ssl_errors(vpninfo);
268 static int reload_pem_cert(struct openconnect_info *vpninfo)
270 BIO *b = BIO_new(BIO_s_file_internal());
275 if (BIO_read_filename(b, vpninfo->cert) <= 0) {
278 vpninfo->progress(vpninfo, PRG_ERR,
279 "Failed to reload X509 cert for expiry check\n");
280 report_ssl_errors(vpninfo);
283 vpninfo->cert_x509 = PEM_read_bio_X509_AUX(b, NULL, NULL, NULL);
284 if (!vpninfo->cert_x509)
290 static int load_certificate(struct openconnect_info *vpninfo)
292 vpninfo->progress(vpninfo, PRG_TRACE,
293 "Using certificate file %s\n", vpninfo->cert);
295 if (vpninfo->cert_type == CERT_TYPE_PKCS12 ||
296 vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
300 f = fopen(vpninfo->cert, "r");
302 vpninfo->progress(vpninfo, PRG_ERR,
303 "Failed to open certificate file %s: %s\n",
304 vpninfo->cert, strerror(errno));
307 p12 = d2i_PKCS12_fp(f, NULL);
310 return load_pkcs12_certificate(vpninfo, p12);
313 if (vpninfo->cert_type == CERT_TYPE_PKCS12) {
314 vpninfo->progress(vpninfo, PRG_ERR, "Read PKCS#12 failed\n");
315 report_ssl_errors(vpninfo);
318 /* Clear error and fall through to see if it's a PEM file... */
322 /* It's PEM or TPM now, and either way we need to load the plain cert: */
323 if (!SSL_CTX_use_certificate_chain_file(vpninfo->https_ctx,
325 vpninfo->progress(vpninfo, PRG_ERR,
326 "Loading certificate failed\n");
327 report_ssl_errors(vpninfo);
331 /* Ew, we can't get it back from the OpenSSL CTX in any sane fashion */
332 reload_pem_cert(vpninfo);
334 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
335 FILE *f = fopen(vpninfo->sslkey, "r");
339 vpninfo->progress(vpninfo, PRG_ERR,
340 "Failed to open private key file %s: %s\n",
341 vpninfo->cert, strerror(errno));
346 while (fgets(buf, 255, f)) {
347 if (!strcmp(buf, "-----BEGIN TSS KEY BLOB-----\n")) {
348 vpninfo->cert_type = CERT_TYPE_TPM;
350 } else if (!strcmp(buf, "-----BEGIN RSA PRIVATE KEY-----\n") ||
351 !strcmp(buf, "-----BEGIN DSA PRIVATE KEY-----\n") ||
352 !strcmp(buf, "-----BEGIN ENCRYPTED PRIVATE KEY-----\n")) {
353 vpninfo->cert_type = CERT_TYPE_PEM;
358 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
359 vpninfo->progress(vpninfo, PRG_ERR,
360 "Failed to identify private key type in '%s'\n",
366 if (vpninfo->cert_type == CERT_TYPE_TPM)
367 return load_tpm_certificate(vpninfo);
369 /* Standard PEM certificate */
370 if (vpninfo->cert_password) {
371 SSL_CTX_set_default_passwd_cb(vpninfo->https_ctx,
373 SSL_CTX_set_default_passwd_cb_userdata(vpninfo->https_ctx,
377 if (!SSL_CTX_use_RSAPrivateKey_file(vpninfo->https_ctx, vpninfo->sslkey,
379 unsigned long err = ERR_peek_error();
381 report_ssl_errors(vpninfo);
383 #ifndef EVP_F_EVP_DECRYPTFINAL_EX
384 #define EVP_F_EVP_DECRYPTFINAL_EX EVP_F_EVP_DECRYPTFINAL
386 /* If the user fat-fingered the passphrase, try again */
387 if (ERR_GET_LIB(err) == ERR_LIB_EVP &&
388 ERR_GET_FUNC(err) == EVP_F_EVP_DECRYPTFINAL_EX &&
389 ERR_GET_REASON(err) == EVP_R_BAD_DECRYPT) {
390 vpninfo->progress(vpninfo, PRG_ERR, "Loading private key failed (wrong passphrase?)\n");
394 vpninfo->progress(vpninfo, PRG_ERR, "Loading private key failed (see above errors)\n");
400 static int get_cert_fingerprint(struct openconnect_info *vpninfo,
401 X509 *cert, const EVP_MD *type,
404 unsigned char md[EVP_MAX_MD_SIZE];
407 if (!X509_digest(cert, type, md, &n))
410 for (i=0; i < n; i++)
411 sprintf(&buf[i*2], "%02X", md[i]);
416 int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
417 X509 *cert, char *buf)
419 return get_cert_fingerprint(vpninfo, cert, EVP_md5(), buf);
422 int get_cert_sha1_fingerprint(struct openconnect_info *vpninfo,
423 X509 *cert, char *buf)
425 return get_cert_fingerprint(vpninfo, cert, EVP_sha1(), buf);
428 static int check_server_cert(struct openconnect_info *vpninfo, X509 *cert)
430 char fingerprint[EVP_MAX_MD_SIZE * 2 + 1];
433 ret = get_cert_sha1_fingerprint(vpninfo, cert, fingerprint);
437 if (strcasecmp(vpninfo->servercert, fingerprint)) {
438 vpninfo->progress(vpninfo, PRG_ERR,
439 "Server SSL certificate didn't match: %s\n", fingerprint);
445 static int match_hostname_elem(const char *hostname, int helem_len,
446 const char *match, int melem_len)
448 if (!helem_len && !melem_len)
451 if (!helem_len || !melem_len)
455 if (match[0] == '*') {
458 for (i = 1 ; i <= helem_len; i++) {
459 if (!match_hostname_elem(hostname + i, helem_len - i,
460 match + 1, melem_len - 1))
466 if (toupper(hostname[0]) == toupper(match[0]))
467 return match_hostname_elem(hostname + 1, helem_len - 1,
468 match + 1, melem_len - 1);
473 static int match_hostname(const char *hostname, const char *match)
476 const char *h_dot, *m_dot;
477 int helem_len, melem_len;
479 h_dot = strchr(hostname, '.');
480 m_dot = strchr(match, '.');
482 if (h_dot && m_dot) {
483 helem_len = h_dot - hostname + 1;
484 melem_len = m_dot - match + 1;
485 } else if (!h_dot && !m_dot) {
486 helem_len = strlen(hostname);
487 melem_len = strlen(match);
492 if (match_hostname_elem(hostname, helem_len,
496 hostname += helem_len;
505 /* cf. RFC2818 and RFC2459 */
506 int match_cert_hostname(struct openconnect_info *vpninfo, X509 *peer_cert)
508 STACK_OF(GENERAL_NAME) *altnames;
510 ASN1_STRING *subjasn1;
511 char *subjstr = NULL;
514 char addrbuf[sizeof(struct in6_addr)];
517 /* Allow GEN_IP in the certificate only if we actually connected
518 by IP address rather than by name. */
519 if (inet_pton(AF_INET, vpninfo->hostname, addrbuf) > 0)
521 else if (inet_pton(AF_INET6, vpninfo->hostname, addrbuf) > 0)
523 else if (vpninfo->hostname[0] == '[' &&
524 vpninfo->hostname[strlen(vpninfo->hostname)-1] == ']') {
525 char *p = &vpninfo->hostname[strlen(vpninfo->hostname)-1];
527 if (inet_pton(AF_INET6, vpninfo->hostname + 1, addrbuf) > 0)
532 altnames = X509_get_ext_d2i(peer_cert, NID_subject_alt_name,
534 for (i = 0; i < sk_GENERAL_NAME_num(altnames); i++) {
535 const GENERAL_NAME *this = sk_GENERAL_NAME_value(altnames, i);
537 if (this->type == GEN_DNS) {
540 int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
546 /* We don't like names with embedded NUL */
547 if (strlen(str) != len)
550 if (!match_hostname(vpninfo->hostname, str)) {
551 vpninfo->progress(vpninfo, PRG_TRACE,
552 "Matched DNS altname '%s'\n",
554 GENERAL_NAMES_free(altnames);
558 vpninfo->progress(vpninfo, PRG_TRACE,
559 "No match for altname '%s'\n",
563 } else if (this->type == GEN_IPADD && addrlen) {
567 if (this->d.ip->length == 4) {
569 } else if (this->d.ip->length == 16) {
572 vpninfo->progress(vpninfo, PRG_ERR,
573 "Certificate has GEN_IPADD altname with bogus length %d\n",
578 /* We only do this for the debug messages */
579 inet_ntop(family, this->d.ip->data, host, sizeof(host));
581 if (this->d.ip->length == addrlen &&
582 !memcmp(addrbuf, this->d.ip->data, addrlen)) {
583 vpninfo->progress(vpninfo, PRG_TRACE,
584 "Matched IP%s address '%s'\n",
585 (family == AF_INET6)?"v6":"",
587 GENERAL_NAMES_free(altnames);
590 vpninfo->progress(vpninfo, PRG_TRACE,
591 "No match for IP%s address '%s'\n",
592 (family == AF_INET6)?"v6":"",
595 } else if (this->type == GEN_URI) {
597 char *url_proto, *url_host, *url_path, *url_host2;
599 int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
604 /* We don't like names with embedded NUL */
605 if (strlen(str) != len)
608 if (openconnect_parse_url(str, &url_proto, &url_host, &url_port, &url_path, 0)) {
613 if (!url_proto || strcasecmp(url_proto, "https"))
616 if (url_port != vpninfo->port)
619 /* Leave url_host as it was so that it can be freed */
620 url_host2 = url_host;
621 if (addrlen == 16 && vpninfo->hostname[0] != '[' &&
622 url_host[0] == '[' && url_host[strlen(url_host)-1] == ']') {
623 /* Cope with https://[IPv6]/ when the hostname is bare IPv6 */
624 url_host[strlen(url_host)-1] = 0;
628 if (strcasecmp(vpninfo->hostname, url_host2))
632 vpninfo->progress(vpninfo, PRG_TRACE, "URI '%s' has non-empty path; ignoring\n",
634 goto no_uri_match_silent;
636 vpninfo->progress(vpninfo, PRG_TRACE,
637 "Matched URI '%s'\n",
643 GENERAL_NAMES_free(altnames);
647 vpninfo->progress(vpninfo, PRG_TRACE,
648 "No match for URI '%s'\n",
657 GENERAL_NAMES_free(altnames);
659 /* According to RFC2818, we don't use the legacy subject name if
660 there was an altname with DNS type. */
662 vpninfo->progress(vpninfo, PRG_ERR, "No altname in peer cert matched '%s'\n",
667 subjname = X509_get_subject_name(peer_cert);
669 vpninfo->progress(vpninfo, PRG_ERR, "No subject name in peer cert!\n");
673 /* Find the _last_ (most specific) commonName */
676 int j = X509_NAME_get_index_by_NID(subjname, NID_commonName, i);
683 subjasn1 = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subjname, i));
685 i = ASN1_STRING_to_UTF8((void *)&subjstr, subjasn1);
687 if (!subjstr || strlen(subjstr) != i) {
688 vpninfo->progress(vpninfo, PRG_ERR,
689 "Failed to parse subject name in peer cert\n");
694 if (match_hostname(vpninfo->hostname, subjstr)) {
695 vpninfo->progress(vpninfo, PRG_ERR, "Peer cert subject mismatch ('%s' != '%s')\n",
696 subjstr, vpninfo->hostname);
699 vpninfo->progress(vpninfo, PRG_TRACE,
700 "Matched peer certificate subject name '%s'\n",
704 OPENSSL_free(subjstr);
708 static int verify_peer(struct openconnect_info *vpninfo, SSL *https_ssl)
713 peer_cert = SSL_get_peer_certificate(https_ssl);
715 if (vpninfo->servercert) {
716 /* If given a cert fingerprint on the command line, that's
718 ret = check_server_cert(vpninfo, peer_cert);
720 int vfy = SSL_get_verify_result(https_ssl);
721 const char *err_string = NULL;
723 if (vfy != X509_V_OK)
724 err_string = X509_verify_cert_error_string(vfy);
725 else if (match_cert_hostname(vpninfo, peer_cert))
726 err_string = "certificate does not match hostname";
729 vpninfo->progress(vpninfo, PRG_ERR,
730 "Server certificate verify failed: %s\n",
733 if (vpninfo->validate_peer_cert)
734 ret = vpninfo->validate_peer_cert(vpninfo, peer_cert,
742 X509_free(peer_cert);
747 static void workaround_openssl_certchain_bug(struct openconnect_info *vpninfo,
750 /* OpenSSL has problems with certificate chains -- if there are
751 multiple certs with the same name, it doesn't necessarily
752 choose the _right_ one. (RT#1942)
753 Pick the right ones for ourselves and add them manually. */
754 X509 *cert = SSL_get_certificate(ssl);
756 X509_STORE *store = SSL_CTX_get_cert_store(vpninfo->https_ctx);
762 /* If we already have 'supporting' certs, don't add them again */
763 if (vpninfo->https_ctx->extra_certs)
766 if (!X509_STORE_CTX_init(&ctx, store, NULL, NULL))
769 while (ctx.get_issuer(&cert2, &ctx, cert) == 1) {
774 X509_NAME_oneline(X509_get_subject_name(cert),
776 vpninfo->progress(vpninfo, PRG_DEBUG,
777 "Extra cert from cafile: '%s'\n", buf);
778 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert);
780 X509_STORE_CTX_cleanup(&ctx);
783 #if OPENSSL_VERSION_NUMBER >= 0x00908000
784 static int ssl_app_verify_callback(X509_STORE_CTX *ctx, void *arg)
786 /* We've seen certificates in the wild which don't have the
787 purpose fields filled in correctly */
788 X509_VERIFY_PARAM_set_purpose(ctx->param, X509_PURPOSE_ANY);
789 return X509_verify_cert(ctx);
793 static int check_certificate_expiry(struct openconnect_info *vpninfo)
799 if (!vpninfo->cert_x509)
803 notAfter = X509_get_notAfter(vpninfo->cert_x509);
804 i = X509_cmp_time(notAfter, &t);
806 vpninfo->progress(vpninfo, PRG_ERR, "Error in client cert notAfter field\n");
809 reason = "has expired";
812 i = X509_cmp_time(notAfter, &t);
814 reason = "expires soon";
818 BIO *bp = BIO_new(BIO_s_mem());
820 char *expiry = "<error>";
824 ASN1_TIME_print(bp, notAfter);
825 BIO_write(bp, &zero, 1);
826 BIO_get_mem_ptr(bp, &bm);
829 vpninfo->progress(vpninfo, PRG_ERR, "Client certificate %s at: %s\n",
837 int openconnect_open_https(struct openconnect_info *vpninfo)
839 method_const SSL_METHOD *ssl3_method;
848 if (vpninfo->peer_addr) {
849 ssl_sock = socket(vpninfo->peer_addr->sa_family, SOCK_STREAM, IPPROTO_IP);
852 vpninfo->progress(vpninfo, PRG_ERR, "Failed to reconnect to %s %s\n",
853 vpninfo->proxy?"proxy":"host",
854 vpninfo->proxy?:vpninfo->hostname);
857 if (connect(ssl_sock, vpninfo->peer_addr, vpninfo->peer_addrlen))
861 struct addrinfo hints, *result, *rp;
865 memset(&hints, 0, sizeof(struct addrinfo));
866 hints.ai_family = AF_UNSPEC;
867 hints.ai_socktype = SOCK_STREAM;
868 hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
869 hints.ai_protocol = 0;
870 hints.ai_canonname = NULL;
871 hints.ai_addr = NULL;
872 hints.ai_next = NULL;
874 /* The 'port' variable is a string because it's easier
875 this way than if we pass NULL to getaddrinfo() and
876 then try to fill in the numeric value into
877 different types of returned sockaddr_in{6,}. */
878 #ifdef OPENCONNECT_LIBPROXY
879 if (vpninfo->proxy_factory) {
884 free(vpninfo->proxy_type);
885 vpninfo->proxy_type = NULL;
886 free(vpninfo->proxy);
887 vpninfo->proxy = NULL;
889 if (vpninfo->port == 443)
890 i = asprintf(&url, "https://%s/%s", vpninfo->hostname,
891 vpninfo->urlpath?:"");
893 i = asprintf(&url, "https://%s:%d/%s", vpninfo->hostname,
894 vpninfo->port, vpninfo->urlpath?:"");
898 proxies = px_proxy_factory_get_proxies(vpninfo->proxy_factory,
901 while (proxies && proxies[i]) {
902 if (!vpninfo->proxy &&
903 (!strncmp(proxies[i], "http://", 7) ||
904 !strncmp(proxies[i], "socks://", 8) ||
905 !strncmp(proxies[i], "socks5://", 9)))
906 openconnect_parse_url(proxies[i], &vpninfo->proxy_type,
907 &vpninfo->proxy, &vpninfo->proxy_port,
914 vpninfo->progress(vpninfo, PRG_TRACE, "Proxy from libproxy: %s://%s:%d/\n",
915 vpninfo->proxy_type, vpninfo->proxy, vpninfo->port);
918 if (vpninfo->proxy) {
919 hostname = vpninfo->proxy;
920 snprintf(port, 6, "%d", vpninfo->proxy_port);
922 hostname = vpninfo->hostname;
923 snprintf(port, 6, "%d", vpninfo->port);
926 if (hostname[0] == '[' && hostname[strlen(hostname)-1] == ']') {
927 /* Solaris has no strndup(). */
928 int len = strlen(hostname) - 2;
929 char *new_hostname = malloc(len + 1);
932 memcpy(new_hostname, hostname + 1, len);
933 new_hostname[len] = 0;
935 hostname = new_hostname;
936 hints.ai_flags |= AI_NUMERICHOST;
939 err = getaddrinfo(hostname, port, &hints, &result);
940 if (hints.ai_flags & AI_NUMERICHOST)
944 vpninfo->progress(vpninfo, PRG_ERR, "getaddrinfo failed for host '%s': %s\n",
945 hostname, gai_strerror(err));
949 for (rp = result; rp ; rp = rp->ai_next) {
952 if (!getnameinfo(rp->ai_addr, rp->ai_addrlen, host,
953 sizeof(host), NULL, 0, NI_NUMERICHOST))
954 vpninfo->progress(vpninfo, PRG_INFO,
955 "Attempting to connect to %s%s%s:%s\n",
956 rp->ai_family == AF_INET6?"[":"",
958 rp->ai_family == AF_INET6?"]":"",
961 ssl_sock = socket(rp->ai_family, rp->ai_socktype,
965 if (connect(ssl_sock, rp->ai_addr, rp->ai_addrlen) >= 0) {
966 /* Store the peer address we actually used, so that DTLS can
967 use it again later */
968 vpninfo->peer_addr = malloc(rp->ai_addrlen);
969 if (!vpninfo->peer_addr) {
970 vpninfo->progress(vpninfo, PRG_ERR, "Failed to allocate sockaddr storage\n");
974 vpninfo->peer_addrlen = rp->ai_addrlen;
975 memcpy(vpninfo->peer_addr, rp->ai_addr, rp->ai_addrlen);
981 freeaddrinfo(result);
984 vpninfo->progress(vpninfo, PRG_ERR, "Failed to connect to host %s\n",
985 vpninfo->proxy?:vpninfo->hostname);
989 fcntl(ssl_sock, F_SETFD, FD_CLOEXEC);
991 if (vpninfo->proxy) {
992 err = process_proxy(vpninfo, ssl_sock);
999 ssl3_method = SSLv3_client_method();
1000 if (!vpninfo->https_ctx) {
1001 vpninfo->https_ctx = SSL_CTX_new(ssl3_method);
1003 if (vpninfo->cert) {
1004 err = load_certificate(vpninfo);
1006 vpninfo->progress(vpninfo, PRG_ERR,
1007 "Loading certificate failed. Aborting.\n");
1010 check_certificate_expiry(vpninfo);
1013 /* We just want to do:
1014 SSL_CTX_set_purpose(vpninfo->https_ctx, X509_PURPOSE_ANY);
1015 ... but it doesn't work with OpenSSL < 0.9.8k because of
1016 problems with inheritance (fixed in v1.1.4.6 of
1017 crypto/x509/x509_vpm.c) so we have to play silly buggers
1018 instead. This trick doesn't work _either_ in < 0.9.7 but
1019 I don't know of _any_ workaround which will, and can't
1020 be bothered to find out either. */
1021 #if OPENSSL_VERSION_NUMBER >= 0x00908000
1022 SSL_CTX_set_cert_verify_callback(vpninfo->https_ctx,
1023 ssl_app_verify_callback, NULL);
1025 SSL_CTX_set_default_verify_paths(vpninfo->https_ctx);
1027 if (vpninfo->cafile) {
1028 if (!SSL_CTX_load_verify_locations(vpninfo->https_ctx, vpninfo->cafile, NULL)) {
1029 vpninfo->progress(vpninfo, PRG_ERR, "Failed to open CA file '%s'\n",
1031 report_ssl_errors(vpninfo);
1038 https_ssl = SSL_new(vpninfo->https_ctx);
1039 workaround_openssl_certchain_bug(vpninfo, https_ssl);
1041 https_bio = BIO_new_socket(ssl_sock, BIO_NOCLOSE);
1042 SSL_set_bio(https_ssl, https_bio, https_bio);
1044 vpninfo->progress(vpninfo, PRG_INFO,
1045 "SSL negotiation with %s\n", vpninfo->hostname);
1047 if (SSL_connect(https_ssl) <= 0) {
1048 vpninfo->progress(vpninfo, PRG_ERR, "SSL connection failure\n");
1049 report_ssl_errors(vpninfo);
1050 SSL_free(https_ssl);
1055 if (verify_peer(vpninfo, https_ssl)) {
1056 SSL_free(https_ssl);
1061 vpninfo->ssl_fd = ssl_sock;
1062 vpninfo->https_ssl = https_ssl;
1064 vpninfo->progress(vpninfo, PRG_INFO,
1065 "Connected to HTTPS on %s\n", vpninfo->hostname);
1070 void openconnect_close_https(struct openconnect_info *vpninfo)
1072 SSL_free(vpninfo->https_ssl);
1073 vpninfo->https_ssl = NULL;
1074 close(vpninfo->ssl_fd);
1075 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds);
1076 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
1077 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds);
1078 vpninfo->ssl_fd = -1;
1081 void openconnect_init_openssl(void)
1083 SSL_library_init ();
1085 SSL_load_error_strings ();
1086 OpenSSL_add_all_algorithms ();
1089 #if defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__)
1090 int openconnect_passphrase_from_fsid(struct openconnect_info *vpninfo)
1094 if (statvfs(vpninfo->sslkey, &buf)) {
1096 vpninfo->progress(vpninfo, PRG_ERR, "statvfs: %s\n", strerror(errno));
1099 if (asprintf(&vpninfo->cert_password, "%lx", buf.f_fsid))
1104 int openconnect_passphrase_from_fsid(struct openconnect_info *vpninfo)
1107 unsigned *fsid = (unsigned *)&buf.f_fsid;
1108 unsigned long long fsid64;
1110 if (statfs(vpninfo->sslkey, &buf)) {
1112 vpninfo->progress(vpninfo, PRG_ERR, "statfs: %s\n", strerror(errno));
1115 fsid64 = ((unsigned long long)fsid[0] << 32) | fsid[1];
1117 if (asprintf(&vpninfo->cert_password, "%llx", fsid64))