Use SSLv3 not TLSv1
[platform/upstream/openconnect.git] / ssl.c
1 /*
2  * OpenConnect (SSL + DTLS) VPN client
3  *
4  * Copyright © 2008-2010 Intel Corporation.
5  *
6  * Author: David Woodhouse <dwmw2@infradead.org>
7  *
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.
11  *
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.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to:
19  *
20  *   Free Software Foundation, Inc.
21  *   51 Franklin Street, Fifth Floor,
22  *   Boston, MA 02110-1301 USA
23  */
24
25 #define _GNU_SOURCE
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <netdb.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <stdio.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 #if defined(__linux__)
37 #include <sys/vfs.h>
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>
43 #endif
44
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>
51
52 #include "openconnect.h"
53
54 /* OSX < 1.6 doesn't have AI_NUMERICSERV */
55 #ifndef AI_NUMERICSERV
56 #define AI_NUMERICSERV 0
57 #endif
58
59 /* Helper functions for reading/writing lines over SSL.
60    We could use cURL for the HTTP stuff, but it's overkill */
61
62 int  __attribute__ ((format (printf, 2, 3)))
63         openconnect_SSL_printf(SSL *ssl, const char *fmt, ...)
64 {
65         char buf[1024];
66         va_list args;
67
68         buf[1023] = 0;
69
70         va_start(args, fmt);
71         vsnprintf(buf, 1023, fmt, args);
72         va_end(args);
73         return SSL_write(ssl, buf, strlen(buf));
74
75 }
76
77 static int print_err(const char *str, size_t len, void *ptr)
78 {
79         struct openconnect_info *vpninfo = ptr;
80
81         vpninfo->progress(vpninfo, PRG_ERR, "%s", str);
82         return 0;
83 }
84
85 void report_ssl_errors(struct openconnect_info *vpninfo)
86 {
87         ERR_print_errors_cb(print_err, vpninfo);
88 }
89
90 int openconnect_SSL_gets(SSL *ssl, char *buf, size_t len)
91 {
92         int i = 0;
93         int ret;
94
95         if (len < 2)
96                 return -EINVAL;
97
98         while ( (ret = SSL_read(ssl, buf + i, 1)) == 1) {
99                 if (buf[i] == '\n') {
100                         buf[i] = 0;
101                         if (i && buf[i-1] == '\r') {
102                                 buf[i-1] = 0;
103                                 i--;
104                         }
105                         return i;
106                 }
107                 i++;
108
109                 if (i >= len - 1) {
110                         buf[i] = 0;
111                         return i;
112                 }
113         }
114         if (ret == 0) {
115                 ret = -SSL_get_error(ssl, ret);
116         }
117         buf[i] = 0;
118         return i ?: ret;
119 }
120
121 static int pem_pw_cb(char *buf, int len, int w, void *v)
122 {
123         struct openconnect_info *vpninfo = v;
124
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);
128
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);
133                 return -1;
134         }
135         strcpy(buf, vpninfo->cert_password);
136         return strlen(vpninfo->cert_password);
137 }
138
139 static int load_pkcs12_certificate(struct openconnect_info *vpninfo, PKCS12 *p12)
140 {
141         EVP_PKEY *pkey = NULL;
142         X509 *cert = NULL;
143         STACK_OF(X509) *ca;
144         int ret = 0;
145         char pass[PEM_BUFSIZE];
146
147  retrypass:
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. */
152         ca = NULL;
153         if (!vpninfo->cert_password) {
154                 if (EVP_read_pw_string(pass, PEM_BUFSIZE,
155                                        "Enter PKCS#12 pass phrase:", 0))
156                         return -EINVAL;
157         }
158         if (!PKCS12_parse(p12, vpninfo->cert_password?:pass, &pkey, &cert, &ca)) {
159                 unsigned long err = ERR_peek_error();
160
161                 report_ssl_errors(vpninfo);
162
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;
168                         goto retrypass;
169                 }
170
171                 vpninfo->progress(vpninfo, PRG_ERR, "Parse PKCS#12 failed (see above errors)\n");
172                 PKCS12_free(p12);
173                 return -EINVAL;
174         }
175         if (cert) {
176                 vpninfo->cert_x509 = cert;
177                 SSL_CTX_use_certificate(vpninfo->https_ctx, cert);
178         } else {
179                 vpninfo->progress(vpninfo, PRG_ERR,
180                                   "PKCS#12 contained no certificate!");
181                 ret = -EINVAL;
182         }
183
184         if (pkey) {
185                 SSL_CTX_use_PrivateKey(vpninfo->https_ctx, pkey);
186                 EVP_PKEY_free(pkey);
187         } else {
188                 vpninfo->progress(vpninfo, PRG_ERR,
189                                   "PKCS#12 contained no private key!");
190                 ret = -EINVAL;
191         }
192
193         /* Only include supporting certificates which are actually necessary */
194         if (ca) {
195                 int i;
196         next:
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) {
200                                 char buf[200];
201
202                                 if (cert2 == cert)
203                                         break;
204
205                                 X509_NAME_oneline(X509_get_subject_name(cert2),
206                                                   buf, sizeof(buf));
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);
211                                 cert = cert2;
212                                 goto next;
213                         }
214                 }
215                 sk_X509_pop_free(ca, X509_free);
216         }
217
218         PKCS12_free(p12);
219         return ret;
220 }
221
222 static int load_tpm_certificate(struct openconnect_info *vpninfo)
223 {
224         ENGINE *e;
225         EVP_PKEY *key;
226         ENGINE_load_builtin_engines();
227
228         e = ENGINE_by_id("tpm");
229         if (!e) {
230                 vpninfo->progress(vpninfo, PRG_ERR, "Can't load TPM engine.\n");
231                 report_ssl_errors(vpninfo);
232                 return -EINVAL;
233         }
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);
238                 ENGINE_free(e);
239                 return -EINVAL;
240         }
241
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);
247                 }
248         }
249         key = ENGINE_load_private_key(e, vpninfo->sslkey, NULL, NULL);
250         if (!key) {
251                 vpninfo->progress(vpninfo, PRG_ERR,
252                                   "Failed to load TPM private key\n");
253                 report_ssl_errors(vpninfo);
254                 ENGINE_free(e);
255                 ENGINE_finish(e);
256                 return -EINVAL;
257         }
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);
261                 ENGINE_free(e);
262                 ENGINE_finish(e);
263                 return -EINVAL;
264         }
265         return 0;
266 }
267
268 static int reload_pem_cert(struct openconnect_info *vpninfo)
269 {
270         BIO *b = BIO_new(BIO_s_file_internal());
271
272         if (!b)
273                 return -ENOMEM;
274
275         if (BIO_read_filename(b, vpninfo->cert) <= 0) {
276         err:
277                 BIO_free(b);
278                 vpninfo->progress(vpninfo, PRG_ERR,
279                                  "Failed to reload X509 cert for expiry check\n");
280                 report_ssl_errors(vpninfo);
281                 return -EIO;
282         }
283         vpninfo->cert_x509 = PEM_read_bio_X509_AUX(b, NULL, NULL, NULL);
284         if (!vpninfo->cert_x509)
285                 goto err;
286
287         return 0;
288 }
289
290 static int load_certificate(struct openconnect_info *vpninfo)
291 {
292         vpninfo->progress(vpninfo, PRG_TRACE,
293                           "Using certificate file %s\n", vpninfo->cert);
294
295         if (vpninfo->cert_type == CERT_TYPE_PKCS12 ||
296             vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
297                 FILE *f;
298                 PKCS12 *p12;
299
300                 f = fopen(vpninfo->cert, "r");
301                 if (!f) {
302                         vpninfo->progress(vpninfo, PRG_ERR,
303                                           "Failed to open certificate file %s: %s\n",
304                                           vpninfo->cert, strerror(errno));
305                         return -ENOENT;
306                 }
307                 p12 = d2i_PKCS12_fp(f, NULL);
308                 fclose(f);
309                 if (p12)
310                         return load_pkcs12_certificate(vpninfo, p12);
311
312                 /* Not PKCS#12 */
313                 if (vpninfo->cert_type == CERT_TYPE_PKCS12) {
314                         vpninfo->progress(vpninfo, PRG_ERR, "Read PKCS#12 failed\n");
315                         report_ssl_errors(vpninfo);
316                         return -EINVAL;
317                 }
318                 /* Clear error and fall through to see if it's a PEM file... */
319                 ERR_clear_error();
320         }
321
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,
324                                                 vpninfo->cert)) {
325                 vpninfo->progress(vpninfo, PRG_ERR,
326                                   "Loading certificate failed\n");
327                 report_ssl_errors(vpninfo);
328                 return -EINVAL;
329         }
330
331         /* Ew, we can't get it back from the OpenSSL CTX in any sane fashion */
332         reload_pem_cert(vpninfo);
333
334         if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
335                 FILE *f = fopen(vpninfo->sslkey, "r");
336                 char buf[256];
337
338                 if (!f) {
339                         vpninfo->progress(vpninfo, PRG_ERR,
340                                           "Failed to open private key file %s: %s\n",
341                                           vpninfo->cert, strerror(errno));
342                         return -ENOENT;
343                 }
344
345                 buf[255] = 0;
346                 while (fgets(buf, 255, f)) {
347                         if (!strcmp(buf, "-----BEGIN TSS KEY BLOB-----\n")) {
348                                 vpninfo->cert_type = CERT_TYPE_TPM;
349                                 break;
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;
354                                 break;
355                         }
356                 }
357                 fclose(f);
358                 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
359                         vpninfo->progress(vpninfo, PRG_ERR,
360                                           "Failed to identify private key type in '%s'\n",
361                                           vpninfo->sslkey);
362                         return -EINVAL;
363                 }
364         }
365
366         if (vpninfo->cert_type == CERT_TYPE_TPM)
367                 return load_tpm_certificate(vpninfo);
368
369         /* Standard PEM certificate */
370         if (vpninfo->cert_password) {
371                 SSL_CTX_set_default_passwd_cb(vpninfo->https_ctx,
372                                               pem_pw_cb);
373                 SSL_CTX_set_default_passwd_cb_userdata(vpninfo->https_ctx,
374                                                        vpninfo);
375         }
376  again:
377         if (!SSL_CTX_use_RSAPrivateKey_file(vpninfo->https_ctx, vpninfo->sslkey,
378                                             SSL_FILETYPE_PEM)) {
379                 unsigned long err = ERR_peek_error();
380                 
381                 report_ssl_errors(vpninfo);
382
383 #ifndef EVP_F_EVP_DECRYPTFINAL_EX
384 #define EVP_F_EVP_DECRYPTFINAL_EX EVP_F_EVP_DECRYPTFINAL
385 #endif
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");
391                         goto again;
392                 }
393                 
394                 vpninfo->progress(vpninfo, PRG_ERR, "Loading private key failed (see above errors)\n");
395                 return -EINVAL;
396         }
397         return 0;
398 }
399
400 enum cert_hash_type {
401         EVP_MD5,
402         EVP_SHA1
403 };
404
405 static int get_cert_fingerprint(struct openconnect_info *vpninfo,
406                                 X509 *cert, enum cert_hash_type hash,
407                                 char *buf)
408 {
409         unsigned char md[EVP_MAX_MD_SIZE];
410         unsigned int i, n;
411
412         switch (hash) {
413         case EVP_MD5:
414                 if (!X509_digest(cert, EVP_md5(), md, &n))
415                         return -ENOMEM;
416                 break;
417         case EVP_SHA1:
418                 if (!X509_digest(cert, EVP_sha1(), md, &n))
419                         return -ENOMEM;
420                 break;
421         default:
422                 vpninfo->progress(vpninfo, PRG_ERR,
423                                   "Unsupported SSL certificate hash function type\n");
424         }
425
426         for (i=0; i < n; i++) {
427                 sprintf(&buf[i*2], "%02X", md[i]);
428         }
429         return 0;
430 }
431
432 int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
433                              X509 *cert, char *buf)
434 {
435         return get_cert_fingerprint(vpninfo, cert, EVP_MD5, buf);
436 }
437
438 int get_cert_sha1_fingerprint(struct openconnect_info *vpninfo,
439                               X509 *cert, char *buf)
440 {
441         return get_cert_fingerprint(vpninfo, cert, EVP_SHA1, buf);
442 }
443
444 static int check_server_cert(struct openconnect_info *vpninfo, X509 *cert)
445 {
446         char fingerprint[EVP_MAX_MD_SIZE * 2 + 1];
447         int ret;
448
449         ret = get_cert_sha1_fingerprint(vpninfo, cert, fingerprint);
450         if (ret)
451                 return ret;
452
453         if (strcasecmp(vpninfo->servercert, fingerprint)) {
454                 vpninfo->progress(vpninfo, PRG_ERR,
455                                   "Server SSL certificate didn't match: %s\n", fingerprint);
456                 return -EINVAL;
457         }
458         return 0;
459 }
460
461 static int match_hostname_elem(const char *hostname, int helem_len,
462                                const char *match, int melem_len)
463 {
464         if (!helem_len && !melem_len)
465                 return 0;
466
467         if (!helem_len || !melem_len)
468                 return -1;
469
470
471         if (match[0] == '*') {
472                 int i;
473
474                 for (i = 1 ; i <= helem_len; i++) {
475                         if (!match_hostname_elem(hostname + i, helem_len - i,
476                                                  match + 1, melem_len - 1))
477                                 return 0;
478                 }
479                 return -1;
480         }
481
482         if (toupper(hostname[0]) == toupper(match[0]))
483                 return match_hostname_elem(hostname + 1, helem_len - 1,
484                                            match + 1, melem_len - 1);
485
486         return -1;
487 }
488
489 static int match_hostname(const char *hostname, const char *match)
490 {
491         while (*match) {
492                 const char *h_dot, *m_dot;
493                 int helem_len, melem_len;
494
495                 h_dot = strchr(hostname, '.');
496                 m_dot = strchr(match, '.');
497                 
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);
504                 } else
505                         return -1;
506
507
508                 if (match_hostname_elem(hostname, helem_len,
509                                         match, melem_len))
510                         return -1;
511
512                 hostname += helem_len;
513                 match += melem_len;
514         }
515         if (*hostname)
516                 return -1;
517
518         return 0;
519 }
520
521 /* cf. RFC2818 and RFC2459 */
522 int match_cert_hostname(struct openconnect_info *vpninfo, X509 *peer_cert)
523 {
524         STACK_OF(GENERAL_NAME) *altnames;
525         X509_NAME *subjname;
526         ASN1_STRING *subjasn1;
527         char *subjstr = NULL;
528         int addrlen = 0;
529         int i, altdns = 0;
530         char addrbuf[sizeof(struct in6_addr)];
531         int ret;
532
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)
536                 addrlen = 4;
537         else if (inet_pton(AF_INET6, vpninfo->hostname, addrbuf) > 0)
538                 addrlen = 16;
539         else if (vpninfo->hostname[0] == '[' &&
540                  vpninfo->hostname[strlen(vpninfo->hostname)-1] == ']') {
541                 char *p = &vpninfo->hostname[strlen(vpninfo->hostname)-1];
542                 *p = 0;
543                 if (inet_pton(AF_INET6, vpninfo->hostname + 1, addrbuf) > 0)
544                         addrlen = 16;
545                 *p = ']';
546         }
547
548         altnames = X509_get_ext_d2i(peer_cert, NID_subject_alt_name,
549                                     NULL, NULL);
550         for (i = 0; i < sk_GENERAL_NAME_num(altnames); i++) {
551                 const GENERAL_NAME *this = sk_GENERAL_NAME_value(altnames, i);
552
553                 if (this->type == GEN_DNS) {
554                         char *str;
555
556                         int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
557                         if (len < 0)
558                                 continue;
559
560                         altdns = 1;
561
562                         /* We don't like names with embedded NUL */
563                         if (strlen(str) != len)
564                                 continue;
565
566                         if (!match_hostname(vpninfo->hostname, str)) {
567                                 vpninfo->progress(vpninfo, PRG_TRACE,
568                                                   "Matched DNS altname '%s'\n",
569                                                   str);
570                                 GENERAL_NAMES_free(altnames);
571                                 OPENSSL_free(str);
572                                 return 0;
573                         } else {
574                                 vpninfo->progress(vpninfo, PRG_TRACE,
575                                                   "No match for altname '%s'\n",
576                                                   str);
577                         }
578                         OPENSSL_free(str);
579                 } else if (this->type == GEN_IPADD && addrlen) {
580                         char host[80];
581                         int family;
582
583                         if (this->d.ip->length == 4) {
584                                 family = AF_INET;
585                         } else if (this->d.ip->length == 16) {
586                                 family = AF_INET6;
587                         } else {
588                                 vpninfo->progress(vpninfo, PRG_ERR,
589                                                   "Certificate has GEN_IPADD altname with bogus length %d\n",
590                                                   this->d.ip->length);
591                                 continue;
592                         }
593                         
594                         /* We only do this for the debug messages */
595                         inet_ntop(family, this->d.ip->data, host, sizeof(host));
596
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":"",
602                                                   host);
603                                 GENERAL_NAMES_free(altnames);
604                                 return 0;
605                         } else {
606                                 vpninfo->progress(vpninfo, PRG_TRACE,
607                                                   "No match for IP%s address '%s'\n",
608                                                   (family == AF_INET6)?"v6":"",
609                                                   host);
610                         }
611                 } else if (this->type == GEN_URI) {
612                         char *str;
613                         char *url_proto, *url_host, *url_path, *url_host2;
614                         int url_port;
615                         int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
616
617                         if (len < 0)
618                                 continue;
619
620                         /* We don't like names with embedded NUL */
621                         if (strlen(str) != len)
622                                 continue;
623
624                         if (parse_url(str, &url_proto, &url_host, &url_port, &url_path, 0)) {
625                                 OPENSSL_free(str);
626                                 continue;
627                         }
628
629                         if (!url_proto || strcasecmp(url_proto, "https"))
630                                 goto no_uri_match;
631
632                         if (url_port != vpninfo->port)
633                                 goto no_uri_match;
634
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;
641                                 url_host2++;
642                         }
643
644                         if (strcasecmp(vpninfo->hostname, url_host2))
645                                 goto no_uri_match;
646
647                         if (url_path) {
648                                 vpninfo->progress(vpninfo, PRG_TRACE, "URI '%s' has non-empty path; ignoring\n",
649                                                   str);
650                                 goto no_uri_match_silent;
651                         }
652                         vpninfo->progress(vpninfo, PRG_TRACE,
653                                           "Matched URI '%s'\n",
654                                           str);
655                         free(url_proto);
656                         free(url_host);
657                         free(url_path);
658                         OPENSSL_free(str);
659                         GENERAL_NAMES_free(altnames);
660                         return 0;
661
662                 no_uri_match:
663                         vpninfo->progress(vpninfo, PRG_TRACE,
664                                           "No match for URI '%s'\n",
665                                           str);
666                 no_uri_match_silent:
667                         free(url_proto);
668                         free(url_host);
669                         free(url_path);
670                         OPENSSL_free(str);
671                 }
672         }
673         GENERAL_NAMES_free(altnames);
674
675         /* According to RFC2818, we don't use the legacy subject name if
676            there was an altname with DNS type. */
677         if (altdns) {
678                 vpninfo->progress(vpninfo, PRG_ERR, "No altname in peer cert matched '%s'\n",
679                                   vpninfo->hostname);
680                 return -EINVAL;
681         }
682
683         subjname = X509_get_subject_name(peer_cert);
684         if (!subjname) {
685                 vpninfo->progress(vpninfo, PRG_ERR, "No subject name in peer cert!\n");
686                 return -EINVAL;
687         }
688
689         /* Find the _last_ (most specific) commonName */
690         i = -1;
691         while (1) {
692                 int j = X509_NAME_get_index_by_NID(subjname, NID_commonName, i);
693                 if (j >= 0)
694                         i = j;
695                 else
696                         break;
697         }
698
699         subjasn1 = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subjname, i));
700
701         i = ASN1_STRING_to_UTF8((void *)&subjstr, subjasn1);
702
703         if (!subjstr || strlen(subjstr) != i) {
704                 vpninfo->progress(vpninfo, PRG_ERR,
705                                   "Failed to parse subject name in peer cert\n");
706                 return -EINVAL;
707         }
708         ret = 0;
709
710         if (match_hostname(vpninfo->hostname, subjstr)) {
711                 vpninfo->progress(vpninfo, PRG_ERR, "Peer cert subject mismatch ('%s' != '%s')\n",
712                                   subjstr, vpninfo->hostname);
713                 ret = -EINVAL;
714         } else {
715                 vpninfo->progress(vpninfo, PRG_TRACE,
716                                   "Matched peer certificate subject name '%s'\n",
717                                   subjstr);
718         }
719
720         OPENSSL_free(subjstr);                    
721         return ret;
722 }
723
724 static int verify_peer(struct openconnect_info *vpninfo, SSL *https_ssl)
725 {
726         X509 *peer_cert;
727         int ret;
728
729         peer_cert = SSL_get_peer_certificate(https_ssl);
730
731         if (vpninfo->servercert) {
732                 /* If given a cert fingerprint on the command line, that's
733                    all we look for */
734                 ret = check_server_cert(vpninfo, peer_cert);
735         } else {
736                 int vfy = SSL_get_verify_result(https_ssl);
737                 const char *err_string = NULL;
738
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";
743
744                 if (err_string) {
745                         vpninfo->progress(vpninfo, PRG_ERR,
746                                           "Server certificate verify failed: %s\n",
747                                           err_string);
748
749                         if (vpninfo->validate_peer_cert)
750                                 ret = vpninfo->validate_peer_cert(vpninfo, peer_cert,
751                                                                   err_string);
752                         else
753                                 ret = -EINVAL;
754                 } else {
755                         ret = 0;
756                 }
757         }
758         X509_free(peer_cert);
759
760         return ret;
761 }
762
763 static void workaround_openssl_certchain_bug(struct openconnect_info *vpninfo,
764                                              SSL *ssl)
765 {
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);
771         X509 *cert2;
772         X509_STORE *store = SSL_CTX_get_cert_store(vpninfo->https_ctx);
773         X509_STORE_CTX ctx;
774
775         if (!cert || !store)
776                 return;
777
778         /* If we already have 'supporting' certs, don't add them again */
779         if (vpninfo->https_ctx->extra_certs)
780                 return;
781
782         if (!X509_STORE_CTX_init(&ctx, store, NULL, NULL))
783                 return;
784
785         while (ctx.get_issuer(&cert2, &ctx, cert) == 1) {
786                 char buf[200];
787                 if (cert2 == cert)
788                         break;
789                 cert = cert2;
790                 X509_NAME_oneline(X509_get_subject_name(cert),
791                                   buf, sizeof(buf));
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);
795         }
796         X509_STORE_CTX_cleanup(&ctx);
797 }
798
799 #if OPENSSL_VERSION_NUMBER >= 0x00908000
800 static int ssl_app_verify_callback(X509_STORE_CTX *ctx, void *arg)
801 {
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);
806 }
807 #endif
808
809 static int check_certificate_expiry(struct openconnect_info *vpninfo)
810 {
811         ASN1_TIME *notAfter;
812         char *reason = NULL;
813         time_t t;
814         int i;
815         if (!vpninfo->cert_x509)
816                 return 0;
817
818         t = time(NULL);
819         notAfter = X509_get_notAfter(vpninfo->cert_x509);
820         i = X509_cmp_time(notAfter, &t);
821         if (!i) {
822                 vpninfo->progress(vpninfo, PRG_ERR, "Error in client cert notAfter field\n");
823                 return -EINVAL;
824         } else if (i < 0) {
825                 reason = "has expired";
826         } else {
827                 t += 60 * 86400;
828                 i = X509_cmp_time(notAfter, &t);
829                 if (i < 0) {
830                         reason = "expires soon";
831                 }
832         }
833         if (reason) {
834                 BIO *bp = BIO_new(BIO_s_mem());
835                 BUF_MEM *bm;
836                 char *expiry = "<error>";
837                 char zero = 0;
838
839                 if (bp) {
840                         ASN1_TIME_print(bp, notAfter);
841                         BIO_write(bp, &zero, 1);
842                         BIO_get_mem_ptr(bp, &bm);
843                         expiry = bm->data;
844                 }
845                 vpninfo->progress(vpninfo, PRG_ERR, "Client certificate %s at: %s\n",
846                                   reason, expiry);
847                 if (bp)
848                         BIO_free(bp);
849         }
850         return 0;
851 }
852
853 int openconnect_open_https(struct openconnect_info *vpninfo)
854 {
855         method_const SSL_METHOD *ssl3_method;
856         SSL *https_ssl;
857         BIO *https_bio;
858         int ssl_sock = -1;
859         int err;
860
861         if (!vpninfo->port)
862                 vpninfo->port = 443;
863
864         if (vpninfo->peer_addr) {
865                 ssl_sock = socket(vpninfo->peer_addr->sa_family, SOCK_STREAM, IPPROTO_IP);
866                 if (ssl_sock < 0) {
867                 reconn_err:
868                         vpninfo->progress(vpninfo, PRG_ERR, "Failed to reconnect to %s %s\n",
869                                           vpninfo->proxy?"proxy":"host",
870                                           vpninfo->proxy?:vpninfo->hostname);
871                         return -EINVAL;
872                 }
873                 if (connect(ssl_sock, vpninfo->peer_addr, vpninfo->peer_addrlen))
874                         goto reconn_err;
875                 
876         } else {
877                 struct addrinfo hints, *result, *rp;
878                 char *hostname;
879                 char port[6];
880
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;
889
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) {
896                         char *url;
897                         char **proxies;
898                         int i = 0;
899
900                         free(vpninfo->proxy_type);
901                         vpninfo->proxy_type = NULL;
902                         free(vpninfo->proxy);
903                         vpninfo->proxy = NULL;
904
905                         if (vpninfo->port == 443)
906                                 i = asprintf(&url, "https://%s/%s", vpninfo->hostname,
907                                              vpninfo->urlpath?:"");
908                         else
909                                 i = asprintf(&url, "https://%s:%d/%s", vpninfo->hostname,
910                                              vpninfo->port, vpninfo->urlpath?:"");
911                         if (i == -1)
912                                 return -ENOMEM;
913
914                         proxies = px_proxy_factory_get_proxies(vpninfo->proxy_factory,
915                                                                url);
916
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,
924                                                   NULL, 0);
925                                 i++;
926                         }
927                         free(url);
928                         free(proxies);
929                         if (vpninfo->proxy)
930                                 vpninfo->progress(vpninfo, PRG_TRACE, "Proxy from libproxy: %s://%s:%d/\n",
931                                                   vpninfo->proxy_type, vpninfo->proxy, vpninfo->port);
932                 }
933 #endif
934                 if (vpninfo->proxy) {
935                         hostname = vpninfo->proxy;
936                         snprintf(port, 6, "%d", vpninfo->proxy_port);
937                 } else {
938                         hostname = vpninfo->hostname;
939                         snprintf(port, 6, "%d", vpninfo->port);
940                 }
941
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);
946                         if (!new_hostname)
947                                 return -ENOMEM;
948                         memcpy(new_hostname, hostname + 1, len);
949                         new_hostname[len] = 0;
950
951                         hostname = new_hostname;
952                         hints.ai_flags |= AI_NUMERICHOST;
953                 }
954
955                 err = getaddrinfo(hostname, port, &hints, &result);
956                 if (hints.ai_flags & AI_NUMERICHOST)
957                         free(hostname);
958
959                 if (err) {
960                         vpninfo->progress(vpninfo, PRG_ERR, "getaddrinfo failed for host '%s': %s\n",
961                                           hostname, gai_strerror(err));
962                         return -EINVAL;
963                 }
964
965                 for (rp = result; rp ; rp = rp->ai_next) {
966                         char host[80];
967
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?"[":"",
973                                                   host,
974                                                   rp->ai_family == AF_INET6?"]":"",
975                                                   port);
976                         
977                         ssl_sock = socket(rp->ai_family, rp->ai_socktype,
978                                           rp->ai_protocol);
979                         if (ssl_sock < 0)
980                                 continue;
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");
987                                         close(ssl_sock);
988                                         return -ENOMEM;
989                                 }
990                                 vpninfo->peer_addrlen = rp->ai_addrlen;
991                                 memcpy(vpninfo->peer_addr, rp->ai_addr, rp->ai_addrlen);
992                                 break;
993                         }
994                         close(ssl_sock);
995                         ssl_sock = -1;
996                 }
997                 freeaddrinfo(result);
998                 
999                 if (ssl_sock < 0) {
1000                         vpninfo->progress(vpninfo, PRG_ERR, "Failed to connect to host %s\n",
1001                                           vpninfo->proxy?:vpninfo->hostname);
1002                         return -EINVAL;
1003                 }
1004         }
1005         fcntl(ssl_sock, F_SETFD, FD_CLOEXEC);
1006
1007         if (vpninfo->proxy) {
1008                 err = process_proxy(vpninfo, ssl_sock);
1009                 if (err) {
1010                         close(ssl_sock);
1011                         return err;
1012                 }
1013         }
1014
1015         ssl3_method = SSLv3_client_method();
1016         if (!vpninfo->https_ctx) {
1017                 vpninfo->https_ctx = SSL_CTX_new(ssl3_method);
1018
1019                 if (vpninfo->cert) {
1020                         err = load_certificate(vpninfo);
1021                         if (err) {
1022                                 vpninfo->progress(vpninfo, PRG_ERR,
1023                                                   "Loading certificate failed. Aborting.\n");
1024                                 return err;
1025                         }
1026                         check_certificate_expiry(vpninfo);
1027                 }
1028
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);
1040 #endif
1041                 SSL_CTX_set_default_verify_paths(vpninfo->https_ctx);
1042
1043                 if (vpninfo->cafile)
1044                         SSL_CTX_load_verify_locations(vpninfo->https_ctx, vpninfo->cafile, NULL);
1045
1046         }
1047         https_ssl = SSL_new(vpninfo->https_ctx);
1048         workaround_openssl_certchain_bug(vpninfo, https_ssl);
1049
1050         https_bio = BIO_new_socket(ssl_sock, BIO_NOCLOSE);
1051         SSL_set_bio(https_ssl, https_bio, https_bio);
1052
1053         vpninfo->progress(vpninfo, PRG_INFO,
1054                           "SSL negotiation with %s\n", vpninfo->hostname);
1055
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);
1060                 close(ssl_sock);
1061                 return -EINVAL;
1062         }
1063
1064         if (verify_peer(vpninfo, https_ssl)) {
1065                 SSL_free(https_ssl);
1066                 close(ssl_sock);
1067                 return -EINVAL;
1068         }
1069
1070         vpninfo->ssl_fd = ssl_sock;
1071         vpninfo->https_ssl = https_ssl;
1072
1073         vpninfo->progress(vpninfo, PRG_INFO,
1074                           "Connected to HTTPS on %s\n", vpninfo->hostname);
1075
1076         return 0;
1077 }
1078
1079 void openconnect_close_https(struct openconnect_info *vpninfo)
1080 {
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;
1088 }
1089
1090 void openconnect_init_openssl(void)
1091 {
1092         SSL_library_init ();
1093         ERR_clear_error ();
1094         SSL_load_error_strings ();
1095         OpenSSL_add_all_algorithms ();
1096 }
1097
1098 #if defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__)
1099 int passphrase_from_fsid(struct openconnect_info *vpninfo)
1100 {
1101         struct statvfs buf;
1102
1103         if (statvfs(vpninfo->sslkey, &buf)) {
1104                 int err = errno;
1105                 vpninfo->progress(vpninfo, PRG_ERR, "statvfs: %s\n", strerror(errno));
1106                 return -err;
1107         }
1108         if (asprintf(&vpninfo->cert_password, "%lx", buf.f_fsid))
1109                 return -ENOMEM;
1110         return 0;
1111 }
1112 #else
1113 int passphrase_from_fsid(struct openconnect_info *vpninfo)
1114 {
1115         struct statfs buf;
1116         unsigned *fsid = (unsigned *)&buf.f_fsid;
1117         unsigned long long fsid64;
1118
1119         if (statfs(vpninfo->sslkey, &buf)) {
1120                 int err = errno;
1121                 vpninfo->progress(vpninfo, PRG_ERR, "statfs: %s\n", strerror(errno));
1122                 return -err;
1123         }
1124         fsid64 = ((unsigned long long)fsid[0] << 32) | fsid[1];
1125
1126         if (asprintf(&vpninfo->cert_password, "%llx", fsid64))
1127                 return -ENOMEM;
1128         return 0;
1129 }
1130 #endif