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