Add Android keystore support
[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 <sys/types.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <ctype.h>
30
31 #include <openssl/ssl.h>
32 #include <openssl/err.h>
33 #include <openssl/engine.h>
34 #include <openssl/evp.h>
35 #include <openssl/rand.h>
36 #include <openssl/pkcs12.h>
37 #include <openssl/x509v3.h>
38 #include <openssl/x509.h>
39 #include <openssl/bio.h>
40
41 #include "openconnect-internal.h"
42
43 int openconnect_sha1(unsigned char *result, void *data, int len)
44 {
45         EVP_MD_CTX c;
46
47         EVP_MD_CTX_init(&c);
48         EVP_Digest(data, len, result, NULL, EVP_sha1(), NULL);
49         EVP_MD_CTX_cleanup(&c);
50
51         return 0;
52 }
53
54 int openconnect_get_cert_DER(struct openconnect_info *vpninfo,
55                              OPENCONNECT_X509 *cert, unsigned char **buf)
56 {
57         BIO *bp = BIO_new(BIO_s_mem());
58         BUF_MEM *certinfo;
59         size_t l;
60
61         if (!i2d_X509_bio(bp, cert)) {
62                 BIO_free(bp);
63                 return -EIO;
64         }
65
66         BIO_get_mem_ptr(bp, &certinfo);
67         l = certinfo->length;
68         *buf = malloc(l);
69         if (!*buf) {
70                 BIO_free(bp);
71                 return -ENOMEM;
72         }
73         memcpy(*buf, certinfo->data, l);
74         BIO_free(bp);
75         return l;
76 }
77
78 int openconnect_random(void *bytes, int len)
79 {
80         if (RAND_bytes(bytes, len) != 1)
81                 return -EIO;
82         return 0;
83 }
84
85 /* Helper functions for reading/writing lines over SSL.
86    We could use cURL for the HTTP stuff, but it's overkill */
87
88 int openconnect_SSL_write(struct openconnect_info *vpninfo, char *buf, size_t len)
89 {
90         size_t orig_len = len;
91
92         while (len) {
93                 int done = SSL_write(vpninfo->https_ssl, buf, len);
94
95                 if (done > 0)
96                         len -= done;
97                 else {
98                         int err = SSL_get_error(vpninfo->https_ssl, done);
99                         fd_set wr_set, rd_set;
100                         int maxfd = vpninfo->ssl_fd;
101
102                         FD_ZERO(&wr_set);
103                         FD_ZERO(&rd_set);
104                         
105                         if (err == SSL_ERROR_WANT_READ)
106                                 FD_SET(vpninfo->ssl_fd, &rd_set);
107                         else if (err == SSL_ERROR_WANT_WRITE)
108                                 FD_SET(vpninfo->ssl_fd, &wr_set);
109                         else {
110                                 vpn_progress(vpninfo, PRG_ERR, _("Failed to write to SSL socket"));
111                                 openconnect_report_ssl_errors(vpninfo);
112                                 return -EIO;
113                         }
114                         if (vpninfo->cancel_fd != -1) {
115                                 FD_SET(vpninfo->cancel_fd, &rd_set);
116                                 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
117                                         maxfd = vpninfo->cancel_fd;
118                         }
119                         select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
120                         if (vpninfo->cancel_fd != -1 &&
121                             FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
122                                 vpn_progress(vpninfo, PRG_ERR, _("SSL write cancelled\n"));
123                                 return -EINTR;
124                         }
125                 }
126         }
127         return orig_len;
128 }
129
130 int openconnect_SSL_read(struct openconnect_info *vpninfo, char *buf, size_t len)
131 {
132         int done;
133
134         while ((done = SSL_read(vpninfo->https_ssl, buf, len)) == -1) {
135                 int err = SSL_get_error(vpninfo->https_ssl, done);
136                 fd_set wr_set, rd_set;
137                 int maxfd = vpninfo->ssl_fd;
138
139                 FD_ZERO(&wr_set);
140                 FD_ZERO(&rd_set);
141                         
142                 if (err == SSL_ERROR_WANT_READ)
143                         FD_SET(vpninfo->ssl_fd, &rd_set);
144                 else if (err == SSL_ERROR_WANT_WRITE)
145                         FD_SET(vpninfo->ssl_fd, &wr_set);
146                 else {
147                         vpn_progress(vpninfo, PRG_ERR, _("Failed to read from SSL socket"));
148                         openconnect_report_ssl_errors(vpninfo);
149                         return -EIO;
150                 }
151                 if (vpninfo->cancel_fd != -1) {
152                         FD_SET(vpninfo->cancel_fd, &rd_set);
153                         if (vpninfo->cancel_fd > vpninfo->ssl_fd)
154                                 maxfd = vpninfo->cancel_fd;
155                 }
156                 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
157                 if (vpninfo->cancel_fd != -1 &&
158                     FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
159                         vpn_progress(vpninfo, PRG_ERR, _("SSL read cancelled\n"));
160                         return -EINTR;
161                 }
162         }
163         return done;
164 }
165
166 int openconnect_SSL_gets(struct openconnect_info *vpninfo, char *buf, size_t len)
167 {
168         int i = 0;
169         int ret;
170
171         if (len < 2)
172                 return -EINVAL;
173
174         while (1) {
175                 ret = SSL_read(vpninfo->https_ssl, buf + i, 1);
176                 if (ret == 1) {
177                         if (buf[i] == '\n') {
178                                 buf[i] = 0;
179                                 if (i && buf[i-1] == '\r') {
180                                         buf[i-1] = 0;
181                                         i--;
182                                 }
183                                 return i;
184                         }
185                         i++;
186
187                         if (i >= len - 1) {
188                                 buf[i] = 0;
189                                 return i;
190                         }
191                 } else {
192                         fd_set rd_set, wr_set;
193                         int maxfd = vpninfo->ssl_fd;
194                         
195                         FD_ZERO(&rd_set);
196                         FD_ZERO(&wr_set);
197                         
198                         ret = SSL_get_error(vpninfo->https_ssl, ret);
199                         if (ret == SSL_ERROR_WANT_READ)
200                                 FD_SET(vpninfo->ssl_fd, &rd_set);
201                         else if (ret == SSL_ERROR_WANT_WRITE)
202                                 FD_SET(vpninfo->ssl_fd, &wr_set);
203                         else {
204                                 vpn_progress(vpninfo, PRG_ERR, _("Failed to read from SSL socket\n"));
205                                 openconnect_report_ssl_errors(vpninfo);
206                                 ret = -EIO;
207                                 break;
208                         }
209                         if (vpninfo->cancel_fd != -1) {
210                                 FD_SET(vpninfo->cancel_fd, &rd_set);
211                                 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
212                                         maxfd = vpninfo->cancel_fd;
213                         }
214                         select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
215                         if (vpninfo->cancel_fd != -1 &&
216                             FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
217                                 vpn_progress(vpninfo, PRG_ERR, _("SSL read cancelled\n"));
218                                 ret = -EINTR;
219                                 break;
220                         }
221                 }
222         }
223         buf[i] = 0;
224         return i ?: ret;
225 }
226
227
228 /* UI handling. All this just to handle the PIN callback from the TPM ENGINE,
229    and turn it into a call to our ->process_auth_form function */
230
231 struct ui_data {
232         struct openconnect_info *vpninfo;
233         struct oc_form_opt **last_opt;
234         struct oc_auth_form form;
235 };
236
237 struct ui_form_opt {
238         struct oc_form_opt opt;
239         UI_STRING *uis;
240 };
241
242  /* Ick. But there is no way to pass this sanely through OpenSSL */
243 static struct openconnect_info *ui_vpninfo;
244
245 static int ui_open(UI *ui)
246 {
247         struct openconnect_info *vpninfo = ui_vpninfo; /* Ick */
248         struct ui_data *ui_data;
249
250         if (!vpninfo || !vpninfo->process_auth_form)
251                 return 0;
252         
253         ui_data = malloc(sizeof(*ui_data));
254         if (!ui_data)
255                 return 0;
256
257         memset(ui_data, 0, sizeof(*ui_data));
258         ui_data->last_opt = &ui_data->form.opts;
259         ui_data->vpninfo = vpninfo;
260         ui_data->form.auth_id = (char *)"openssl_ui";
261         UI_add_user_data(ui, ui_data);
262
263         return 1;
264 }
265
266 static int ui_write(UI *ui, UI_STRING *uis)
267 {
268         struct ui_data *ui_data = UI_get0_user_data(ui);
269         struct ui_form_opt *opt;
270
271         switch(UI_get_string_type(uis)) {
272         case UIT_ERROR:
273                 ui_data->form.error = (char *)UI_get0_output_string(uis);
274                 break;
275         case UIT_INFO:
276                 ui_data->form.message = (char *)UI_get0_output_string(uis);
277                 break;
278         case UIT_PROMPT:
279                 opt = malloc(sizeof(*opt));
280                 if (!opt)
281                         return 1;
282                 memset(opt, 0, sizeof(*opt));
283                 opt->uis = uis;
284                 opt->opt.label = opt->opt.name = (char *)UI_get0_output_string(uis);
285                 if (UI_get_input_flags(uis) & UI_INPUT_FLAG_ECHO)
286                         opt->opt.type = OC_FORM_OPT_TEXT;
287                 else
288                         opt->opt.type = OC_FORM_OPT_PASSWORD;
289                 *(ui_data->last_opt) = &opt->opt;
290                 ui_data->last_opt = &opt->opt.next;
291                 break;
292
293         default:
294                 fprintf(stderr, "Unhandled SSL UI request type %d\n",
295                         UI_get_string_type(uis));
296                 return 0;
297         }
298         return 1;
299 }
300
301 static int ui_flush(UI *ui)
302 {
303         struct ui_data *ui_data = UI_get0_user_data(ui);
304         struct openconnect_info *vpninfo = ui_data->vpninfo;
305         struct ui_form_opt *opt;
306         int ret;
307
308         ret = vpninfo->process_auth_form(vpninfo->cbdata, &ui_data->form);
309         if (ret)
310                 return 0;
311
312         for (opt = (struct ui_form_opt *)ui_data->form.opts; opt;
313              opt = (struct ui_form_opt *)opt->opt.next) {
314                 if (opt->opt.value && opt->uis)
315                         UI_set_result(ui, opt->uis, opt->opt.value);
316         }
317         return 1;
318 }
319
320 static int ui_close(UI *ui)
321 {
322         struct ui_data *ui_data = UI_get0_user_data(ui);
323         struct ui_form_opt *opt, *next_opt;
324
325         opt = (struct ui_form_opt *)ui_data->form.opts;
326         while (opt) {
327                 next_opt = (struct ui_form_opt *)opt->opt.next;
328                 if (opt->opt.value)
329                         free(opt->opt.value);
330                 free(opt);
331                 opt = next_opt;
332         }
333         free(ui_data);
334         UI_add_user_data(ui, NULL);
335
336         return 1;
337 }
338
339 static UI_METHOD *create_openssl_ui(struct openconnect_info *vpninfo)
340 {
341         UI_METHOD *ui_method = UI_create_method((char *)"AnyConnect VPN UI");
342
343         /* There is a race condition here because of the use of the
344            static ui_vpninfo pointer. This sucks, but it's OpenSSL's
345            fault and in practice it's *never* going to hurt us.
346
347            This UI is only used for loading certificates from a TPM; for
348            PKCS#12 and PEM files we hook the passphrase request differently.
349            The ui_vpninfo variable is set here, and is used from ui_open()
350            when the TPM ENGINE decides it needs to ask the user for a PIN.
351
352            The race condition exists because theoretically, there
353            could be more than one thread using libopenconnect and
354            trying to authenticate to a VPN server, within the *same*
355            process. And if *both* are using certificates from the TPM,
356            and *both* manage to be within that short window of time
357            between setting ui_vpninfo and invoking ui_open() to fetch
358            the PIN, then one connection's ->process_auth_form() could
359            get a PIN request for the *other* connection. 
360
361            However, the only thing that ever does run libopenconnect more
362            than once from the same process is KDE's NetworkManager support,
363            and NetworkManager doesn't *support* having more than one VPN
364            connected anyway, so first that would have to be fixed and then
365            you'd have to connect to two VPNs simultaneously by clicking
366            'connect' on both at *exactly* the same time and then getting
367            *really* unlucky.
368
369            Oh, and the KDE support won't be using OpenSSL anyway because of
370            licensing conflicts... so although this sucks, I'm not going to
371            lose sleep over it.
372         */
373         ui_vpninfo = vpninfo;
374
375         /* Set up a UI method of our own for password/passphrase requests */
376         UI_method_set_opener(ui_method, ui_open);
377         UI_method_set_writer(ui_method, ui_write);
378         UI_method_set_flusher(ui_method, ui_flush);
379         UI_method_set_closer(ui_method, ui_close);
380
381         return ui_method;
382 }
383
384 static int pem_pw_cb(char *buf, int len, int w, void *v)
385 {
386         struct openconnect_info *vpninfo = v;
387         char *pass = NULL;
388         int plen;
389
390         if (vpninfo->cert_password) {
391                 pass = vpninfo->cert_password;
392                 vpninfo->cert_password = NULL;
393         } else if (request_passphrase(vpninfo, "openconnect_pem",
394                                       &pass, _("Enter PEM pass phrase:")))
395                 return -1;
396
397         plen = strlen(pass);
398
399         if (len <= plen) {
400                 vpn_progress(vpninfo, PRG_ERR,
401                              _("PEM password too long (%d >= %d)\n"),
402                              plen, len);
403                 free(pass);
404                 return -1;
405         }
406
407         memcpy(buf, pass, plen+1);
408         free(pass);
409         return plen;
410 }
411
412 static int load_pkcs12_certificate(struct openconnect_info *vpninfo, PKCS12 *p12)
413 {
414         EVP_PKEY *pkey = NULL;
415         X509 *cert = NULL;
416         STACK_OF(X509) *ca;
417         int ret = 0;
418         char *pass;
419
420         pass = vpninfo->cert_password;
421         vpninfo->cert_password = NULL;
422  retrypass:
423         /* We do this every time round the loop, to work around a bug in
424            OpenSSL < 1.0.0-beta2 -- where the stack at *ca will be freed
425            when PKCS12_parse() returns an error, but *ca is left pointing
426            to the freed memory. */
427         ca = NULL;
428         if (!pass && request_passphrase(vpninfo, "openconnect_pkcs12", &pass,
429                                         _("Enter PKCS#12 pass phrase:")) < 0) {
430                 PKCS12_free(p12);
431                 return -EINVAL;
432         }
433         if (!PKCS12_parse(p12, pass, &pkey, &cert, &ca)) {
434                 unsigned long err = ERR_peek_error();
435
436                 openconnect_report_ssl_errors(vpninfo);
437
438                 if (ERR_GET_LIB(err) == ERR_LIB_PKCS12 &&
439                     ERR_GET_FUNC(err) == PKCS12_F_PKCS12_PARSE &&
440                     ERR_GET_REASON(err) == PKCS12_R_MAC_VERIFY_FAILURE) {
441                         vpn_progress(vpninfo, PRG_ERR,
442                                      _("Parse PKCS#12 failed (wrong passphrase?)\n"));
443                         free(pass);
444                         pass = NULL;
445                         goto retrypass;
446                 }
447
448                 vpn_progress(vpninfo, PRG_ERR,
449                              _("Parse PKCS#12 failed (see above errors)\n"));
450                 PKCS12_free(p12);
451                 free(pass);
452                 return -EINVAL;
453         }
454         free(pass);
455         if (cert) {
456                 char buf[200];
457                 vpninfo->cert_x509 = cert;
458                 SSL_CTX_use_certificate(vpninfo->https_ctx, cert);
459                 X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
460                 vpn_progress(vpninfo, PRG_INFO,
461                              _("Using client certificate '%s'\n"), buf);
462         } else {
463                 vpn_progress(vpninfo, PRG_ERR,
464                              _("PKCS#12 contained no certificate!"));
465                 ret = -EINVAL;
466         }
467
468         if (pkey) {
469                 SSL_CTX_use_PrivateKey(vpninfo->https_ctx, pkey);
470                 EVP_PKEY_free(pkey);
471         } else {
472                 vpn_progress(vpninfo, PRG_ERR,
473                              _("PKCS#12 contained no private key!"));
474                 ret = -EINVAL;
475         }
476
477         /* Only include supporting certificates which are actually necessary */
478         if (ca) {
479                 int i;
480         next:
481                 for (i = 0; i < sk_X509_num(ca); i++) {
482                         X509 *cert2 = sk_X509_value(ca, i);
483                         if (X509_check_issued(cert2, cert) == X509_V_OK) {
484                                 char buf[200];
485
486                                 if (cert2 == cert)
487                                         break;
488                                 if (X509_check_issued(cert2, cert2) == X509_V_OK)
489                                         break;
490
491                                 X509_NAME_oneline(X509_get_subject_name(cert2),
492                                                   buf, sizeof(buf));
493                                 vpn_progress(vpninfo, PRG_DEBUG,
494                                              _("Extra cert from PKCS#12: '%s'\n"), buf);
495                                 CRYPTO_add(&cert2->references, 1, CRYPTO_LOCK_X509);
496                                 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert2);
497                                 cert = cert2;
498                                 goto next;
499                         }
500                 }
501                 sk_X509_pop_free(ca, X509_free);
502         }
503
504         PKCS12_free(p12);
505         return ret;
506 }
507
508 #ifdef HAVE_ENGINE
509 static int load_tpm_certificate(struct openconnect_info *vpninfo)
510 {
511         ENGINE *e;
512         EVP_PKEY *key;
513         UI_METHOD *meth = NULL;
514         int ret = 0;
515
516         ENGINE_load_builtin_engines();
517
518         e = ENGINE_by_id("tpm");
519         if (!e) {
520                 vpn_progress(vpninfo, PRG_ERR, _("Can't load TPM engine.\n"));
521                 openconnect_report_ssl_errors(vpninfo);
522                 return -EINVAL;
523         }
524         if (!ENGINE_init(e) || !ENGINE_set_default_RSA(e) ||
525             !ENGINE_set_default_RAND(e)) {
526                 vpn_progress(vpninfo, PRG_ERR, _("Failed to init TPM engine\n"));
527                 openconnect_report_ssl_errors(vpninfo);
528                 ENGINE_free(e);
529                 return -EINVAL;
530         }
531
532         if (vpninfo->cert_password) {
533                 if (!ENGINE_ctrl_cmd(e, "PIN", strlen(vpninfo->cert_password),
534                                      vpninfo->cert_password, NULL, 0)) {
535                         vpn_progress(vpninfo, PRG_ERR,
536                                      _("Failed to set TPM SRK password\n"));
537                         openconnect_report_ssl_errors(vpninfo);
538                 }
539                 vpninfo->cert_password = NULL;
540                 free(vpninfo->cert_password);
541         } else {
542                 /* Provide our own UI method to handle the PIN callback. */
543                 meth = create_openssl_ui(vpninfo);
544         }
545         key = ENGINE_load_private_key(e, vpninfo->sslkey, meth, NULL);
546         if (meth)
547                 UI_destroy_method(meth);
548         if (!key) {
549                 vpn_progress(vpninfo, PRG_ERR,
550                              _("Failed to load TPM private key\n"));
551                 openconnect_report_ssl_errors(vpninfo);
552                 ret = -EINVAL;
553                 goto out;
554         }
555         if (!SSL_CTX_use_PrivateKey(vpninfo->https_ctx, key)) {
556                 vpn_progress(vpninfo, PRG_ERR, _("Add key from TPM failed\n"));
557                 openconnect_report_ssl_errors(vpninfo);
558                 ret = -EINVAL;
559         }
560         EVP_PKEY_free(key);
561  out:
562         ENGINE_finish(e);
563         ENGINE_free(e);
564         return ret;
565 }
566 #else
567 static int load_tpm_certificate(struct openconnect_info *vpninfo)
568 {
569         vpn_progress(vpninfo, PRG_ERR,
570                      _("This version of OpenConnect was built without TPM support\n"));
571         return -EINVAL;
572 }
573 #endif
574
575 static int reload_pem_cert(struct openconnect_info *vpninfo)
576 {
577         BIO *b = BIO_new(BIO_s_file_internal());
578         char buf[200];
579
580         if (!b)
581                 return -ENOMEM;
582
583         if (BIO_read_filename(b, vpninfo->cert) <= 0) {
584         err:
585                 BIO_free(b);
586                 vpn_progress(vpninfo, PRG_ERR,
587                              _("Failed to reload X509 cert for expiry check\n"));
588                 openconnect_report_ssl_errors(vpninfo);
589                 return -EIO;
590         }
591         vpninfo->cert_x509 = PEM_read_bio_X509_AUX(b, NULL, NULL, NULL);
592         BIO_free(b);
593         if (!vpninfo->cert_x509)
594                 goto err;
595
596         X509_NAME_oneline(X509_get_subject_name(vpninfo->cert_x509), buf, sizeof(buf));
597         vpn_progress(vpninfo, PRG_INFO,
598                              _("Using client certificate '%s'\n"), buf);
599
600         return 0;
601 }
602
603 #ifdef ANDROID_KEYSTORE
604 static BIO *BIO_from_keystore(struct openconnect_info *vpninfo, const char *item)
605 {
606         char content[KEYSTORE_MESSAGE_SIZE];
607         BIO *b;
608         int len;
609         const char *p = item + 9;
610
611         /* Skip first two slashes if the user has given it as
612            keystore://foo ... */
613         if (*p == '/')
614                 p++;
615         if (*p == '/')
616                 p++;
617         len = keystore_get(p, strlen(p), content);
618         if (len < 0) {
619                 vpn_progress(vpninfo, PRG_ERR,
620                              _("Failed to lead item '%s' from keystore\n"),
621                              p);
622                 return NULL;
623         }
624         if (!(b = BIO_new(BIO_s_mem())) || BIO_write(b, content, len) != len) {
625                 vpn_progress(vpninfo, PRG_ERR,
626                              _("Failed to create BIO for keystore item '%s'\n"),
627                                p);
628                 BIO_free(b);
629                 return NULL;
630         }
631         return b;
632 }
633 #endif
634
635 static int is_pem_password_error(struct openconnect_info *vpninfo)
636 {
637         unsigned long err = ERR_peek_error();
638
639         openconnect_report_ssl_errors(vpninfo);
640
641 #ifndef EVP_F_EVP_DECRYPTFINAL_EX
642 #define EVP_F_EVP_DECRYPTFINAL_EX EVP_F_EVP_DECRYPTFINAL
643 #endif
644         /* If the user fat-fingered the passphrase, try again */
645         if (ERR_GET_LIB(err) == ERR_LIB_EVP &&
646             ERR_GET_FUNC(err) == EVP_F_EVP_DECRYPTFINAL_EX &&
647             ERR_GET_REASON(err) == EVP_R_BAD_DECRYPT) {
648                 vpn_progress(vpninfo, PRG_ERR,
649                              _("Loading private key failed (wrong passphrase?)\n"));
650                 return 1;
651         }
652
653         vpn_progress(vpninfo, PRG_ERR,
654                      _("Loading private key failed (see above errors)\n"));
655         return 0;
656 }
657
658 static int load_certificate(struct openconnect_info *vpninfo)
659 {
660         if (!strncmp(vpninfo->sslkey, "pkcs11:", 7) ||
661             !strncmp(vpninfo->cert, "pkcs11:", 7)) {
662                 vpn_progress(vpninfo, PRG_ERR,
663                              _("This binary built without PKCS#11 support\n"));
664                 return -EINVAL;
665         }
666                      
667         vpn_progress(vpninfo, PRG_TRACE,
668                      _("Using certificate file %s\n"), vpninfo->cert);
669
670         if (strncmp(vpninfo->cert, "keystore:", 9) &&
671             (vpninfo->cert_type == CERT_TYPE_PKCS12 ||
672              vpninfo->cert_type == CERT_TYPE_UNKNOWN)) {
673                 FILE *f;
674                 PKCS12 *p12;
675
676                 f = fopen(vpninfo->cert, "r");
677                 if (!f) {
678                         vpn_progress(vpninfo, PRG_ERR,
679                                      _("Failed to open certificate file %s: %s\n"),
680                                      vpninfo->cert, strerror(errno));
681                         return -ENOENT;
682                 }
683                 p12 = d2i_PKCS12_fp(f, NULL);
684                 fclose(f);
685                 if (p12)
686                         return load_pkcs12_certificate(vpninfo, p12);
687
688                 /* Not PKCS#12 */
689                 if (vpninfo->cert_type == CERT_TYPE_PKCS12) {
690                         vpn_progress(vpninfo, PRG_ERR, _("Read PKCS#12 failed\n"));
691                         openconnect_report_ssl_errors(vpninfo);
692                         return -EINVAL;
693                 }
694                 /* Clear error and fall through to see if it's a PEM file... */
695                 ERR_clear_error();
696         }
697
698         /* It's PEM or TPM now, and either way we need to load the plain cert: */
699 #ifdef ANDROID_KEYSTORE
700         if (!strncmp(vpninfo->cert, "keystore:", 9)) {
701                 BIO *b = BIO_from_keystore(vpninfo, vpninfo->cert);
702                 if (!b)
703                         return -EINVAL;
704                 vpninfo->cert_x509 = PEM_read_bio_X509_AUX(b, NULL, pem_pw_cb, vpninfo);
705                 BIO_free(b);
706                 if (!vpninfo->cert_x509) {
707                         vpn_progress(vpninfo, PRG_ERR,
708                                      _("Failed to load X509 certificate from keystore\n"));
709                         openconnect_report_ssl_errors(vpninfo);
710                         BIO_free(b);
711                         return -EINVAL;
712                 }
713                 if (!SSL_CTX_use_certificate(vpninfo->https_ctx, vpninfo->cert_x509)) {
714                         vpn_progress(vpninfo, PRG_ERR,
715                                      _("Failed to use X509 certificate from keystore\n"));
716                         openconnect_report_ssl_errors(vpninfo);
717                         X509_free(vpninfo->cert_x509);
718                         vpninfo->cert_x509 = NULL;
719                         return -EINVAL;
720                 }
721         } else
722 #endif /* ANDROID_KEYSTORE */
723         {
724                 if (!SSL_CTX_use_certificate_chain_file(vpninfo->https_ctx,
725                                                         vpninfo->cert)) {
726                         vpn_progress(vpninfo, PRG_ERR,
727                                      _("Loading certificate failed\n"));
728                         openconnect_report_ssl_errors(vpninfo);
729                         return -EINVAL;
730                 }
731
732                 /* Ew, we can't get it back from the OpenSSL CTX in any sane fashion */
733                 reload_pem_cert(vpninfo);
734         }
735
736 #ifdef ANDROID_KEYSTORE
737         if (!strncmp(vpninfo->sslkey, "keystore:", 9)) {
738                 EVP_PKEY *key;
739                 BIO *b;
740
741         again_android:
742                 b = BIO_from_keystore(vpninfo, vpninfo->sslkey);
743                 if (!b)
744                         return -EINVAL;
745                 key = PEM_read_bio_PrivateKey(b, NULL, pem_pw_cb, vpninfo);
746                 BIO_free(b);
747                 if (!key) {
748                         if (is_pem_password_error(vpninfo))
749                                 goto again_android;
750                         return -EINVAL;
751                 }
752                 if (!SSL_CTX_use_PrivateKey(vpninfo->https_ctx, key)) {
753                         vpn_progress(vpninfo, PRG_ERR,
754                                      _("Failed to use private key from keystore\n"));
755                         EVP_PKEY_free(key);
756                         X509_free(vpninfo->cert_x509);
757                         vpninfo->cert_x509 = NULL;
758                         return -EINVAL;
759                 }
760                 return 0;
761         }
762 #endif /* ANDROID */
763
764         if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
765                 FILE *f = fopen(vpninfo->sslkey, "r");
766                 char buf[256];
767
768                 if (!f) {
769                         vpn_progress(vpninfo, PRG_ERR,
770                                      _("Failed to open private key file %s: %s\n"),
771                                      vpninfo->cert, strerror(errno));
772                         return -ENOENT;
773                 }
774
775                 buf[255] = 0;
776                 while (fgets(buf, 255, f)) {
777                         if (!strcmp(buf, "-----BEGIN TSS KEY BLOB-----\n")) {
778                                 vpninfo->cert_type = CERT_TYPE_TPM;
779                                 break;
780                         } else if (!strcmp(buf, "-----BEGIN RSA PRIVATE KEY-----\n") ||
781                                    !strcmp(buf, "-----BEGIN DSA PRIVATE KEY-----\n") ||
782                                    !strcmp(buf, "-----BEGIN ENCRYPTED PRIVATE KEY-----\n")) {
783                                 vpninfo->cert_type = CERT_TYPE_PEM;
784                                 break;
785                         }
786                 }
787                 fclose(f);
788                 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
789                         vpn_progress(vpninfo, PRG_ERR,
790                                      _("Failed to identify private key type in '%s'\n"),
791                                      vpninfo->sslkey);
792                         return -EINVAL;
793                 }
794         }
795
796         if (vpninfo->cert_type == CERT_TYPE_TPM)
797                 return load_tpm_certificate(vpninfo);
798
799         /* Standard PEM certificate */
800         SSL_CTX_set_default_passwd_cb(vpninfo->https_ctx, pem_pw_cb);
801         SSL_CTX_set_default_passwd_cb_userdata(vpninfo->https_ctx, vpninfo);
802  again:
803         if (!SSL_CTX_use_RSAPrivateKey_file(vpninfo->https_ctx, vpninfo->sslkey,
804                                             SSL_FILETYPE_PEM)) {
805                 if (is_pem_password_error(vpninfo))
806                         goto again;
807                 return -EINVAL;
808         }
809         return 0;
810 }
811
812 static int get_cert_fingerprint(struct openconnect_info *vpninfo,
813                                 OPENCONNECT_X509 *cert, const EVP_MD *type,
814                                 char *buf)
815 {
816         unsigned char md[EVP_MAX_MD_SIZE];
817         unsigned int i, n;
818
819         if (!X509_digest(cert, type, md, &n))
820                 return -ENOMEM;
821
822         for (i=0; i < n; i++)
823                 sprintf(&buf[i*2], "%02X", md[i]);
824
825         return 0;
826 }
827
828 int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
829                              OPENCONNECT_X509 *cert, char *buf)
830 {
831         return get_cert_fingerprint(vpninfo, cert, EVP_md5(), buf);
832 }
833
834 int openconnect_get_cert_sha1(struct openconnect_info *vpninfo,
835                               OPENCONNECT_X509 *cert, char *buf)
836 {
837         return get_cert_fingerprint(vpninfo, cert, EVP_sha1(), buf);
838 }
839
840 static int check_server_cert(struct openconnect_info *vpninfo, X509 *cert)
841 {
842         char fingerprint[EVP_MAX_MD_SIZE * 2 + 1];
843         int ret;
844
845         ret = openconnect_get_cert_sha1(vpninfo, cert, fingerprint);
846         if (ret)
847                 return ret;
848
849         if (strcasecmp(vpninfo->servercert, fingerprint)) {
850                 vpn_progress(vpninfo, PRG_ERR,
851                              _("Server SSL certificate didn't match: %s\n"), fingerprint);
852                 return -EINVAL;
853         }
854         return 0;
855 }
856
857 static int match_hostname_elem(const char *hostname, int helem_len,
858                                const char *match, int melem_len)
859 {
860         if (!helem_len && !melem_len)
861                 return 0;
862
863         if (!helem_len || !melem_len)
864                 return -1;
865
866
867         if (match[0] == '*') {
868                 int i;
869
870                 for (i = 1 ; i <= helem_len; i++) {
871                         if (!match_hostname_elem(hostname + i, helem_len - i,
872                                                  match + 1, melem_len - 1))
873                                 return 0;
874                 }
875                 return -1;
876         }
877
878         /* From the NetBSD (5.1) man page for ctype(3):
879            Values of type char or signed char must first be cast to unsigned char,
880            to ensure that the values are within the correct range.  The result
881            should then be cast to int to avoid warnings from some compilers.
882            We do indeed get warning "array subscript has type 'char'" without
883            the casts. Ick. */
884         if (toupper((int)(unsigned char)hostname[0]) ==
885             toupper((int)(unsigned char)match[0]))
886                 return match_hostname_elem(hostname + 1, helem_len - 1,
887                                            match + 1, melem_len - 1);
888
889         return -1;
890 }
891
892 static int match_hostname(const char *hostname, const char *match)
893 {
894         while (*match) {
895                 const char *h_dot, *m_dot;
896                 int helem_len, melem_len;
897
898                 h_dot = strchr(hostname, '.');
899                 m_dot = strchr(match, '.');
900                 
901                 if (h_dot && m_dot) {
902                         helem_len = h_dot - hostname + 1;
903                         melem_len = m_dot - match + 1;
904                 } else if (!h_dot && !m_dot) {
905                         helem_len = strlen(hostname);
906                         melem_len = strlen(match);
907                 } else
908                         return -1;
909
910
911                 if (match_hostname_elem(hostname, helem_len,
912                                         match, melem_len))
913                         return -1;
914
915                 hostname += helem_len;
916                 match += melem_len;
917         }
918         if (*hostname)
919                 return -1;
920
921         return 0;
922 }
923
924 /* cf. RFC2818 and RFC2459 */
925 static int match_cert_hostname(struct openconnect_info *vpninfo, X509 *peer_cert)
926 {
927         STACK_OF(GENERAL_NAME) *altnames;
928         X509_NAME *subjname;
929         ASN1_STRING *subjasn1;
930         char *subjstr = NULL;
931         int addrlen = 0;
932         int i, altdns = 0;
933         char addrbuf[sizeof(struct in6_addr)];
934         int ret;
935
936         /* Allow GEN_IP in the certificate only if we actually connected
937            by IP address rather than by name. */
938         if (inet_pton(AF_INET, vpninfo->hostname, addrbuf) > 0)
939                 addrlen = 4;
940         else if (inet_pton(AF_INET6, vpninfo->hostname, addrbuf) > 0)
941                 addrlen = 16;
942         else if (vpninfo->hostname[0] == '[' &&
943                  vpninfo->hostname[strlen(vpninfo->hostname)-1] == ']') {
944                 char *p = &vpninfo->hostname[strlen(vpninfo->hostname)-1];
945                 *p = 0;
946                 if (inet_pton(AF_INET6, vpninfo->hostname + 1, addrbuf) > 0)
947                         addrlen = 16;
948                 *p = ']';
949         }
950
951         altnames = X509_get_ext_d2i(peer_cert, NID_subject_alt_name,
952                                     NULL, NULL);
953         for (i = 0; i < sk_GENERAL_NAME_num(altnames); i++) {
954                 const GENERAL_NAME *this = sk_GENERAL_NAME_value(altnames, i);
955
956                 if (this->type == GEN_DNS) {
957                         char *str;
958
959                         int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
960                         if (len < 0)
961                                 continue;
962
963                         altdns = 1;
964
965                         /* We don't like names with embedded NUL */
966                         if (strlen(str) != len)
967                                 continue;
968
969                         if (!match_hostname(vpninfo->hostname, str)) {
970                                 vpn_progress(vpninfo, PRG_TRACE,
971                                              _("Matched DNS altname '%s'\n"),
972                                              str);
973                                 GENERAL_NAMES_free(altnames);
974                                 OPENSSL_free(str);
975                                 return 0;
976                         } else {
977                                 vpn_progress(vpninfo, PRG_TRACE,
978                                              _("No match for altname '%s'\n"),
979                                              str);
980                         }
981                         OPENSSL_free(str);
982                 } else if (this->type == GEN_IPADD && addrlen) {
983                         char host[80];
984                         int family;
985
986                         if (this->d.ip->length == 4) {
987                                 family = AF_INET;
988                         } else if (this->d.ip->length == 16) {
989                                 family = AF_INET6;
990                         } else {
991                                 vpn_progress(vpninfo, PRG_ERR,
992                                              _("Certificate has GEN_IPADD altname with bogus length %d\n"),
993                                              this->d.ip->length);
994                                 continue;
995                         }
996                         
997                         /* We only do this for the debug messages */
998                         inet_ntop(family, this->d.ip->data, host, sizeof(host));
999
1000                         if (this->d.ip->length == addrlen &&
1001                             !memcmp(addrbuf, this->d.ip->data, addrlen)) {
1002                                 vpn_progress(vpninfo, PRG_TRACE,
1003                                              _("Matched %s address '%s'\n"),
1004                                              (family == AF_INET6)?"IPv6":"IPv4",
1005                                              host);
1006                                 GENERAL_NAMES_free(altnames);
1007                                 return 0;
1008                         } else {
1009                                 vpn_progress(vpninfo, PRG_TRACE,
1010                                              _("No match for %s address '%s'\n"),
1011                                              (family == AF_INET6)?"IPv6":"IPv4",
1012                                              host);
1013                         }
1014                 } else if (this->type == GEN_URI) {
1015                         char *str;
1016                         char *url_proto, *url_host, *url_path, *url_host2;
1017                         int url_port;
1018                         int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
1019
1020                         if (len < 0)
1021                                 continue;
1022
1023                         /* We don't like names with embedded NUL */
1024                         if (strlen(str) != len)
1025                                 continue;
1026
1027                         if (internal_parse_url(str, &url_proto, &url_host, &url_port, &url_path, 0)) {
1028                                 OPENSSL_free(str);
1029                                 continue;
1030                         }
1031
1032                         if (!url_proto || strcasecmp(url_proto, "https"))
1033                                 goto no_uri_match;
1034
1035                         if (url_port != vpninfo->port)
1036                                 goto no_uri_match;
1037
1038                         /* Leave url_host as it was so that it can be freed */
1039                         url_host2 = url_host;
1040                         if (addrlen == 16 && vpninfo->hostname[0] != '[' &&
1041                             url_host[0] == '[' && url_host[strlen(url_host)-1] == ']') {
1042                                 /* Cope with https://[IPv6]/ when the hostname is bare IPv6 */
1043                                 url_host[strlen(url_host)-1] = 0;
1044                                 url_host2++;
1045                         }
1046
1047                         if (strcasecmp(vpninfo->hostname, url_host2))
1048                                 goto no_uri_match;
1049
1050                         if (url_path) {
1051                                 vpn_progress(vpninfo, PRG_TRACE,
1052                                              _("URI '%s' has non-empty path; ignoring\n"),
1053                                              str);
1054                                 goto no_uri_match_silent;
1055                         }
1056                         vpn_progress(vpninfo, PRG_TRACE,
1057                                      _("Matched URI '%s'\n"),
1058                                      str);
1059                         free(url_proto);
1060                         free(url_host);
1061                         free(url_path);
1062                         OPENSSL_free(str);
1063                         GENERAL_NAMES_free(altnames);
1064                         return 0;
1065
1066                 no_uri_match:
1067                         vpn_progress(vpninfo, PRG_TRACE,
1068                                      _("No match for URI '%s'\n"),
1069                                      str);
1070                 no_uri_match_silent:
1071                         free(url_proto);
1072                         free(url_host);
1073                         free(url_path);
1074                         OPENSSL_free(str);
1075                 }
1076         }
1077         GENERAL_NAMES_free(altnames);
1078
1079         /* According to RFC2818, we don't use the legacy subject name if
1080            there was an altname with DNS type. */
1081         if (altdns) {
1082                 vpn_progress(vpninfo, PRG_ERR,
1083                              _("No altname in peer cert matched '%s'\n"),
1084                              vpninfo->hostname);
1085                 return -EINVAL;
1086         }
1087
1088         subjname = X509_get_subject_name(peer_cert);
1089         if (!subjname) {
1090                 vpn_progress(vpninfo, PRG_ERR,
1091                              _("No subject name in peer cert!\n"));
1092                 return -EINVAL;
1093         }
1094
1095         /* Find the _last_ (most specific) commonName */
1096         i = -1;
1097         while (1) {
1098                 int j = X509_NAME_get_index_by_NID(subjname, NID_commonName, i);
1099                 if (j >= 0)
1100                         i = j;
1101                 else
1102                         break;
1103         }
1104
1105         subjasn1 = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subjname, i));
1106
1107         i = ASN1_STRING_to_UTF8((void *)&subjstr, subjasn1);
1108
1109         if (!subjstr || strlen(subjstr) != i) {
1110                 vpn_progress(vpninfo, PRG_ERR,
1111                              _("Failed to parse subject name in peer cert\n"));
1112                 return -EINVAL;
1113         }
1114         ret = 0;
1115
1116         if (match_hostname(vpninfo->hostname, subjstr)) {
1117                 vpn_progress(vpninfo, PRG_ERR,
1118                              _("Peer cert subject mismatch ('%s' != '%s')\n"),
1119                              subjstr, vpninfo->hostname);
1120                 ret = -EINVAL;
1121         } else {
1122                 vpn_progress(vpninfo, PRG_TRACE,
1123                              _("Matched peer certificate subject name '%s'\n"),
1124                              subjstr);
1125         }
1126
1127         OPENSSL_free(subjstr);                    
1128         return ret;
1129 }
1130
1131 static int verify_peer(struct openconnect_info *vpninfo, SSL *https_ssl)
1132 {
1133         X509 *peer_cert;
1134         int ret;
1135
1136         peer_cert = SSL_get_peer_certificate(https_ssl);
1137
1138         if (vpninfo->servercert) {
1139                 /* If given a cert fingerprint on the command line, that's
1140                    all we look for */
1141                 ret = check_server_cert(vpninfo, peer_cert);
1142         } else {
1143                 int vfy = SSL_get_verify_result(https_ssl);
1144                 const char *err_string = NULL;
1145
1146                 if (vfy != X509_V_OK)
1147                         err_string = X509_verify_cert_error_string(vfy);
1148                 else if (match_cert_hostname(vpninfo, peer_cert))
1149                         err_string = _("certificate does not match hostname");
1150
1151                 if (err_string) {
1152                         vpn_progress(vpninfo, PRG_INFO,
1153                                      _("Server certificate verify failed: %s\n"),
1154                                      err_string);
1155
1156                         if (vpninfo->validate_peer_cert)
1157                                 ret = vpninfo->validate_peer_cert(vpninfo->cbdata,
1158                                                                   peer_cert,
1159                                                                   err_string);
1160                         else
1161                                 ret = -EINVAL;
1162                 } else {
1163                         ret = 0;
1164                 }
1165         }
1166         X509_free(peer_cert);
1167
1168         return ret;
1169 }
1170
1171 static void workaround_openssl_certchain_bug(struct openconnect_info *vpninfo,
1172                                              SSL *ssl)
1173 {
1174         /* OpenSSL has problems with certificate chains -- if there are
1175            multiple certs with the same name, it doesn't necessarily
1176            choose the _right_ one. (RT#1942)
1177            Pick the right ones for ourselves and add them manually. */
1178         X509 *cert = SSL_get_certificate(ssl);
1179         X509 *cert2;
1180         X509_STORE *store = SSL_CTX_get_cert_store(vpninfo->https_ctx);
1181         X509_STORE_CTX ctx;
1182
1183         if (!cert || !store)
1184                 return;
1185
1186         /* If we already have 'supporting' certs, don't add them again */
1187         if (vpninfo->https_ctx->extra_certs)
1188                 return;
1189
1190         if (!X509_STORE_CTX_init(&ctx, store, NULL, NULL))
1191                 return;
1192
1193         while (ctx.get_issuer(&cert2, &ctx, cert) == 1) {
1194                 char buf[200];
1195                 if (cert2 == cert)
1196                         break;
1197                 if (X509_check_issued(cert2, cert2) == X509_V_OK)
1198                         break;
1199                 cert = cert2;
1200                 X509_NAME_oneline(X509_get_subject_name(cert),
1201                                   buf, sizeof(buf));
1202                 vpn_progress(vpninfo, PRG_DEBUG,
1203                              _("Extra cert from cafile: '%s'\n"), buf);
1204                 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert);
1205         }
1206         X509_STORE_CTX_cleanup(&ctx);
1207 }
1208
1209 #if OPENSSL_VERSION_NUMBER >= 0x00908000
1210 static int ssl_app_verify_callback(X509_STORE_CTX *ctx, void *arg)
1211 {
1212         /* We've seen certificates in the wild which don't have the
1213            purpose fields filled in correctly */
1214         X509_VERIFY_PARAM_set_purpose(ctx->param, X509_PURPOSE_ANY);
1215         return X509_verify_cert(ctx);
1216 }
1217 #endif
1218
1219 static int check_certificate_expiry(struct openconnect_info *vpninfo)
1220 {
1221         ASN1_TIME *notAfter;
1222         const char *reason = NULL;
1223         time_t t;
1224         int i;
1225
1226         if (!vpninfo->cert_x509)
1227                 return 0;
1228
1229         t = time(NULL);
1230         notAfter = X509_get_notAfter(vpninfo->cert_x509);
1231         i = X509_cmp_time(notAfter, &t);
1232         if (!i) {
1233                 vpn_progress(vpninfo, PRG_ERR,
1234                              _("Error in client cert notAfter field\n"));
1235                 return -EINVAL;
1236         } else if (i < 0) {
1237                 reason = _("Client certificate has expired at");
1238         } else {
1239                 t += vpninfo->cert_expire_warning;
1240                 i = X509_cmp_time(notAfter, &t);
1241                 if (i < 0) {
1242                         reason = _("Client certificate expires soon at");
1243                 }
1244         }
1245         if (reason) {
1246                 BIO *bp = BIO_new(BIO_s_mem());
1247                 BUF_MEM *bm;
1248                 const char *expiry = _("<error>");
1249                 char zero = 0;
1250
1251                 if (bp) {
1252                         ASN1_TIME_print(bp, notAfter);
1253                         BIO_write(bp, &zero, 1);
1254                         BIO_get_mem_ptr(bp, &bm);
1255                         expiry = bm->data;
1256                 }
1257                 vpn_progress(vpninfo, PRG_ERR, "%s: %s\n", reason, expiry);
1258                 if (bp)
1259                         BIO_free(bp);
1260         }
1261         return 0;
1262 }
1263 int openconnect_open_https(struct openconnect_info *vpninfo)
1264 {
1265         method_const SSL_METHOD *ssl3_method;
1266         SSL *https_ssl;
1267         BIO *https_bio;
1268         int ssl_sock;
1269         int err;
1270
1271         if (vpninfo->https_ssl)
1272                 return 0;
1273
1274         if (vpninfo->peer_cert) {
1275                 X509_free(vpninfo->peer_cert);
1276                 vpninfo->peer_cert = NULL;
1277         }
1278
1279         ssl_sock = connect_https_socket(vpninfo);
1280         if (ssl_sock < 0)
1281                 return ssl_sock;
1282
1283         ssl3_method = TLSv1_client_method();
1284         if (!vpninfo->https_ctx) {
1285                 vpninfo->https_ctx = SSL_CTX_new(ssl3_method);
1286
1287                 /* Some servers (or their firewalls) really don't like seeing
1288                    extensions. */
1289 #ifdef SSL_OP_NO_TICKET
1290                 SSL_CTX_set_options (vpninfo->https_ctx, SSL_OP_NO_TICKET);
1291 #endif
1292
1293                 if (vpninfo->cert) {
1294                         err = load_certificate(vpninfo);
1295                         if (err) {
1296                                 vpn_progress(vpninfo, PRG_ERR,
1297                                              _("Loading certificate failed. Aborting.\n"));
1298                                 return err;
1299                         }
1300                         check_certificate_expiry(vpninfo);
1301                 }
1302
1303                 /* We just want to do:
1304                    SSL_CTX_set_purpose(vpninfo->https_ctx, X509_PURPOSE_ANY); 
1305                    ... but it doesn't work with OpenSSL < 0.9.8k because of 
1306                    problems with inheritance (fixed in v1.1.4.6 of
1307                    crypto/x509/x509_vpm.c) so we have to play silly buggers
1308                    instead. This trick doesn't work _either_ in < 0.9.7 but
1309                    I don't know of _any_ workaround which will, and can't
1310                    be bothered to find out either. */
1311 #if OPENSSL_VERSION_NUMBER >= 0x00908000
1312                 SSL_CTX_set_cert_verify_callback(vpninfo->https_ctx,
1313                                                  ssl_app_verify_callback, NULL);
1314 #endif
1315                 SSL_CTX_set_default_verify_paths(vpninfo->https_ctx);
1316
1317                 if (vpninfo->cafile) {
1318                         if (!SSL_CTX_load_verify_locations(vpninfo->https_ctx, vpninfo->cafile, NULL)) {
1319                                 vpn_progress(vpninfo, PRG_ERR,
1320                                              _("Failed to open CA file '%s'\n"),
1321                                              vpninfo->cafile);
1322                                 openconnect_report_ssl_errors(vpninfo);
1323                                 close(ssl_sock);
1324                                 return -EINVAL;
1325                         }
1326                 }
1327
1328         }
1329         https_ssl = SSL_new(vpninfo->https_ctx);
1330         workaround_openssl_certchain_bug(vpninfo, https_ssl);
1331
1332         https_bio = BIO_new_socket(ssl_sock, BIO_NOCLOSE);
1333         BIO_set_nbio(https_bio, 1);
1334         SSL_set_bio(https_ssl, https_bio, https_bio);
1335
1336         vpn_progress(vpninfo, PRG_INFO, _("SSL negotiation with %s\n"),
1337                      vpninfo->hostname);
1338
1339         while ((err = SSL_connect(https_ssl)) <= 0) {
1340                 fd_set wr_set, rd_set;
1341                 int maxfd = ssl_sock;
1342                 
1343                 FD_ZERO(&wr_set);
1344                 FD_ZERO(&rd_set);
1345
1346                 err = SSL_get_error(https_ssl, err);
1347                 if (err == SSL_ERROR_WANT_READ)
1348                         FD_SET(ssl_sock, &rd_set);
1349                 else if (err == SSL_ERROR_WANT_WRITE)
1350                         FD_SET(ssl_sock, &wr_set);
1351                 else {
1352                         vpn_progress(vpninfo, PRG_ERR, _("SSL connection failure\n"));
1353                         openconnect_report_ssl_errors(vpninfo);
1354                         SSL_free(https_ssl);
1355                         close(ssl_sock);
1356                         return -EINVAL;
1357                 }
1358
1359                 if (vpninfo->cancel_fd != -1) {
1360                         FD_SET(vpninfo->cancel_fd, &rd_set);
1361                         if (vpninfo->cancel_fd > ssl_sock)
1362                                 maxfd = vpninfo->cancel_fd;
1363                 }
1364                 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
1365                 if (vpninfo->cancel_fd != -1 &&
1366                     FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
1367                         vpn_progress(vpninfo, PRG_ERR, _("SSL connection cancelled\n"));
1368                         SSL_free(https_ssl);
1369                         close(ssl_sock);
1370                         return -EINVAL;
1371                 }
1372         }
1373
1374         if (verify_peer(vpninfo, https_ssl)) {
1375                 SSL_free(https_ssl);
1376                 close(ssl_sock);
1377                 return -EINVAL;
1378         }
1379
1380         vpninfo->ssl_fd = ssl_sock;
1381         vpninfo->https_ssl = https_ssl;
1382
1383         /* Stash this now, because it might not be available later if the
1384            server has disconnected. */
1385         vpninfo->peer_cert = SSL_get_peer_certificate(vpninfo->https_ssl);
1386
1387         vpn_progress(vpninfo, PRG_INFO, _("Connected to HTTPS on %s\n"),
1388                      vpninfo->hostname);
1389
1390         return 0;
1391 }
1392
1393 void openconnect_close_https(struct openconnect_info *vpninfo, int final)
1394 {
1395         if (vpninfo->peer_cert) {
1396                 X509_free(vpninfo->peer_cert);
1397                 vpninfo->peer_cert = NULL;
1398         }
1399         if (vpninfo->https_ssl) {
1400                 SSL_free(vpninfo->https_ssl);
1401                 vpninfo->https_ssl = NULL;
1402         }
1403         if (vpninfo->ssl_fd != -1) {
1404                 close(vpninfo->ssl_fd);
1405                 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds);
1406                 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
1407                 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds);
1408                 vpninfo->ssl_fd = -1;
1409         }
1410         if (final) {
1411                 if (vpninfo->https_ctx) {
1412                         SSL_CTX_free(vpninfo->https_ctx);
1413                         vpninfo->https_ctx = NULL;
1414                 }
1415                 if (vpninfo->cert_x509) {
1416                         X509_free(vpninfo->cert_x509);
1417                         vpninfo->cert_x509 = NULL;
1418                 }
1419         }
1420 }
1421
1422 void openconnect_init_ssl(void)
1423 {
1424         SSL_library_init ();
1425         ERR_clear_error ();
1426         SSL_load_error_strings ();
1427         OpenSSL_add_all_algorithms ();
1428 }
1429
1430 char *openconnect_get_cert_details(struct openconnect_info *vpninfo,
1431                                    OPENCONNECT_X509 *cert)
1432 {
1433         BIO *bp = BIO_new(BIO_s_mem());
1434         BUF_MEM *certinfo;
1435         char zero = 0;
1436         char *ret;
1437
1438         X509_print_ex(bp, cert, 0, 0);
1439         BIO_write(bp, &zero, 1);
1440         BIO_get_mem_ptr(bp, &certinfo);
1441
1442         ret = strdup(certinfo->data);
1443         BIO_free(bp);
1444         return ret;
1445 }
1446
1447
1448 int openconnect_local_cert_md5(struct openconnect_info *vpninfo,
1449                                char *buf)
1450 {
1451         buf[0] = 0;
1452
1453         if (!vpninfo->cert_x509)
1454                 return -EIO;
1455
1456         if (get_cert_md5_fingerprint(vpninfo, vpninfo->cert_x509, buf))
1457                 return -EIO;
1458
1459         return 0;
1460 }