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