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