Fix FreeBSD compile
[platform/upstream/openconnect.git] / openssl.c
1 /*
2  * OpenConnect (SSL + DTLS) VPN client
3  *
4  * Copyright © 2008-2012 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 #include <errno.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <ctype.h>
29
30 #include <openssl/ssl.h>
31 #include <openssl/err.h>
32 #include <openssl/engine.h>
33 #include <openssl/evp.h>
34 #include <openssl/rand.h>
35 #include <openssl/pkcs12.h>
36 #include <openssl/x509v3.h>
37 #include <openssl/x509.h>
38 #include <openssl/bio.h>
39
40 #include "openconnect-internal.h"
41
42 int openconnect_sha1(unsigned char *result, void *data, int len)
43 {
44         EVP_MD_CTX c;
45
46         EVP_MD_CTX_init(&c);
47         EVP_Digest(data, len, result, NULL, EVP_sha1(), NULL);
48         EVP_MD_CTX_cleanup(&c);
49
50         return 0;
51 }
52
53 int openconnect_get_cert_DER(struct openconnect_info *vpninfo,
54                              struct x509_st *cert, unsigned char **buf)
55 {
56         BIO *bp = BIO_new(BIO_s_mem());
57         BUF_MEM *certinfo;
58         size_t l;
59
60         if (!i2d_X509_bio(bp, cert)) {
61                 BIO_free(bp);
62                 return -EIO;
63         }
64
65         BIO_get_mem_ptr(bp, &certinfo);
66         l = certinfo->length;
67         *buf = malloc(l);
68         if (!*buf) {
69                 BIO_free(bp);
70                 return -ENOMEM;
71         }
72         memcpy(*buf, certinfo->data, l);
73         BIO_free(bp);
74         return l;
75 }
76
77 int openconnect_random(void *bytes, int len)
78 {
79         if (RAND_bytes(bytes, len) != 1)
80                 return -EIO;
81         return 0;
82 }
83
84 /* Helper functions for reading/writing lines over SSL.
85    We could use cURL for the HTTP stuff, but it's overkill */
86
87 int openconnect_SSL_write(struct openconnect_info *vpninfo, char *buf, size_t len)
88 {
89         size_t orig_len = len;
90
91         while (len) {
92                 int done = SSL_write(vpninfo->https_ssl, buf, len);
93
94                 if (done > 0)
95                         len -= done;
96                 else {
97                         int err = SSL_get_error(vpninfo->https_ssl, done);
98                         fd_set wr_set, rd_set;
99                         int maxfd = vpninfo->ssl_fd;
100
101                         FD_ZERO(&wr_set);
102                         FD_ZERO(&rd_set);
103                         
104                         if (err == SSL_ERROR_WANT_READ)
105                                 FD_SET(vpninfo->ssl_fd, &rd_set);
106                         else if (err == SSL_ERROR_WANT_WRITE)
107                                 FD_SET(vpninfo->ssl_fd, &wr_set);
108                         else {
109                                 vpn_progress(vpninfo, PRG_ERR, _("Failed to write to SSL socket"));
110                                 openconnect_report_ssl_errors(vpninfo);
111                                 return -EIO;
112                         }
113                         if (vpninfo->cancel_fd != -1) {
114                                 FD_SET(vpninfo->cancel_fd, &rd_set);
115                                 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
116                                         maxfd = vpninfo->cancel_fd;
117                         }
118                         select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
119                         if (vpninfo->cancel_fd != -1 &&
120                             FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
121                                 vpn_progress(vpninfo, PRG_ERR, _("SSL write cancelled\n"));
122                                 return -EINTR;
123                         }
124                 }
125         }
126         return orig_len;
127 }
128
129 int openconnect_SSL_read(struct openconnect_info *vpninfo, char *buf, size_t len)
130 {
131         int done;
132
133         while ((done = SSL_read(vpninfo->https_ssl, buf, len)) == -1) {
134                 int err = SSL_get_error(vpninfo->https_ssl, done);
135                 fd_set wr_set, rd_set;
136                 int maxfd = vpninfo->ssl_fd;
137
138                 FD_ZERO(&wr_set);
139                 FD_ZERO(&rd_set);
140                         
141                 if (err == SSL_ERROR_WANT_READ)
142                         FD_SET(vpninfo->ssl_fd, &rd_set);
143                 else if (err == SSL_ERROR_WANT_WRITE)
144                         FD_SET(vpninfo->ssl_fd, &wr_set);
145                 else {
146                         vpn_progress(vpninfo, PRG_ERR, _("Failed to read from SSL socket"));
147                         openconnect_report_ssl_errors(vpninfo);
148                         return -EIO;
149                 }
150                 if (vpninfo->cancel_fd != -1) {
151                         FD_SET(vpninfo->cancel_fd, &rd_set);
152                         if (vpninfo->cancel_fd > vpninfo->ssl_fd)
153                                 maxfd = vpninfo->cancel_fd;
154                 }
155                 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
156                 if (vpninfo->cancel_fd != -1 &&
157                     FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
158                         vpn_progress(vpninfo, PRG_ERR, _("SSL read cancelled\n"));
159                         return -EINTR;
160                 }
161         }
162         return done;
163 }
164
165 static int print_err(const char *str, size_t len, void *ptr)
166 {
167         struct openconnect_info *vpninfo = ptr;
168
169         vpn_progress(vpninfo, PRG_ERR, "%s", str);
170         return 0;
171 }
172
173 void openconnect_report_ssl_errors(struct openconnect_info *vpninfo)
174 {
175         ERR_print_errors_cb(print_err, vpninfo);
176 }
177
178 int openconnect_SSL_gets(struct openconnect_info *vpninfo, char *buf, size_t len)
179 {
180         int i = 0;
181         int ret;
182
183         if (len < 2)
184                 return -EINVAL;
185
186         while (1) {
187                 ret = SSL_read(vpninfo->https_ssl, buf + i, 1);
188                 if (ret == 1) {
189                         if (buf[i] == '\n') {
190                                 buf[i] = 0;
191                                 if (i && buf[i-1] == '\r') {
192                                         buf[i-1] = 0;
193                                         i--;
194                                 }
195                                 return i;
196                         }
197                         i++;
198
199                         if (i >= len - 1) {
200                                 buf[i] = 0;
201                                 return i;
202                         }
203                 } else {
204                         fd_set rd_set, wr_set;
205                         int maxfd = vpninfo->ssl_fd;
206                         
207                         FD_ZERO(&rd_set);
208                         FD_ZERO(&wr_set);
209                         
210                         ret = SSL_get_error(vpninfo->https_ssl, ret);
211                         if (ret == SSL_ERROR_WANT_READ)
212                                 FD_SET(vpninfo->ssl_fd, &rd_set);
213                         else if (ret == SSL_ERROR_WANT_WRITE)
214                                 FD_SET(vpninfo->ssl_fd, &wr_set);
215                         else {
216                                 vpn_progress(vpninfo, PRG_ERR, _("Failed to read from SSL socket\n"));
217                                 openconnect_report_ssl_errors(vpninfo);
218                                 ret = -EIO;
219                                 break;
220                         }
221                         if (vpninfo->cancel_fd != -1) {
222                                 FD_SET(vpninfo->cancel_fd, &rd_set);
223                                 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
224                                         maxfd = vpninfo->cancel_fd;
225                         }
226                         select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
227                         if (vpninfo->cancel_fd != -1 &&
228                             FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
229                                 vpn_progress(vpninfo, PRG_ERR, _("SSL read cancelled\n"));
230                                 ret = -EINTR;
231                                 break;
232                         }
233                 }
234         }
235         buf[i] = 0;
236         return i ?: ret;
237 }
238
239 static int pem_pw_cb(char *buf, int len, int w, void *v)
240 {
241         struct openconnect_info *vpninfo = v;
242
243         /* Only try the provided password once... */
244         SSL_CTX_set_default_passwd_cb(vpninfo->https_ctx, NULL);
245         SSL_CTX_set_default_passwd_cb_userdata(vpninfo->https_ctx, NULL);
246
247         if (len <= strlen(vpninfo->cert_password)) {
248                 vpn_progress(vpninfo, PRG_ERR,
249                              _("PEM password too long (%zd >= %d)\n"),
250                              strlen(vpninfo->cert_password), len);
251                 return -1;
252         }
253         strcpy(buf, vpninfo->cert_password);
254         return strlen(vpninfo->cert_password);
255 }
256
257 static int load_pkcs12_certificate(struct openconnect_info *vpninfo, PKCS12 *p12)
258 {
259         EVP_PKEY *pkey = NULL;
260         X509 *cert = NULL;
261         STACK_OF(X509) *ca;
262         int ret = 0;
263         char pass[PEM_BUFSIZE];
264
265  retrypass:
266         /* We do this every time round the loop, to work around a bug in
267            OpenSSL < 1.0.0-beta2 -- where the stack at *ca will be freed
268            when PKCS12_parse() returns an error, but *ca is left pointing
269            to the freed memory. */
270         ca = NULL;
271         if (!vpninfo->cert_password) {
272                 if (EVP_read_pw_string(pass, PEM_BUFSIZE,
273                                        "Enter PKCS#12 pass phrase:", 0))
274                         return -EINVAL;
275         }
276         if (!PKCS12_parse(p12, vpninfo->cert_password?:pass, &pkey, &cert, &ca)) {
277                 unsigned long err = ERR_peek_error();
278
279                 openconnect_report_ssl_errors(vpninfo);
280
281                 if (ERR_GET_LIB(err) == ERR_LIB_PKCS12 &&
282                     ERR_GET_FUNC(err) == PKCS12_F_PKCS12_PARSE &&
283                     ERR_GET_REASON(err) == PKCS12_R_MAC_VERIFY_FAILURE) {
284                         vpn_progress(vpninfo, PRG_ERR,
285                                      _("Parse PKCS#12 failed (wrong passphrase?)\n"));
286                         vpninfo->cert_password = NULL;
287                         goto retrypass;
288                 }
289
290                 vpn_progress(vpninfo, PRG_ERR,
291                              _("Parse PKCS#12 failed (see above errors)\n"));
292                 PKCS12_free(p12);
293                 return -EINVAL;
294         }
295         if (cert) {
296                 vpninfo->cert_x509 = cert;
297                 SSL_CTX_use_certificate(vpninfo->https_ctx, cert);
298         } else {
299                 vpn_progress(vpninfo, PRG_ERR,
300                              _("PKCS#12 contained no certificate!"));
301                 ret = -EINVAL;
302         }
303
304         if (pkey) {
305                 SSL_CTX_use_PrivateKey(vpninfo->https_ctx, pkey);
306                 EVP_PKEY_free(pkey);
307         } else {
308                 vpn_progress(vpninfo, PRG_ERR,
309                              _("PKCS#12 contained no private key!"));
310                 ret = -EINVAL;
311         }
312
313         /* Only include supporting certificates which are actually necessary */
314         if (ca) {
315                 int i;
316         next:
317                 for (i = 0; i < sk_X509_num(ca); i++) {
318                         X509 *cert2 = sk_X509_value(ca, i);
319                         if (X509_check_issued(cert2, cert) == X509_V_OK) {
320                                 char buf[200];
321
322                                 if (cert2 == cert)
323                                         break;
324                                 if (X509_check_issued(cert2, cert2) == X509_V_OK)
325                                         break;
326
327                                 X509_NAME_oneline(X509_get_subject_name(cert2),
328                                                   buf, sizeof(buf));
329                                 vpn_progress(vpninfo, PRG_DEBUG,
330                                              _("Extra cert from PKCS#12: '%s'\n"), buf);
331                                 CRYPTO_add(&cert2->references, 1, CRYPTO_LOCK_X509);
332                                 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert2);
333                                 cert = cert2;
334                                 goto next;
335                         }
336                 }
337                 sk_X509_pop_free(ca, X509_free);
338         }
339
340         PKCS12_free(p12);
341         return ret;
342 }
343
344 #ifdef HAVE_ENGINE
345 static int load_tpm_certificate(struct openconnect_info *vpninfo)
346 {
347         ENGINE *e;
348         EVP_PKEY *key;
349         ENGINE_load_builtin_engines();
350
351         e = ENGINE_by_id("tpm");
352         if (!e) {
353                 vpn_progress(vpninfo, PRG_ERR, _("Can't load TPM engine.\n"));
354                 openconnect_report_ssl_errors(vpninfo);
355                 return -EINVAL;
356         }
357         if (!ENGINE_init(e) || !ENGINE_set_default_RSA(e) ||
358             !ENGINE_set_default_RAND(e)) {
359                 vpn_progress(vpninfo, PRG_ERR, _("Failed to init TPM engine\n"));
360                 openconnect_report_ssl_errors(vpninfo);
361                 ENGINE_free(e);
362                 return -EINVAL;
363         }
364
365         if (vpninfo->cert_password) {
366                 if (!ENGINE_ctrl_cmd(e, "PIN", strlen(vpninfo->cert_password),
367                                      vpninfo->cert_password, NULL, 0)) {
368                         vpn_progress(vpninfo, PRG_ERR,
369                                      _("Failed to set TPM SRK password\n"));
370                         openconnect_report_ssl_errors(vpninfo);
371                 }
372         }
373         key = ENGINE_load_private_key(e, vpninfo->sslkey, NULL, NULL);
374         if (!key) {
375                 vpn_progress(vpninfo, PRG_ERR,
376                              _("Failed to load TPM private key\n"));
377                 openconnect_report_ssl_errors(vpninfo);
378                 ENGINE_free(e);
379                 ENGINE_finish(e);
380                 return -EINVAL;
381         }
382         if (!SSL_CTX_use_PrivateKey(vpninfo->https_ctx, key)) {
383                 vpn_progress(vpninfo, PRG_ERR, _("Add key from TPM failed\n"));
384                 openconnect_report_ssl_errors(vpninfo);
385                 ENGINE_free(e);
386                 ENGINE_finish(e);
387                 return -EINVAL;
388         }
389         return 0;
390 }
391 #else
392 static int load_tpm_certificate(struct openconnect_info *vpninfo)
393 {
394         vpn_progress(vpninfo, PRG_ERR,
395                      _("This version of OpenConnect was built without TPM support\n"));
396         return -EINVAL;
397 }
398 #endif
399
400 static int reload_pem_cert(struct openconnect_info *vpninfo)
401 {
402         BIO *b = BIO_new(BIO_s_file_internal());
403
404         if (!b)
405                 return -ENOMEM;
406
407         if (BIO_read_filename(b, vpninfo->cert) <= 0) {
408         err:
409                 BIO_free(b);
410                 vpn_progress(vpninfo, PRG_ERR,
411                              _("Failed to reload X509 cert for expiry check\n"));
412                 openconnect_report_ssl_errors(vpninfo);
413                 return -EIO;
414         }
415         vpninfo->cert_x509 = PEM_read_bio_X509_AUX(b, NULL, NULL, NULL);
416         if (!vpninfo->cert_x509)
417                 goto err;
418
419         return 0;
420 }
421
422 static int load_certificate(struct openconnect_info *vpninfo)
423 {
424         vpn_progress(vpninfo, PRG_TRACE,
425                      _("Using certificate file %s\n"), vpninfo->cert);
426
427         if (vpninfo->cert_type == CERT_TYPE_PKCS12 ||
428             vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
429                 FILE *f;
430                 PKCS12 *p12;
431
432                 f = fopen(vpninfo->cert, "r");
433                 if (!f) {
434                         vpn_progress(vpninfo, PRG_ERR,
435                                      _("Failed to open certificate file %s: %s\n"),
436                                      vpninfo->cert, strerror(errno));
437                         return -ENOENT;
438                 }
439                 p12 = d2i_PKCS12_fp(f, NULL);
440                 fclose(f);
441                 if (p12)
442                         return load_pkcs12_certificate(vpninfo, p12);
443
444                 /* Not PKCS#12 */
445                 if (vpninfo->cert_type == CERT_TYPE_PKCS12) {
446                         vpn_progress(vpninfo, PRG_ERR, _("Read PKCS#12 failed\n"));
447                         openconnect_report_ssl_errors(vpninfo);
448                         return -EINVAL;
449                 }
450                 /* Clear error and fall through to see if it's a PEM file... */
451                 ERR_clear_error();
452         }
453
454         /* It's PEM or TPM now, and either way we need to load the plain cert: */
455         if (!SSL_CTX_use_certificate_chain_file(vpninfo->https_ctx,
456                                                 vpninfo->cert)) {
457                 vpn_progress(vpninfo, PRG_ERR,
458                              _("Loading certificate failed\n"));
459                 openconnect_report_ssl_errors(vpninfo);
460                 return -EINVAL;
461         }
462
463         /* Ew, we can't get it back from the OpenSSL CTX in any sane fashion */
464         reload_pem_cert(vpninfo);
465
466         if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
467                 FILE *f = fopen(vpninfo->sslkey, "r");
468                 char buf[256];
469
470                 if (!f) {
471                         vpn_progress(vpninfo, PRG_ERR,
472                                      _("Failed to open private key file %s: %s\n"),
473                                      vpninfo->cert, strerror(errno));
474                         return -ENOENT;
475                 }
476
477                 buf[255] = 0;
478                 while (fgets(buf, 255, f)) {
479                         if (!strcmp(buf, "-----BEGIN TSS KEY BLOB-----\n")) {
480                                 vpninfo->cert_type = CERT_TYPE_TPM;
481                                 break;
482                         } else if (!strcmp(buf, "-----BEGIN RSA PRIVATE KEY-----\n") ||
483                                    !strcmp(buf, "-----BEGIN DSA PRIVATE KEY-----\n") ||
484                                    !strcmp(buf, "-----BEGIN ENCRYPTED PRIVATE KEY-----\n")) {
485                                 vpninfo->cert_type = CERT_TYPE_PEM;
486                                 break;
487                         }
488                 }
489                 fclose(f);
490                 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
491                         vpn_progress(vpninfo, PRG_ERR,
492                                      _("Failed to identify private key type in '%s'\n"),
493                                      vpninfo->sslkey);
494                         return -EINVAL;
495                 }
496         }
497
498         if (vpninfo->cert_type == CERT_TYPE_TPM)
499                 return load_tpm_certificate(vpninfo);
500
501         /* Standard PEM certificate */
502         if (vpninfo->cert_password) {
503                 SSL_CTX_set_default_passwd_cb(vpninfo->https_ctx,
504                                               pem_pw_cb);
505                 SSL_CTX_set_default_passwd_cb_userdata(vpninfo->https_ctx,
506                                                        vpninfo);
507         }
508  again:
509         if (!SSL_CTX_use_RSAPrivateKey_file(vpninfo->https_ctx, vpninfo->sslkey,
510                                             SSL_FILETYPE_PEM)) {
511                 unsigned long err = ERR_peek_error();
512                 
513                 openconnect_report_ssl_errors(vpninfo);
514
515 #ifndef EVP_F_EVP_DECRYPTFINAL_EX
516 #define EVP_F_EVP_DECRYPTFINAL_EX EVP_F_EVP_DECRYPTFINAL
517 #endif
518                 /* If the user fat-fingered the passphrase, try again */
519                 if (ERR_GET_LIB(err) == ERR_LIB_EVP &&
520                     ERR_GET_FUNC(err) == EVP_F_EVP_DECRYPTFINAL_EX &&
521                     ERR_GET_REASON(err) == EVP_R_BAD_DECRYPT) {
522                         vpn_progress(vpninfo, PRG_ERR,
523                                      _("Loading private key failed (wrong passphrase?)\n"));
524                         goto again;
525                 }
526                 
527                 vpn_progress(vpninfo, PRG_ERR,
528                              _("Loading private key failed (see above errors)\n"));
529                 return -EINVAL;
530         }
531         return 0;
532 }
533
534 static int get_cert_fingerprint(struct openconnect_info *vpninfo,
535                                 X509 *cert, const EVP_MD *type,
536                                 char *buf)
537 {
538         unsigned char md[EVP_MAX_MD_SIZE];
539         unsigned int i, n;
540
541         if (!X509_digest(cert, type, md, &n))
542                 return -ENOMEM;
543
544         for (i=0; i < n; i++)
545                 sprintf(&buf[i*2], "%02X", md[i]);
546
547         return 0;
548 }
549
550 int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
551                              X509 *cert, char *buf)
552 {
553         return get_cert_fingerprint(vpninfo, cert, EVP_md5(), buf);
554 }
555
556 int openconnect_get_cert_sha1(struct openconnect_info *vpninfo,
557                               X509 *cert, char *buf)
558 {
559         return get_cert_fingerprint(vpninfo, cert, EVP_sha1(), buf);
560 }
561
562 static int check_server_cert(struct openconnect_info *vpninfo, X509 *cert)
563 {
564         char fingerprint[EVP_MAX_MD_SIZE * 2 + 1];
565         int ret;
566
567         ret = openconnect_get_cert_sha1(vpninfo, cert, fingerprint);
568         if (ret)
569                 return ret;
570
571         if (strcasecmp(vpninfo->servercert, fingerprint)) {
572                 vpn_progress(vpninfo, PRG_ERR,
573                              _("Server SSL certificate didn't match: %s\n"), fingerprint);
574                 return -EINVAL;
575         }
576         return 0;
577 }
578
579 static int match_hostname_elem(const char *hostname, int helem_len,
580                                const char *match, int melem_len)
581 {
582         if (!helem_len && !melem_len)
583                 return 0;
584
585         if (!helem_len || !melem_len)
586                 return -1;
587
588
589         if (match[0] == '*') {
590                 int i;
591
592                 for (i = 1 ; i <= helem_len; i++) {
593                         if (!match_hostname_elem(hostname + i, helem_len - i,
594                                                  match + 1, melem_len - 1))
595                                 return 0;
596                 }
597                 return -1;
598         }
599
600         /* From the NetBSD (5.1) man page for ctype(3):
601            Values of type char or signed char must first be cast to unsigned char,
602            to ensure that the values are within the correct range.  The result
603            should then be cast to int to avoid warnings from some compilers.
604            We do indeed get warning "array subscript has type 'char'" without
605            the casts. Ick. */
606         if (toupper((int)(unsigned char)hostname[0]) ==
607             toupper((int)(unsigned char)match[0]))
608                 return match_hostname_elem(hostname + 1, helem_len - 1,
609                                            match + 1, melem_len - 1);
610
611         return -1;
612 }
613
614 static int match_hostname(const char *hostname, const char *match)
615 {
616         while (*match) {
617                 const char *h_dot, *m_dot;
618                 int helem_len, melem_len;
619
620                 h_dot = strchr(hostname, '.');
621                 m_dot = strchr(match, '.');
622                 
623                 if (h_dot && m_dot) {
624                         helem_len = h_dot - hostname + 1;
625                         melem_len = m_dot - match + 1;
626                 } else if (!h_dot && !m_dot) {
627                         helem_len = strlen(hostname);
628                         melem_len = strlen(match);
629                 } else
630                         return -1;
631
632
633                 if (match_hostname_elem(hostname, helem_len,
634                                         match, melem_len))
635                         return -1;
636
637                 hostname += helem_len;
638                 match += melem_len;
639         }
640         if (*hostname)
641                 return -1;
642
643         return 0;
644 }
645
646 /* cf. RFC2818 and RFC2459 */
647 static int match_cert_hostname(struct openconnect_info *vpninfo, X509 *peer_cert)
648 {
649         STACK_OF(GENERAL_NAME) *altnames;
650         X509_NAME *subjname;
651         ASN1_STRING *subjasn1;
652         char *subjstr = NULL;
653         int addrlen = 0;
654         int i, altdns = 0;
655         char addrbuf[sizeof(struct in6_addr)];
656         int ret;
657
658         /* Allow GEN_IP in the certificate only if we actually connected
659            by IP address rather than by name. */
660         if (inet_pton(AF_INET, vpninfo->hostname, addrbuf) > 0)
661                 addrlen = 4;
662         else if (inet_pton(AF_INET6, vpninfo->hostname, addrbuf) > 0)
663                 addrlen = 16;
664         else if (vpninfo->hostname[0] == '[' &&
665                  vpninfo->hostname[strlen(vpninfo->hostname)-1] == ']') {
666                 char *p = &vpninfo->hostname[strlen(vpninfo->hostname)-1];
667                 *p = 0;
668                 if (inet_pton(AF_INET6, vpninfo->hostname + 1, addrbuf) > 0)
669                         addrlen = 16;
670                 *p = ']';
671         }
672
673         altnames = X509_get_ext_d2i(peer_cert, NID_subject_alt_name,
674                                     NULL, NULL);
675         for (i = 0; i < sk_GENERAL_NAME_num(altnames); i++) {
676                 const GENERAL_NAME *this = sk_GENERAL_NAME_value(altnames, i);
677
678                 if (this->type == GEN_DNS) {
679                         char *str;
680
681                         int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
682                         if (len < 0)
683                                 continue;
684
685                         altdns = 1;
686
687                         /* We don't like names with embedded NUL */
688                         if (strlen(str) != len)
689                                 continue;
690
691                         if (!match_hostname(vpninfo->hostname, str)) {
692                                 vpn_progress(vpninfo, PRG_TRACE,
693                                              _("Matched DNS altname '%s'\n"),
694                                              str);
695                                 GENERAL_NAMES_free(altnames);
696                                 OPENSSL_free(str);
697                                 return 0;
698                         } else {
699                                 vpn_progress(vpninfo, PRG_TRACE,
700                                              _("No match for altname '%s'\n"),
701                                              str);
702                         }
703                         OPENSSL_free(str);
704                 } else if (this->type == GEN_IPADD && addrlen) {
705                         char host[80];
706                         int family;
707
708                         if (this->d.ip->length == 4) {
709                                 family = AF_INET;
710                         } else if (this->d.ip->length == 16) {
711                                 family = AF_INET6;
712                         } else {
713                                 vpn_progress(vpninfo, PRG_ERR,
714                                              _("Certificate has GEN_IPADD altname with bogus length %d\n"),
715                                              this->d.ip->length);
716                                 continue;
717                         }
718                         
719                         /* We only do this for the debug messages */
720                         inet_ntop(family, this->d.ip->data, host, sizeof(host));
721
722                         if (this->d.ip->length == addrlen &&
723                             !memcmp(addrbuf, this->d.ip->data, addrlen)) {
724                                 vpn_progress(vpninfo, PRG_TRACE,
725                                              _("Matched %s address '%s'\n"),
726                                              (family == AF_INET6)?"IPv6":"IPv4",
727                                              host);
728                                 GENERAL_NAMES_free(altnames);
729                                 return 0;
730                         } else {
731                                 vpn_progress(vpninfo, PRG_TRACE,
732                                              _("No match for %s address '%s'\n"),
733                                              (family == AF_INET6)?"IPv6":"IPv4",
734                                              host);
735                         }
736                 } else if (this->type == GEN_URI) {
737                         char *str;
738                         char *url_proto, *url_host, *url_path, *url_host2;
739                         int url_port;
740                         int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
741
742                         if (len < 0)
743                                 continue;
744
745                         /* We don't like names with embedded NUL */
746                         if (strlen(str) != len)
747                                 continue;
748
749                         if (internal_parse_url(str, &url_proto, &url_host, &url_port, &url_path, 0)) {
750                                 OPENSSL_free(str);
751                                 continue;
752                         }
753
754                         if (!url_proto || strcasecmp(url_proto, "https"))
755                                 goto no_uri_match;
756
757                         if (url_port != vpninfo->port)
758                                 goto no_uri_match;
759
760                         /* Leave url_host as it was so that it can be freed */
761                         url_host2 = url_host;
762                         if (addrlen == 16 && vpninfo->hostname[0] != '[' &&
763                             url_host[0] == '[' && url_host[strlen(url_host)-1] == ']') {
764                                 /* Cope with https://[IPv6]/ when the hostname is bare IPv6 */
765                                 url_host[strlen(url_host)-1] = 0;
766                                 url_host2++;
767                         }
768
769                         if (strcasecmp(vpninfo->hostname, url_host2))
770                                 goto no_uri_match;
771
772                         if (url_path) {
773                                 vpn_progress(vpninfo, PRG_TRACE,
774                                              _("URI '%s' has non-empty path; ignoring\n"),
775                                              str);
776                                 goto no_uri_match_silent;
777                         }
778                         vpn_progress(vpninfo, PRG_TRACE,
779                                      _("Matched URI '%s'\n"),
780                                      str);
781                         free(url_proto);
782                         free(url_host);
783                         free(url_path);
784                         OPENSSL_free(str);
785                         GENERAL_NAMES_free(altnames);
786                         return 0;
787
788                 no_uri_match:
789                         vpn_progress(vpninfo, PRG_TRACE,
790                                      _("No match for URI '%s'\n"),
791                                      str);
792                 no_uri_match_silent:
793                         free(url_proto);
794                         free(url_host);
795                         free(url_path);
796                         OPENSSL_free(str);
797                 }
798         }
799         GENERAL_NAMES_free(altnames);
800
801         /* According to RFC2818, we don't use the legacy subject name if
802            there was an altname with DNS type. */
803         if (altdns) {
804                 vpn_progress(vpninfo, PRG_ERR,
805                              _("No altname in peer cert matched '%s'\n"),
806                              vpninfo->hostname);
807                 return -EINVAL;
808         }
809
810         subjname = X509_get_subject_name(peer_cert);
811         if (!subjname) {
812                 vpn_progress(vpninfo, PRG_ERR,
813                              _("No subject name in peer cert!\n"));
814                 return -EINVAL;
815         }
816
817         /* Find the _last_ (most specific) commonName */
818         i = -1;
819         while (1) {
820                 int j = X509_NAME_get_index_by_NID(subjname, NID_commonName, i);
821                 if (j >= 0)
822                         i = j;
823                 else
824                         break;
825         }
826
827         subjasn1 = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subjname, i));
828
829         i = ASN1_STRING_to_UTF8((void *)&subjstr, subjasn1);
830
831         if (!subjstr || strlen(subjstr) != i) {
832                 vpn_progress(vpninfo, PRG_ERR,
833                              _("Failed to parse subject name in peer cert\n"));
834                 return -EINVAL;
835         }
836         ret = 0;
837
838         if (match_hostname(vpninfo->hostname, subjstr)) {
839                 vpn_progress(vpninfo, PRG_ERR,
840                              _("Peer cert subject mismatch ('%s' != '%s')\n"),
841                              subjstr, vpninfo->hostname);
842                 ret = -EINVAL;
843         } else {
844                 vpn_progress(vpninfo, PRG_TRACE,
845                              _("Matched peer certificate subject name '%s'\n"),
846                              subjstr);
847         }
848
849         OPENSSL_free(subjstr);                    
850         return ret;
851 }
852
853 static int verify_peer(struct openconnect_info *vpninfo, SSL *https_ssl)
854 {
855         X509 *peer_cert;
856         int ret;
857
858         peer_cert = SSL_get_peer_certificate(https_ssl);
859
860         if (vpninfo->servercert) {
861                 /* If given a cert fingerprint on the command line, that's
862                    all we look for */
863                 ret = check_server_cert(vpninfo, peer_cert);
864         } else {
865                 int vfy = SSL_get_verify_result(https_ssl);
866                 const char *err_string = NULL;
867
868                 if (vfy != X509_V_OK)
869                         err_string = X509_verify_cert_error_string(vfy);
870                 else if (match_cert_hostname(vpninfo, peer_cert))
871                         err_string = _("certificate does not match hostname");
872
873                 if (err_string) {
874                         vpn_progress(vpninfo, PRG_INFO,
875                                      _("Server certificate verify failed: %s\n"),
876                                      err_string);
877
878                         if (vpninfo->validate_peer_cert)
879                                 ret = vpninfo->validate_peer_cert(vpninfo->cbdata,
880                                                                   peer_cert,
881                                                                   err_string);
882                         else
883                                 ret = -EINVAL;
884                 } else {
885                         ret = 0;
886                 }
887         }
888         X509_free(peer_cert);
889
890         return ret;
891 }
892
893 static void workaround_openssl_certchain_bug(struct openconnect_info *vpninfo,
894                                              SSL *ssl)
895 {
896         /* OpenSSL has problems with certificate chains -- if there are
897            multiple certs with the same name, it doesn't necessarily
898            choose the _right_ one. (RT#1942)
899            Pick the right ones for ourselves and add them manually. */
900         X509 *cert = SSL_get_certificate(ssl);
901         X509 *cert2;
902         X509_STORE *store = SSL_CTX_get_cert_store(vpninfo->https_ctx);
903         X509_STORE_CTX ctx;
904
905         if (!cert || !store)
906                 return;
907
908         /* If we already have 'supporting' certs, don't add them again */
909         if (vpninfo->https_ctx->extra_certs)
910                 return;
911
912         if (!X509_STORE_CTX_init(&ctx, store, NULL, NULL))
913                 return;
914
915         while (ctx.get_issuer(&cert2, &ctx, cert) == 1) {
916                 char buf[200];
917                 if (cert2 == cert)
918                         break;
919                 if (X509_check_issued(cert2, cert2) == X509_V_OK)
920                         break;
921                 cert = cert2;
922                 X509_NAME_oneline(X509_get_subject_name(cert),
923                                   buf, sizeof(buf));
924                 vpn_progress(vpninfo, PRG_DEBUG,
925                              _("Extra cert from cafile: '%s'\n"), buf);
926                 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert);
927         }
928         X509_STORE_CTX_cleanup(&ctx);
929 }
930
931 #if OPENSSL_VERSION_NUMBER >= 0x00908000
932 static int ssl_app_verify_callback(X509_STORE_CTX *ctx, void *arg)
933 {
934         /* We've seen certificates in the wild which don't have the
935            purpose fields filled in correctly */
936         X509_VERIFY_PARAM_set_purpose(ctx->param, X509_PURPOSE_ANY);
937         return X509_verify_cert(ctx);
938 }
939 #endif
940
941 static int check_certificate_expiry(struct openconnect_info *vpninfo)
942 {
943         ASN1_TIME *notAfter;
944         const char *reason = NULL;
945         time_t t;
946         int i;
947
948         if (!vpninfo->cert_x509)
949                 return 0;
950
951         t = time(NULL);
952         notAfter = X509_get_notAfter(vpninfo->cert_x509);
953         i = X509_cmp_time(notAfter, &t);
954         if (!i) {
955                 vpn_progress(vpninfo, PRG_ERR,
956                              _("Error in client cert notAfter field\n"));
957                 return -EINVAL;
958         } else if (i < 0) {
959                 reason = _("Client certificate has expired at");
960         } else {
961                 t += vpninfo->cert_expire_warning;
962                 i = X509_cmp_time(notAfter, &t);
963                 if (i < 0) {
964                         reason = _("Client certificate expires soon at");
965                 }
966         }
967         if (reason) {
968                 BIO *bp = BIO_new(BIO_s_mem());
969                 BUF_MEM *bm;
970                 const char *expiry = _("<error>");
971                 char zero = 0;
972
973                 if (bp) {
974                         ASN1_TIME_print(bp, notAfter);
975                         BIO_write(bp, &zero, 1);
976                         BIO_get_mem_ptr(bp, &bm);
977                         expiry = bm->data;
978                 }
979                 vpn_progress(vpninfo, PRG_ERR, "%s: %s\n", reason, expiry);
980                 if (bp)
981                         BIO_free(bp);
982         }
983         return 0;
984 }
985 int openconnect_open_https(struct openconnect_info *vpninfo)
986 {
987         method_const SSL_METHOD *ssl3_method;
988         SSL *https_ssl;
989         BIO *https_bio;
990         int ssl_sock;
991         int err;
992
993         if (vpninfo->https_ssl)
994                 return 0;
995
996         if (vpninfo->peer_cert) {
997                 X509_free(vpninfo->peer_cert);
998                 vpninfo->peer_cert = NULL;
999         }
1000
1001         ssl_sock = connect_https_socket(vpninfo);
1002         if (ssl_sock < 0)
1003                 return ssl_sock;
1004
1005         ssl3_method = TLSv1_client_method();
1006         if (!vpninfo->https_ctx) {
1007                 vpninfo->https_ctx = SSL_CTX_new(ssl3_method);
1008
1009                 /* Some servers (or their firewalls) really don't like seeing
1010                    extensions. */
1011 #ifdef SSL_OP_NO_TICKET
1012                 SSL_CTX_set_options (vpninfo->https_ctx, SSL_OP_NO_TICKET);
1013 #endif
1014
1015                 if (vpninfo->cert) {
1016                         err = load_certificate(vpninfo);
1017                         if (err) {
1018                                 vpn_progress(vpninfo, PRG_ERR,
1019                                              _("Loading certificate failed. Aborting.\n"));
1020                                 return err;
1021                         }
1022                         check_certificate_expiry(vpninfo);
1023                 }
1024
1025                 /* We just want to do:
1026                    SSL_CTX_set_purpose(vpninfo->https_ctx, X509_PURPOSE_ANY); 
1027                    ... but it doesn't work with OpenSSL < 0.9.8k because of 
1028                    problems with inheritance (fixed in v1.1.4.6 of
1029                    crypto/x509/x509_vpm.c) so we have to play silly buggers
1030                    instead. This trick doesn't work _either_ in < 0.9.7 but
1031                    I don't know of _any_ workaround which will, and can't
1032                    be bothered to find out either. */
1033 #if OPENSSL_VERSION_NUMBER >= 0x00908000
1034                 SSL_CTX_set_cert_verify_callback(vpninfo->https_ctx,
1035                                                  ssl_app_verify_callback, NULL);
1036 #endif
1037                 SSL_CTX_set_default_verify_paths(vpninfo->https_ctx);
1038
1039                 if (vpninfo->cafile) {
1040                         if (!SSL_CTX_load_verify_locations(vpninfo->https_ctx, vpninfo->cafile, NULL)) {
1041                                 vpn_progress(vpninfo, PRG_ERR,
1042                                              _("Failed to open CA file '%s'\n"),
1043                                              vpninfo->cafile);
1044                                 openconnect_report_ssl_errors(vpninfo);
1045                                 close(ssl_sock);
1046                                 return -EINVAL;
1047                         }
1048                 }
1049
1050         }
1051         https_ssl = SSL_new(vpninfo->https_ctx);
1052         workaround_openssl_certchain_bug(vpninfo, https_ssl);
1053
1054         https_bio = BIO_new_socket(ssl_sock, BIO_NOCLOSE);
1055         BIO_set_nbio(https_bio, 1);
1056         SSL_set_bio(https_ssl, https_bio, https_bio);
1057
1058         vpn_progress(vpninfo, PRG_INFO, _("SSL negotiation with %s\n"),
1059                      vpninfo->hostname);
1060
1061         while ((err = SSL_connect(https_ssl)) <= 0) {
1062                 fd_set wr_set, rd_set;
1063                 int maxfd = ssl_sock;
1064                 
1065                 FD_ZERO(&wr_set);
1066                 FD_ZERO(&rd_set);
1067
1068                 err = SSL_get_error(https_ssl, err);
1069                 if (err == SSL_ERROR_WANT_READ)
1070                         FD_SET(ssl_sock, &rd_set);
1071                 else if (err == SSL_ERROR_WANT_WRITE)
1072                         FD_SET(ssl_sock, &wr_set);
1073                 else {
1074                         vpn_progress(vpninfo, PRG_ERR, _("SSL connection failure\n"));
1075                         openconnect_report_ssl_errors(vpninfo);
1076                         SSL_free(https_ssl);
1077                         close(ssl_sock);
1078                         return -EINVAL;
1079                 }
1080
1081                 if (vpninfo->cancel_fd != -1) {
1082                         FD_SET(vpninfo->cancel_fd, &rd_set);
1083                         if (vpninfo->cancel_fd > ssl_sock)
1084                                 maxfd = vpninfo->cancel_fd;
1085                 }
1086                 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
1087                 if (vpninfo->cancel_fd != -1 &&
1088                     FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
1089                         vpn_progress(vpninfo, PRG_ERR, _("SSL connection cancelled\n"));
1090                         SSL_free(https_ssl);
1091                         close(ssl_sock);
1092                         return -EINVAL;
1093                 }
1094         }
1095
1096         if (verify_peer(vpninfo, https_ssl)) {
1097                 SSL_free(https_ssl);
1098                 close(ssl_sock);
1099                 return -EINVAL;
1100         }
1101
1102         vpninfo->ssl_fd = ssl_sock;
1103         vpninfo->https_ssl = https_ssl;
1104
1105         /* Stash this now, because it might not be available later if the
1106            server has disconnected. */
1107         vpninfo->peer_cert = SSL_get_peer_certificate(vpninfo->https_ssl);
1108
1109         vpn_progress(vpninfo, PRG_INFO, _("Connected to HTTPS on %s\n"),
1110                      vpninfo->hostname);
1111
1112         return 0;
1113 }
1114
1115 void openconnect_close_https(struct openconnect_info *vpninfo)
1116 {
1117         if (vpninfo->peer_cert) {
1118                 X509_free(vpninfo->peer_cert);
1119                 vpninfo->peer_cert = NULL;
1120         }
1121         if (vpninfo->https_ssl) {
1122                 SSL_free(vpninfo->https_ssl);
1123                 vpninfo->https_ssl = NULL;
1124         }
1125         if (vpninfo->ssl_fd != -1) {
1126                 close(vpninfo->ssl_fd);
1127                 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds);
1128                 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
1129                 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds);
1130                 vpninfo->ssl_fd = -1;
1131         }
1132 }
1133
1134 void openconnect_init_openssl(void)
1135 {
1136         SSL_library_init ();
1137         ERR_clear_error ();
1138         SSL_load_error_strings ();
1139         OpenSSL_add_all_algorithms ();
1140 }
1141
1142 char *openconnect_get_cert_details(struct openconnect_info *vpninfo,
1143                                    struct x509_st *cert)
1144 {
1145         BIO *bp = BIO_new(BIO_s_mem());
1146         BUF_MEM *certinfo;
1147         char zero = 0;
1148         char *ret;
1149
1150         X509_print_ex(bp, cert, 0, 0);
1151         BIO_write(bp, &zero, 1);
1152         BIO_get_mem_ptr(bp, &certinfo);
1153
1154         ret = strdup(certinfo->data);
1155         BIO_free(bp);
1156         return ret;
1157 }
1158
1159
1160 int openconnect_local_cert_md5(struct openconnect_info *vpninfo,
1161                                char *buf)
1162 {
1163         buf[0] = 0;
1164
1165         if (!vpninfo->cert_x509)
1166                 return -EIO;
1167
1168         if (get_cert_md5_fingerprint(vpninfo, vpninfo->cert_x509, buf))
1169                 return -EIO;
1170
1171         return 0;
1172 }