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