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 #if defined(__linux__)
37 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__APPLE__)
38 #include <sys/param.h>
39 #include <sys/mount.h>
40 #elif defined (__sun__) || defined(__NetBSD__) || defined(__DragonFly__)
41 #include <sys/statvfs.h>
44 #include <openssl/ssl.h>
45 #include <openssl/err.h>
46 #include <openssl/engine.h>
47 #include <openssl/evp.h>
48 #include <openssl/pkcs12.h>
49 #include <openssl/x509v3.h>
51 #include "openconnect.h"
53 /* OSX < 1.6 doesn't have AI_NUMERICSERV */
54 #ifndef AI_NUMERICSERV
55 #define AI_NUMERICSERV 0
58 /* Helper functions for reading/writing lines over SSL.
59 We could use cURL for the HTTP stuff, but it's overkill */
61 int __attribute__ ((format (printf, 2, 3)))
62 openconnect_SSL_printf(SSL *ssl, const char *fmt, ...)
70 vsnprintf(buf, 1023, fmt, args);
72 return SSL_write(ssl, buf, strlen(buf));
76 static int print_err(const char *str, size_t len, void *ptr)
78 struct openconnect_info *vpninfo = ptr;
80 vpninfo->progress(vpninfo, PRG_ERR, "%s", str);
84 void report_ssl_errors(struct openconnect_info *vpninfo)
86 ERR_print_errors_cb(print_err, vpninfo);
89 int openconnect_SSL_gets(SSL *ssl, char *buf, size_t len)
97 while ( (ret = SSL_read(ssl, buf + i, 1)) == 1) {
100 if (i && buf[i-1] == '\r') {
114 ret = -SSL_get_error(ssl, ret);
120 static int pem_pw_cb(char *buf, int len, int w, void *v)
122 struct openconnect_info *vpninfo = v;
124 /* Only try the provided password once... */
125 SSL_CTX_set_default_passwd_cb(vpninfo->https_ctx, NULL);
126 SSL_CTX_set_default_passwd_cb_userdata(vpninfo->https_ctx, NULL);
128 if (len <= strlen(vpninfo->cert_password)) {
129 vpninfo->progress(vpninfo, PRG_ERR,
130 "PEM password too long (%zd >= %d)\n",
131 strlen(vpninfo->cert_password), len);
134 strcpy(buf, vpninfo->cert_password);
135 return strlen(vpninfo->cert_password);
138 static int load_pkcs12_certificate(struct openconnect_info *vpninfo, PKCS12 *p12)
140 EVP_PKEY *pkey = NULL;
142 STACK_OF(X509) *ca = sk_X509_new_null();
144 char pass[PEM_BUFSIZE];
147 if (!vpninfo->cert_password) {
148 if (EVP_read_pw_string(pass, PEM_BUFSIZE,
149 "Enter PKCS#12 pass phrase:", 0))
152 if (!PKCS12_parse(p12, vpninfo->cert_password?:pass, &pkey, &cert, &ca)) {
153 unsigned long err = ERR_peek_error();
155 report_ssl_errors(vpninfo);
157 if (ERR_GET_LIB(err) == ERR_LIB_PKCS12 &&
158 ERR_GET_FUNC(err) == PKCS12_F_PKCS12_PARSE &&
159 ERR_GET_REASON(err) == PKCS12_R_MAC_VERIFY_FAILURE) {
160 vpninfo->progress(vpninfo, PRG_ERR, "Parse PKCS#12 failed (wrong passphrase?)\n");
161 vpninfo->cert_password = NULL;
162 #if OPENSSL_VERSION_NUMBER < 0x10000002
163 /* Older versions of OpenSSL screw the ca stack up
164 and will SEGV if you attempt to free (or reuse) it.
165 So allocate a new one, and live with the memory leak. */
166 ca = sk_X509_new_null();
171 vpninfo->progress(vpninfo, PRG_ERR, "Parse PKCS#12 failed (see above errors)\n");
176 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 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert2);
221 static int load_tpm_certificate(struct openconnect_info *vpninfo)
225 ENGINE_load_builtin_engines();
227 e = ENGINE_by_id("tpm");
229 vpninfo->progress(vpninfo, PRG_ERR, "Can't load TPM engine.\n");
230 report_ssl_errors(vpninfo);
233 if (!ENGINE_init(e) || !ENGINE_set_default_RSA(e) ||
234 !ENGINE_set_default_RAND(e)) {
235 vpninfo->progress(vpninfo, PRG_ERR, "Failed to init TPM engine\n");
236 report_ssl_errors(vpninfo);
241 if (vpninfo->cert_password) {
242 if (!ENGINE_ctrl_cmd(e, "PIN", strlen(vpninfo->cert_password),
243 vpninfo->cert_password, NULL, 0)) {
244 vpninfo->progress(vpninfo, PRG_ERR, "Failed to set TPM SRK password\n");
245 report_ssl_errors(vpninfo);
248 key = ENGINE_load_private_key(e, vpninfo->sslkey, NULL, NULL);
250 vpninfo->progress(vpninfo, PRG_ERR,
251 "Failed to load TPM private key\n");
252 report_ssl_errors(vpninfo);
257 if (!SSL_CTX_use_PrivateKey(vpninfo->https_ctx, key)) {
258 vpninfo->progress(vpninfo, PRG_ERR, "Add key from TPM failed\n");
259 report_ssl_errors(vpninfo);
267 static int load_certificate(struct openconnect_info *vpninfo)
269 vpninfo->progress(vpninfo, PRG_TRACE,
270 "Using certificate file %s\n", vpninfo->cert);
272 if (vpninfo->cert_type == CERT_TYPE_PKCS12 ||
273 vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
277 f = fopen(vpninfo->cert, "r");
279 vpninfo->progress(vpninfo, PRG_ERR,
280 "Failed to open certificate file %s: %s\n",
281 vpninfo->cert, strerror(errno));
284 p12 = d2i_PKCS12_fp(f, NULL);
287 return load_pkcs12_certificate(vpninfo, p12);
290 if (vpninfo->cert_type == CERT_TYPE_PKCS12) {
291 vpninfo->progress(vpninfo, PRG_ERR, "Read PKCS#12 failed\n");
292 report_ssl_errors(vpninfo);
295 /* Clear error and fall through to see if it's a PEM file... */
299 /* It's PEM or TPM now, and either way we need to load the plain cert: */
300 if (!SSL_CTX_use_certificate_chain_file(vpninfo->https_ctx,
302 vpninfo->progress(vpninfo, PRG_ERR,
303 "Loading certificate failed\n");
304 report_ssl_errors(vpninfo);
308 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
309 FILE *f = fopen(vpninfo->sslkey, "r");
313 vpninfo->progress(vpninfo, PRG_ERR,
314 "Failed to open private key file %s: %s\n",
315 vpninfo->cert, strerror(errno));
320 while (fgets(buf, 255, f)) {
321 if (!strcmp(buf, "-----BEGIN TSS KEY BLOB-----\n")) {
322 vpninfo->cert_type = CERT_TYPE_TPM;
324 } else if (!strcmp(buf, "-----BEGIN RSA PRIVATE KEY-----\n") ||
325 !strcmp(buf, "-----BEGIN DSA PRIVATE KEY-----\n") ||
326 !strcmp(buf, "-----BEGIN ENCRYPTED PRIVATE KEY-----\n")) {
327 vpninfo->cert_type = CERT_TYPE_PEM;
332 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
333 vpninfo->progress(vpninfo, PRG_ERR,
334 "Failed to identify private key type in '%s'\n",
340 if (vpninfo->cert_type == CERT_TYPE_TPM)
341 return load_tpm_certificate(vpninfo);
343 /* Standard PEM certificate */
344 if (vpninfo->cert_password) {
345 SSL_CTX_set_default_passwd_cb(vpninfo->https_ctx,
347 SSL_CTX_set_default_passwd_cb_userdata(vpninfo->https_ctx,
351 if (!SSL_CTX_use_RSAPrivateKey_file(vpninfo->https_ctx, vpninfo->sslkey,
353 unsigned long err = ERR_peek_error();
355 report_ssl_errors(vpninfo);
357 #ifndef EVP_F_EVP_DECRYPTFINAL_EX
358 #define EVP_F_EVP_DECRYPTFINAL_EX EVP_F_EVP_DECRYPTFINAL
360 /* If the user fat-fingered the passphrase, try again */
361 if (ERR_GET_LIB(err) == ERR_LIB_EVP &&
362 ERR_GET_FUNC(err) == EVP_F_EVP_DECRYPTFINAL_EX &&
363 ERR_GET_REASON(err) == EVP_R_BAD_DECRYPT) {
364 vpninfo->progress(vpninfo, PRG_ERR, "Loading private key failed (wrong passphrase?)\n");
368 vpninfo->progress(vpninfo, PRG_ERR, "Loading private key failed (see above errors)\n");
374 enum cert_hash_type {
379 static int get_cert_fingerprint(struct openconnect_info *vpninfo,
380 X509 *cert, enum cert_hash_type hash,
383 unsigned char md[EVP_MAX_MD_SIZE];
388 if (!X509_digest(cert, EVP_md5(), md, &n))
392 if (!X509_digest(cert, EVP_sha1(), md, &n))
396 vpninfo->progress(vpninfo, PRG_ERR,
397 "Unsupported SSL certificate hash function type\n");
400 for (i=0; i < n; i++) {
401 sprintf(&buf[i*2], "%02X", md[i]);
406 int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
407 X509 *cert, char *buf)
409 return get_cert_fingerprint(vpninfo, cert, EVP_MD5, buf);
412 int get_cert_sha1_fingerprint(struct openconnect_info *vpninfo,
413 X509 *cert, char *buf)
415 return get_cert_fingerprint(vpninfo, cert, EVP_SHA1, buf);
418 static int check_server_cert(struct openconnect_info *vpninfo, X509 *cert)
420 char fingerprint[EVP_MAX_MD_SIZE * 2 + 1];
423 ret = get_cert_sha1_fingerprint(vpninfo, cert, fingerprint);
427 if (strcasecmp(vpninfo->servercert, fingerprint)) {
428 vpninfo->progress(vpninfo, PRG_ERR,
429 "Server SSL certificate didn't match: %s\n", fingerprint);
435 static int verify_peer(struct openconnect_info *vpninfo, SSL *https_ssl)
439 if (vpninfo->cafile) {
440 int vfy = SSL_get_verify_result(https_ssl);
442 if (vfy != X509_V_OK) {
443 vpninfo->progress(vpninfo, PRG_ERR, "Server certificate verify failed: %s\n",
444 X509_verify_cert_error_string(vfy));
450 peer_cert = SSL_get_peer_certificate(https_ssl);
452 if (vpninfo->servercert)
453 return check_server_cert(vpninfo, peer_cert);
455 if (vpninfo->validate_peer_cert)
456 return vpninfo->validate_peer_cert(vpninfo, peer_cert);
458 /* If no validation function, just let it succeed */
462 static void workaround_openssl_certchain_bug(struct openconnect_info *vpninfo,
465 /* OpenSSL has problems with certificate chains -- if there are
466 multiple certs with the same name, it doesn't necessarily
467 choose the _right_ one. (RT#1942)
468 Pick the right ones for ourselves and add them manually. */
469 X509 *cert = SSL_get_certificate(ssl);
471 X509_STORE *store = SSL_CTX_get_cert_store(vpninfo->https_ctx);
477 /* If we already have 'supporting' certs, don't add them again */
478 if (vpninfo->https_ctx->extra_certs)
481 if (!X509_STORE_CTX_init(&ctx, store, NULL, NULL))
484 while (ctx.get_issuer(&cert2, &ctx, cert) == 1) {
489 X509_NAME_oneline(X509_get_subject_name(cert),
491 vpninfo->progress(vpninfo, PRG_DEBUG,
492 "Extra cert from cafile: '%s'\n", buf);
493 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert);
495 X509_STORE_CTX_cleanup(&ctx);
498 #if OPENSSL_VERSION_NUMBER >= 0x00908000
499 static int ssl_app_verify_callback(X509_STORE_CTX *ctx, void *arg)
501 /* We've seen certificates in the wild which don't have the
502 purpose fields filled in correctly */
503 X509_VERIFY_PARAM_set_purpose(ctx->param, X509_PURPOSE_ANY);
504 return X509_verify_cert(ctx);
508 int openconnect_open_https(struct openconnect_info *vpninfo)
510 method_const SSL_METHOD *ssl3_method;
519 if (vpninfo->peer_addr) {
520 ssl_sock = socket(vpninfo->peer_addr->sa_family, SOCK_STREAM, IPPROTO_IP);
523 vpninfo->progress(vpninfo, PRG_ERR, "Failed to reconnect to %s %s\n",
524 vpninfo->proxy?"proxy":"host",
525 vpninfo->proxy?:vpninfo->hostname);
528 if (connect(ssl_sock, vpninfo->peer_addr, vpninfo->peer_addrlen))
532 struct addrinfo hints, *result, *rp;
536 memset(&hints, 0, sizeof(struct addrinfo));
537 hints.ai_family = AF_UNSPEC;
538 hints.ai_socktype = SOCK_STREAM;
539 hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
540 hints.ai_protocol = 0;
541 hints.ai_canonname = NULL;
542 hints.ai_addr = NULL;
543 hints.ai_next = NULL;
545 /* The 'port' variable is a string because it's easier
546 this way than if we pass NULL to getaddrinfo() and
547 then try to fill in the numeric value into
548 different types of returned sockaddr_in{6,}. */
549 #ifdef OPENCONNECT_LIBPROXY
550 if (vpninfo->proxy_factory) {
555 free(vpninfo->proxy_type);
556 vpninfo->proxy_type = NULL;
557 free(vpninfo->proxy);
558 vpninfo->proxy = NULL;
560 if (vpninfo->port == 443)
561 i = asprintf(&url, "https://%s/%s", vpninfo->hostname,
562 vpninfo->urlpath?:"");
564 i = asprintf(&url, "https://%s:%d/%s", vpninfo->hostname,
565 vpninfo->port, vpninfo->urlpath?:"");
569 proxies = px_proxy_factory_get_proxies(vpninfo->proxy_factory,
572 while (proxies && proxies[i]) {
573 if (!vpninfo->proxy &&
574 (!strncmp(proxies[i], "http://", 7) ||
575 !strncmp(proxies[i], "socks://", 8) ||
576 !strncmp(proxies[i], "socks5://", 9)))
577 parse_url(proxies[i], &vpninfo->proxy_type,
578 &vpninfo->proxy, &vpninfo->proxy_port,
585 vpninfo->progress(vpninfo, PRG_TRACE, "Proxy from libproxy: %s://%s:%d/\n",
586 vpninfo->proxy_type, vpninfo->proxy, vpninfo->port);
589 if (vpninfo->proxy) {
590 hostname = vpninfo->proxy;
591 snprintf(port, 6, "%d", vpninfo->proxy_port);
593 hostname = vpninfo->hostname;
594 snprintf(port, 6, "%d", vpninfo->port);
597 if (hostname[0] == '[' && hostname[strlen(hostname)-1] == ']') {
598 /* Solaris has no strndup(). */
599 int len = strlen(hostname) - 2;
600 char *new_hostname = malloc(len + 1);
603 memcpy(new_hostname, hostname + 1, len);
604 new_hostname[len] = 0;
606 hostname = new_hostname;
607 hints.ai_flags |= AI_NUMERICHOST;
610 err = getaddrinfo(hostname, port, &hints, &result);
611 if (hints.ai_flags & AI_NUMERICHOST)
615 vpninfo->progress(vpninfo, PRG_ERR, "getaddrinfo failed for host '%s': %s\n",
616 hostname, gai_strerror(err));
620 for (rp = result; rp ; rp = rp->ai_next) {
623 if (!getnameinfo(rp->ai_addr, rp->ai_addrlen, host,
624 sizeof(host), NULL, 0, NI_NUMERICHOST))
625 vpninfo->progress(vpninfo, PRG_INFO,
626 "Attempting to connect to %s%s%s:%s\n",
627 rp->ai_family == AF_INET6?"[":"",
629 rp->ai_family == AF_INET6?"]":"",
632 ssl_sock = socket(rp->ai_family, rp->ai_socktype,
636 if (connect(ssl_sock, rp->ai_addr, rp->ai_addrlen) >= 0) {
637 /* Store the peer address we actually used, so that DTLS can
638 use it again later */
639 vpninfo->peer_addr = malloc(rp->ai_addrlen);
640 if (!vpninfo->peer_addr) {
641 vpninfo->progress(vpninfo, PRG_ERR, "Failed to allocate sockaddr storage\n");
645 vpninfo->peer_addrlen = rp->ai_addrlen;
646 memcpy(vpninfo->peer_addr, rp->ai_addr, rp->ai_addrlen);
652 freeaddrinfo(result);
655 vpninfo->progress(vpninfo, PRG_ERR, "Failed to connect to host %s\n",
656 vpninfo->proxy?:vpninfo->hostname);
660 fcntl(ssl_sock, F_SETFD, FD_CLOEXEC);
662 if (vpninfo->proxy) {
663 err = process_proxy(vpninfo, ssl_sock);
670 ssl3_method = TLSv1_client_method();
671 if (!vpninfo->https_ctx) {
672 vpninfo->https_ctx = SSL_CTX_new(ssl3_method);
675 err = load_certificate(vpninfo);
677 vpninfo->progress(vpninfo, PRG_ERR,
678 "Loading certificate failed. Aborting.\n");
683 /* We just want to do:
684 SSL_CTX_set_purpose(vpninfo->https_ctx, X509_PURPOSE_ANY);
685 ... but it doesn't work with OpenSSL < 0.9.8k because of
686 problems with inheritance (fixed in v1.1.4.6 of
687 crypto/x509/x509_vpm.c) so we have to play silly buggers
688 instead. This trick doesn't work _either_ in < 0.9.7 but
689 I don't know of _any_ workaround which will, and can't
690 be bothered to find out either. */
691 #if OPENSSL_VERSION_NUMBER >= 0x00908000
692 SSL_CTX_set_cert_verify_callback(vpninfo->https_ctx,
693 ssl_app_verify_callback, NULL);
695 SSL_CTX_set_default_verify_paths(vpninfo->https_ctx);
698 SSL_CTX_load_verify_locations(vpninfo->https_ctx, vpninfo->cafile, NULL);
701 https_ssl = SSL_new(vpninfo->https_ctx);
702 workaround_openssl_certchain_bug(vpninfo, https_ssl);
704 https_bio = BIO_new_socket(ssl_sock, BIO_NOCLOSE);
705 SSL_set_bio(https_ssl, https_bio, https_bio);
707 vpninfo->progress(vpninfo, PRG_INFO,
708 "SSL negotiation with %s\n", vpninfo->hostname);
710 if (SSL_connect(https_ssl) <= 0) {
711 vpninfo->progress(vpninfo, PRG_ERR, "SSL connection failure\n");
712 report_ssl_errors(vpninfo);
718 if (verify_peer(vpninfo, https_ssl)) {
724 vpninfo->ssl_fd = ssl_sock;
725 vpninfo->https_ssl = https_ssl;
727 vpninfo->progress(vpninfo, PRG_INFO,
728 "Connected to HTTPS on %s\n", vpninfo->hostname);
733 void openconnect_close_https(struct openconnect_info *vpninfo)
735 SSL_free(vpninfo->https_ssl);
736 vpninfo->https_ssl = NULL;
737 close(vpninfo->ssl_fd);
738 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds);
739 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
740 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds);
741 vpninfo->ssl_fd = -1;
744 void openconnect_init_openssl(void)
748 SSL_load_error_strings ();
749 OpenSSL_add_all_algorithms ();
752 #if defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__)
753 int passphrase_from_fsid(struct openconnect_info *vpninfo)
757 if (statvfs(vpninfo->sslkey, &buf)) {
759 vpninfo->progress(vpninfo, PRG_ERR, "statvfs: %s\n", strerror(errno));
762 if (asprintf(&vpninfo->cert_password, "%lx", buf.f_fsid))
767 int passphrase_from_fsid(struct openconnect_info *vpninfo)
770 unsigned *fsid = (unsigned *)&buf.f_fsid;
771 unsigned long long fsid64;
773 if (statfs(vpninfo->sslkey, &buf)) {
775 vpninfo->progress(vpninfo, PRG_ERR, "statfs: %s\n", strerror(errno));
778 fsid64 = ((unsigned long long)fsid[0] << 32) | fsid[1];
780 if (asprintf(&vpninfo->cert_password, "%llx", fsid64))