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.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 enum cert_hash_type {
405 static int get_cert_fingerprint(struct openconnect_info *vpninfo,
406 X509 *cert, enum cert_hash_type hash,
409 unsigned char md[EVP_MAX_MD_SIZE];
414 if (!X509_digest(cert, EVP_md5(), md, &n))
418 if (!X509_digest(cert, EVP_sha1(), md, &n))
422 vpninfo->progress(vpninfo, PRG_ERR,
423 "Unsupported SSL certificate hash function type\n");
426 for (i=0; i < n; i++) {
427 sprintf(&buf[i*2], "%02X", md[i]);
432 int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
433 X509 *cert, char *buf)
435 return get_cert_fingerprint(vpninfo, cert, EVP_MD5, buf);
438 int get_cert_sha1_fingerprint(struct openconnect_info *vpninfo,
439 X509 *cert, char *buf)
441 return get_cert_fingerprint(vpninfo, cert, EVP_SHA1, buf);
444 static int check_server_cert(struct openconnect_info *vpninfo, X509 *cert)
446 char fingerprint[EVP_MAX_MD_SIZE * 2 + 1];
449 ret = get_cert_sha1_fingerprint(vpninfo, cert, fingerprint);
453 if (strcasecmp(vpninfo->servercert, fingerprint)) {
454 vpninfo->progress(vpninfo, PRG_ERR,
455 "Server SSL certificate didn't match: %s\n", fingerprint);
461 static int match_hostname_elem(const char *hostname, int helem_len,
462 const char *match, int melem_len)
464 if (!helem_len && !melem_len)
467 if (!helem_len || !melem_len)
471 if (match[0] == '*') {
474 for (i = 1 ; i <= helem_len; i++) {
475 if (!match_hostname_elem(hostname + i, helem_len - i,
476 match + 1, melem_len - 1))
482 if (toupper(hostname[0]) == toupper(match[0]))
483 return match_hostname_elem(hostname + 1, helem_len - 1,
484 match + 1, melem_len - 1);
489 static int match_hostname(const char *hostname, const char *match)
492 const char *h_dot, *m_dot;
493 int helem_len, melem_len;
495 h_dot = strchr(hostname, '.');
496 m_dot = strchr(match, '.');
498 if (h_dot && m_dot) {
499 helem_len = h_dot - hostname + 1;
500 melem_len = m_dot - match + 1;
501 } else if (!h_dot && !m_dot) {
502 helem_len = strlen(hostname);
503 melem_len = strlen(match);
508 if (match_hostname_elem(hostname, helem_len,
512 hostname += helem_len;
521 /* cf. RFC2818 and RFC2459 */
522 int match_cert_hostname(struct openconnect_info *vpninfo, X509 *peer_cert)
524 STACK_OF(GENERAL_NAME) *altnames;
526 ASN1_STRING *subjasn1;
527 char *subjstr = NULL;
530 char addrbuf[sizeof(struct in6_addr)];
533 /* Allow GEN_IP in the certificate only if we actually connected
534 by IP address rather than by name. */
535 if (inet_pton(AF_INET, vpninfo->hostname, addrbuf) > 0)
537 else if (inet_pton(AF_INET6, vpninfo->hostname, addrbuf) > 0)
539 else if (vpninfo->hostname[0] == '[' &&
540 vpninfo->hostname[strlen(vpninfo->hostname)-1] == ']') {
541 char *p = &vpninfo->hostname[strlen(vpninfo->hostname)-1];
543 if (inet_pton(AF_INET6, vpninfo->hostname + 1, addrbuf) > 0)
548 altnames = X509_get_ext_d2i(peer_cert, NID_subject_alt_name,
550 for (i = 0; i < sk_GENERAL_NAME_num(altnames); i++) {
551 const GENERAL_NAME *this = sk_GENERAL_NAME_value(altnames, i);
553 if (this->type == GEN_DNS) {
556 int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
562 /* We don't like names with embedded NUL */
563 if (strlen(str) != len)
566 if (!match_hostname(vpninfo->hostname, str)) {
567 vpninfo->progress(vpninfo, PRG_TRACE,
568 "Matched DNS altname '%s'\n",
570 GENERAL_NAMES_free(altnames);
574 vpninfo->progress(vpninfo, PRG_TRACE,
575 "No match for altname '%s'\n",
579 } else if (this->type == GEN_IPADD && addrlen) {
583 if (this->d.ip->length == 4) {
585 } else if (this->d.ip->length == 16) {
588 vpninfo->progress(vpninfo, PRG_ERR,
589 "Certificate has GEN_IPADD altname with bogus length %d\n",
594 /* We only do this for the debug messages */
595 inet_ntop(family, this->d.ip->data, host, sizeof(host));
597 if (this->d.ip->length == addrlen &&
598 !memcmp(addrbuf, this->d.ip->data, addrlen)) {
599 vpninfo->progress(vpninfo, PRG_TRACE,
600 "Matched IP%s address '%s'\n",
601 (family == AF_INET6)?"v6":"",
603 GENERAL_NAMES_free(altnames);
606 vpninfo->progress(vpninfo, PRG_TRACE,
607 "No match for IP%s address '%s'\n",
608 (family == AF_INET6)?"v6":"",
611 } else if (this->type == GEN_URI) {
613 char *url_proto, *url_host, *url_path, *url_host2;
615 int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
620 /* We don't like names with embedded NUL */
621 if (strlen(str) != len)
624 if (parse_url(str, &url_proto, &url_host, &url_port, &url_path, 0)) {
629 if (!url_proto || strcasecmp(url_proto, "https"))
632 if (url_port != vpninfo->port)
635 /* Leave url_host as it was so that it can be freed */
636 url_host2 = url_host;
637 if (addrlen == 16 && vpninfo->hostname[0] != '[' &&
638 url_host[0] == '[' && url_host[strlen(url_host)-1] == ']') {
639 /* Cope with https://[IPv6]/ when the hostname is bare IPv6 */
640 url_host[strlen(url_host)-1] = 0;
644 if (strcasecmp(vpninfo->hostname, url_host2))
648 vpninfo->progress(vpninfo, PRG_TRACE, "URI '%s' has non-empty path; ignoring\n",
650 goto no_uri_match_silent;
652 vpninfo->progress(vpninfo, PRG_TRACE,
653 "Matched URI '%s'\n",
659 GENERAL_NAMES_free(altnames);
663 vpninfo->progress(vpninfo, PRG_TRACE,
664 "No match for URI '%s'\n",
673 GENERAL_NAMES_free(altnames);
675 /* According to RFC2818, we don't use the legacy subject name if
676 there was an altname with DNS type. */
678 vpninfo->progress(vpninfo, PRG_ERR, "No altname in peer cert matched '%s'\n",
683 subjname = X509_get_subject_name(peer_cert);
685 vpninfo->progress(vpninfo, PRG_ERR, "No subject name in peer cert!\n");
689 /* Find the _last_ (most specific) commonName */
692 int j = X509_NAME_get_index_by_NID(subjname, NID_commonName, i);
699 subjasn1 = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subjname, i));
701 i = ASN1_STRING_to_UTF8((void *)&subjstr, subjasn1);
703 if (!subjstr || strlen(subjstr) != i) {
704 vpninfo->progress(vpninfo, PRG_ERR,
705 "Failed to parse subject name in peer cert\n");
710 if (match_hostname(vpninfo->hostname, subjstr)) {
711 vpninfo->progress(vpninfo, PRG_ERR, "Peer cert subject mismatch ('%s' != '%s')\n",
712 subjstr, vpninfo->hostname);
715 vpninfo->progress(vpninfo, PRG_TRACE,
716 "Matched peer certificate subject name '%s'\n",
720 OPENSSL_free(subjstr);
724 static int verify_peer(struct openconnect_info *vpninfo, SSL *https_ssl)
729 peer_cert = SSL_get_peer_certificate(https_ssl);
731 if (vpninfo->servercert) {
732 /* If given a cert fingerprint on the command line, that's
734 ret = check_server_cert(vpninfo, peer_cert);
736 int vfy = SSL_get_verify_result(https_ssl);
737 const char *err_string = NULL;
739 if (vfy != X509_V_OK)
740 err_string = X509_verify_cert_error_string(vfy);
741 else if (match_cert_hostname(vpninfo, peer_cert))
742 err_string = "certificate does not match hostname";
745 vpninfo->progress(vpninfo, PRG_ERR,
746 "Server certificate verify failed: %s\n",
749 if (vpninfo->validate_peer_cert)
750 ret = vpninfo->validate_peer_cert(vpninfo, peer_cert,
758 X509_free(peer_cert);
763 static void workaround_openssl_certchain_bug(struct openconnect_info *vpninfo,
766 /* OpenSSL has problems with certificate chains -- if there are
767 multiple certs with the same name, it doesn't necessarily
768 choose the _right_ one. (RT#1942)
769 Pick the right ones for ourselves and add them manually. */
770 X509 *cert = SSL_get_certificate(ssl);
772 X509_STORE *store = SSL_CTX_get_cert_store(vpninfo->https_ctx);
778 /* If we already have 'supporting' certs, don't add them again */
779 if (vpninfo->https_ctx->extra_certs)
782 if (!X509_STORE_CTX_init(&ctx, store, NULL, NULL))
785 while (ctx.get_issuer(&cert2, &ctx, cert) == 1) {
790 X509_NAME_oneline(X509_get_subject_name(cert),
792 vpninfo->progress(vpninfo, PRG_DEBUG,
793 "Extra cert from cafile: '%s'\n", buf);
794 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert);
796 X509_STORE_CTX_cleanup(&ctx);
799 #if OPENSSL_VERSION_NUMBER >= 0x00908000
800 static int ssl_app_verify_callback(X509_STORE_CTX *ctx, void *arg)
802 /* We've seen certificates in the wild which don't have the
803 purpose fields filled in correctly */
804 X509_VERIFY_PARAM_set_purpose(ctx->param, X509_PURPOSE_ANY);
805 return X509_verify_cert(ctx);
809 static int check_certificate_expiry(struct openconnect_info *vpninfo)
815 if (!vpninfo->cert_x509)
819 notAfter = X509_get_notAfter(vpninfo->cert_x509);
820 i = X509_cmp_time(notAfter, &t);
822 vpninfo->progress(vpninfo, PRG_ERR, "Error in client cert notAfter field\n");
825 reason = "has expired";
828 i = X509_cmp_time(notAfter, &t);
830 reason = "expires soon";
834 BIO *bp = BIO_new(BIO_s_mem());
836 char *expiry = "<error>";
840 ASN1_TIME_print(bp, notAfter);
841 BIO_write(bp, &zero, 1);
842 BIO_get_mem_ptr(bp, &bm);
845 vpninfo->progress(vpninfo, PRG_ERR, "Client certificate %s at: %s\n",
853 int openconnect_open_https(struct openconnect_info *vpninfo)
855 method_const SSL_METHOD *ssl3_method;
864 if (vpninfo->peer_addr) {
865 ssl_sock = socket(vpninfo->peer_addr->sa_family, SOCK_STREAM, IPPROTO_IP);
868 vpninfo->progress(vpninfo, PRG_ERR, "Failed to reconnect to %s %s\n",
869 vpninfo->proxy?"proxy":"host",
870 vpninfo->proxy?:vpninfo->hostname);
873 if (connect(ssl_sock, vpninfo->peer_addr, vpninfo->peer_addrlen))
877 struct addrinfo hints, *result, *rp;
881 memset(&hints, 0, sizeof(struct addrinfo));
882 hints.ai_family = AF_UNSPEC;
883 hints.ai_socktype = SOCK_STREAM;
884 hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
885 hints.ai_protocol = 0;
886 hints.ai_canonname = NULL;
887 hints.ai_addr = NULL;
888 hints.ai_next = NULL;
890 /* The 'port' variable is a string because it's easier
891 this way than if we pass NULL to getaddrinfo() and
892 then try to fill in the numeric value into
893 different types of returned sockaddr_in{6,}. */
894 #ifdef OPENCONNECT_LIBPROXY
895 if (vpninfo->proxy_factory) {
900 free(vpninfo->proxy_type);
901 vpninfo->proxy_type = NULL;
902 free(vpninfo->proxy);
903 vpninfo->proxy = NULL;
905 if (vpninfo->port == 443)
906 i = asprintf(&url, "https://%s/%s", vpninfo->hostname,
907 vpninfo->urlpath?:"");
909 i = asprintf(&url, "https://%s:%d/%s", vpninfo->hostname,
910 vpninfo->port, vpninfo->urlpath?:"");
914 proxies = px_proxy_factory_get_proxies(vpninfo->proxy_factory,
917 while (proxies && proxies[i]) {
918 if (!vpninfo->proxy &&
919 (!strncmp(proxies[i], "http://", 7) ||
920 !strncmp(proxies[i], "socks://", 8) ||
921 !strncmp(proxies[i], "socks5://", 9)))
922 parse_url(proxies[i], &vpninfo->proxy_type,
923 &vpninfo->proxy, &vpninfo->proxy_port,
930 vpninfo->progress(vpninfo, PRG_TRACE, "Proxy from libproxy: %s://%s:%d/\n",
931 vpninfo->proxy_type, vpninfo->proxy, vpninfo->port);
934 if (vpninfo->proxy) {
935 hostname = vpninfo->proxy;
936 snprintf(port, 6, "%d", vpninfo->proxy_port);
938 hostname = vpninfo->hostname;
939 snprintf(port, 6, "%d", vpninfo->port);
942 if (hostname[0] == '[' && hostname[strlen(hostname)-1] == ']') {
943 /* Solaris has no strndup(). */
944 int len = strlen(hostname) - 2;
945 char *new_hostname = malloc(len + 1);
948 memcpy(new_hostname, hostname + 1, len);
949 new_hostname[len] = 0;
951 hostname = new_hostname;
952 hints.ai_flags |= AI_NUMERICHOST;
955 err = getaddrinfo(hostname, port, &hints, &result);
956 if (hints.ai_flags & AI_NUMERICHOST)
960 vpninfo->progress(vpninfo, PRG_ERR, "getaddrinfo failed for host '%s': %s\n",
961 hostname, gai_strerror(err));
965 for (rp = result; rp ; rp = rp->ai_next) {
968 if (!getnameinfo(rp->ai_addr, rp->ai_addrlen, host,
969 sizeof(host), NULL, 0, NI_NUMERICHOST))
970 vpninfo->progress(vpninfo, PRG_INFO,
971 "Attempting to connect to %s%s%s:%s\n",
972 rp->ai_family == AF_INET6?"[":"",
974 rp->ai_family == AF_INET6?"]":"",
977 ssl_sock = socket(rp->ai_family, rp->ai_socktype,
981 if (connect(ssl_sock, rp->ai_addr, rp->ai_addrlen) >= 0) {
982 /* Store the peer address we actually used, so that DTLS can
983 use it again later */
984 vpninfo->peer_addr = malloc(rp->ai_addrlen);
985 if (!vpninfo->peer_addr) {
986 vpninfo->progress(vpninfo, PRG_ERR, "Failed to allocate sockaddr storage\n");
990 vpninfo->peer_addrlen = rp->ai_addrlen;
991 memcpy(vpninfo->peer_addr, rp->ai_addr, rp->ai_addrlen);
997 freeaddrinfo(result);
1000 vpninfo->progress(vpninfo, PRG_ERR, "Failed to connect to host %s\n",
1001 vpninfo->proxy?:vpninfo->hostname);
1005 fcntl(ssl_sock, F_SETFD, FD_CLOEXEC);
1007 if (vpninfo->proxy) {
1008 err = process_proxy(vpninfo, ssl_sock);
1015 ssl3_method = SSLv3_client_method();
1016 if (!vpninfo->https_ctx) {
1017 vpninfo->https_ctx = SSL_CTX_new(ssl3_method);
1019 if (vpninfo->cert) {
1020 err = load_certificate(vpninfo);
1022 vpninfo->progress(vpninfo, PRG_ERR,
1023 "Loading certificate failed. Aborting.\n");
1026 check_certificate_expiry(vpninfo);
1029 /* We just want to do:
1030 SSL_CTX_set_purpose(vpninfo->https_ctx, X509_PURPOSE_ANY);
1031 ... but it doesn't work with OpenSSL < 0.9.8k because of
1032 problems with inheritance (fixed in v1.1.4.6 of
1033 crypto/x509/x509_vpm.c) so we have to play silly buggers
1034 instead. This trick doesn't work _either_ in < 0.9.7 but
1035 I don't know of _any_ workaround which will, and can't
1036 be bothered to find out either. */
1037 #if OPENSSL_VERSION_NUMBER >= 0x00908000
1038 SSL_CTX_set_cert_verify_callback(vpninfo->https_ctx,
1039 ssl_app_verify_callback, NULL);
1041 SSL_CTX_set_default_verify_paths(vpninfo->https_ctx);
1043 if (vpninfo->cafile)
1044 SSL_CTX_load_verify_locations(vpninfo->https_ctx, vpninfo->cafile, NULL);
1047 https_ssl = SSL_new(vpninfo->https_ctx);
1048 workaround_openssl_certchain_bug(vpninfo, https_ssl);
1050 https_bio = BIO_new_socket(ssl_sock, BIO_NOCLOSE);
1051 SSL_set_bio(https_ssl, https_bio, https_bio);
1053 vpninfo->progress(vpninfo, PRG_INFO,
1054 "SSL negotiation with %s\n", vpninfo->hostname);
1056 if (SSL_connect(https_ssl) <= 0) {
1057 vpninfo->progress(vpninfo, PRG_ERR, "SSL connection failure\n");
1058 report_ssl_errors(vpninfo);
1059 SSL_free(https_ssl);
1064 if (verify_peer(vpninfo, https_ssl)) {
1065 SSL_free(https_ssl);
1070 vpninfo->ssl_fd = ssl_sock;
1071 vpninfo->https_ssl = https_ssl;
1073 vpninfo->progress(vpninfo, PRG_INFO,
1074 "Connected to HTTPS on %s\n", vpninfo->hostname);
1079 void openconnect_close_https(struct openconnect_info *vpninfo)
1081 SSL_free(vpninfo->https_ssl);
1082 vpninfo->https_ssl = NULL;
1083 close(vpninfo->ssl_fd);
1084 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds);
1085 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
1086 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds);
1087 vpninfo->ssl_fd = -1;
1090 void openconnect_init_openssl(void)
1092 SSL_library_init ();
1094 SSL_load_error_strings ();
1095 OpenSSL_add_all_algorithms ();
1098 #if defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__)
1099 int passphrase_from_fsid(struct openconnect_info *vpninfo)
1103 if (statvfs(vpninfo->sslkey, &buf)) {
1105 vpninfo->progress(vpninfo, PRG_ERR, "statvfs: %s\n", strerror(errno));
1108 if (asprintf(&vpninfo->cert_password, "%lx", buf.f_fsid))
1113 int passphrase_from_fsid(struct openconnect_info *vpninfo)
1116 unsigned *fsid = (unsigned *)&buf.f_fsid;
1117 unsigned long long fsid64;
1119 if (statfs(vpninfo->sslkey, &buf)) {
1121 vpninfo->progress(vpninfo, PRG_ERR, "statfs: %s\n", strerror(errno));
1124 fsid64 = ((unsigned long long)fsid[0] << 32) | fsid[1];
1126 if (asprintf(&vpninfo->cert_password, "%llx", fsid64))