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