OpenSSL: Free BIO leak in reload_pem_cert()
[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         int ret = 0;
514
515         ENGINE_load_builtin_engines();
516
517         e = ENGINE_by_id("tpm");
518         if (!e) {
519                 vpn_progress(vpninfo, PRG_ERR, _("Can't load TPM engine.\n"));
520                 openconnect_report_ssl_errors(vpninfo);
521                 return -EINVAL;
522         }
523         if (!ENGINE_init(e) || !ENGINE_set_default_RSA(e) ||
524             !ENGINE_set_default_RAND(e)) {
525                 vpn_progress(vpninfo, PRG_ERR, _("Failed to init TPM engine\n"));
526                 openconnect_report_ssl_errors(vpninfo);
527                 ENGINE_free(e);
528                 return -EINVAL;
529         }
530
531         if (vpninfo->cert_password) {
532                 if (!ENGINE_ctrl_cmd(e, "PIN", strlen(vpninfo->cert_password),
533                                      vpninfo->cert_password, NULL, 0)) {
534                         vpn_progress(vpninfo, PRG_ERR,
535                                      _("Failed to set TPM SRK password\n"));
536                         openconnect_report_ssl_errors(vpninfo);
537                 }
538                 vpninfo->cert_password = NULL;
539                 free(vpninfo->cert_password);
540         } else {
541                 /* Provide our own UI method to handle the PIN callback. */
542                 meth = create_openssl_ui(vpninfo);
543         }
544         key = ENGINE_load_private_key(e, vpninfo->sslkey, meth, NULL);
545         if (meth)
546                 UI_destroy_method(meth);
547         if (!key) {
548                 vpn_progress(vpninfo, PRG_ERR,
549                              _("Failed to load TPM private key\n"));
550                 openconnect_report_ssl_errors(vpninfo);
551                 ret = -EINVAL;
552                 goto out;
553         }
554         if (!SSL_CTX_use_PrivateKey(vpninfo->https_ctx, key)) {
555                 vpn_progress(vpninfo, PRG_ERR, _("Add key from TPM failed\n"));
556                 openconnect_report_ssl_errors(vpninfo);
557                 ret = -EINVAL;
558         }
559         EVP_PKEY_free(key);
560  out:
561         ENGINE_finish(e);
562         ENGINE_free(e);
563         return ret;
564 }
565 #else
566 static int load_tpm_certificate(struct openconnect_info *vpninfo)
567 {
568         vpn_progress(vpninfo, PRG_ERR,
569                      _("This version of OpenConnect was built without TPM support\n"));
570         return -EINVAL;
571 }
572 #endif
573
574 static int reload_pem_cert(struct openconnect_info *vpninfo)
575 {
576         BIO *b = BIO_new(BIO_s_file_internal());
577         char buf[200];
578
579         if (!b)
580                 return -ENOMEM;
581
582         if (BIO_read_filename(b, vpninfo->cert) <= 0) {
583         err:
584                 BIO_free(b);
585                 vpn_progress(vpninfo, PRG_ERR,
586                              _("Failed to reload X509 cert for expiry check\n"));
587                 openconnect_report_ssl_errors(vpninfo);
588                 return -EIO;
589         }
590         vpninfo->cert_x509 = PEM_read_bio_X509_AUX(b, NULL, NULL, NULL);
591         BIO_free(b);
592         if (!vpninfo->cert_x509)
593                 goto err;
594
595         X509_NAME_oneline(X509_get_subject_name(vpninfo->cert_x509), buf, sizeof(buf));
596         vpn_progress(vpninfo, PRG_INFO,
597                              _("Using client certificate '%s'\n"), buf);
598
599         return 0;
600 }
601
602 static int load_certificate(struct openconnect_info *vpninfo)
603 {
604         if (!strncmp(vpninfo->sslkey, "pkcs11:", 7) ||
605             !strncmp(vpninfo->cert, "pkcs11:", 7)) {
606                 vpn_progress(vpninfo, PRG_ERR,
607                              _("This binary built without PKCS#11 support\n"));
608                 return -EINVAL;
609         }
610                      
611         vpn_progress(vpninfo, PRG_TRACE,
612                      _("Using certificate file %s\n"), vpninfo->cert);
613
614         if (vpninfo->cert_type == CERT_TYPE_PKCS12 ||
615             vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
616                 FILE *f;
617                 PKCS12 *p12;
618
619                 f = fopen(vpninfo->cert, "r");
620                 if (!f) {
621                         vpn_progress(vpninfo, PRG_ERR,
622                                      _("Failed to open certificate file %s: %s\n"),
623                                      vpninfo->cert, strerror(errno));
624                         return -ENOENT;
625                 }
626                 p12 = d2i_PKCS12_fp(f, NULL);
627                 fclose(f);
628                 if (p12)
629                         return load_pkcs12_certificate(vpninfo, p12);
630
631                 /* Not PKCS#12 */
632                 if (vpninfo->cert_type == CERT_TYPE_PKCS12) {
633                         vpn_progress(vpninfo, PRG_ERR, _("Read PKCS#12 failed\n"));
634                         openconnect_report_ssl_errors(vpninfo);
635                         return -EINVAL;
636                 }
637                 /* Clear error and fall through to see if it's a PEM file... */
638                 ERR_clear_error();
639         }
640
641         /* It's PEM or TPM now, and either way we need to load the plain cert: */
642         if (!SSL_CTX_use_certificate_chain_file(vpninfo->https_ctx,
643                                                 vpninfo->cert)) {
644                 vpn_progress(vpninfo, PRG_ERR,
645                              _("Loading certificate failed\n"));
646                 openconnect_report_ssl_errors(vpninfo);
647                 return -EINVAL;
648         }
649
650         /* Ew, we can't get it back from the OpenSSL CTX in any sane fashion */
651         reload_pem_cert(vpninfo);
652
653         if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
654                 FILE *f = fopen(vpninfo->sslkey, "r");
655                 char buf[256];
656
657                 if (!f) {
658                         vpn_progress(vpninfo, PRG_ERR,
659                                      _("Failed to open private key file %s: %s\n"),
660                                      vpninfo->cert, strerror(errno));
661                         return -ENOENT;
662                 }
663
664                 buf[255] = 0;
665                 while (fgets(buf, 255, f)) {
666                         if (!strcmp(buf, "-----BEGIN TSS KEY BLOB-----\n")) {
667                                 vpninfo->cert_type = CERT_TYPE_TPM;
668                                 break;
669                         } else if (!strcmp(buf, "-----BEGIN RSA PRIVATE KEY-----\n") ||
670                                    !strcmp(buf, "-----BEGIN DSA PRIVATE KEY-----\n") ||
671                                    !strcmp(buf, "-----BEGIN ENCRYPTED PRIVATE KEY-----\n")) {
672                                 vpninfo->cert_type = CERT_TYPE_PEM;
673                                 break;
674                         }
675                 }
676                 fclose(f);
677                 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
678                         vpn_progress(vpninfo, PRG_ERR,
679                                      _("Failed to identify private key type in '%s'\n"),
680                                      vpninfo->sslkey);
681                         return -EINVAL;
682                 }
683         }
684
685         if (vpninfo->cert_type == CERT_TYPE_TPM)
686                 return load_tpm_certificate(vpninfo);
687
688         /* Standard PEM certificate */
689         SSL_CTX_set_default_passwd_cb(vpninfo->https_ctx, pem_pw_cb);
690         SSL_CTX_set_default_passwd_cb_userdata(vpninfo->https_ctx, vpninfo);
691  again:
692         if (!SSL_CTX_use_RSAPrivateKey_file(vpninfo->https_ctx, vpninfo->sslkey,
693                                             SSL_FILETYPE_PEM)) {
694                 unsigned long err = ERR_peek_error();
695                 
696                 openconnect_report_ssl_errors(vpninfo);
697
698 #ifndef EVP_F_EVP_DECRYPTFINAL_EX
699 #define EVP_F_EVP_DECRYPTFINAL_EX EVP_F_EVP_DECRYPTFINAL
700 #endif
701                 /* If the user fat-fingered the passphrase, try again */
702                 if (ERR_GET_LIB(err) == ERR_LIB_EVP &&
703                     ERR_GET_FUNC(err) == EVP_F_EVP_DECRYPTFINAL_EX &&
704                     ERR_GET_REASON(err) == EVP_R_BAD_DECRYPT) {
705                         vpn_progress(vpninfo, PRG_ERR,
706                                      _("Loading private key failed (wrong passphrase?)\n"));
707                         goto again;
708                 }
709                 
710                 vpn_progress(vpninfo, PRG_ERR,
711                              _("Loading private key failed (see above errors)\n"));
712                 return -EINVAL;
713         }
714         return 0;
715 }
716
717 static int get_cert_fingerprint(struct openconnect_info *vpninfo,
718                                 OPENCONNECT_X509 *cert, const EVP_MD *type,
719                                 char *buf)
720 {
721         unsigned char md[EVP_MAX_MD_SIZE];
722         unsigned int i, n;
723
724         if (!X509_digest(cert, type, md, &n))
725                 return -ENOMEM;
726
727         for (i=0; i < n; i++)
728                 sprintf(&buf[i*2], "%02X", md[i]);
729
730         return 0;
731 }
732
733 int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
734                              OPENCONNECT_X509 *cert, char *buf)
735 {
736         return get_cert_fingerprint(vpninfo, cert, EVP_md5(), buf);
737 }
738
739 int openconnect_get_cert_sha1(struct openconnect_info *vpninfo,
740                               OPENCONNECT_X509 *cert, char *buf)
741 {
742         return get_cert_fingerprint(vpninfo, cert, EVP_sha1(), buf);
743 }
744
745 static int check_server_cert(struct openconnect_info *vpninfo, X509 *cert)
746 {
747         char fingerprint[EVP_MAX_MD_SIZE * 2 + 1];
748         int ret;
749
750         ret = openconnect_get_cert_sha1(vpninfo, cert, fingerprint);
751         if (ret)
752                 return ret;
753
754         if (strcasecmp(vpninfo->servercert, fingerprint)) {
755                 vpn_progress(vpninfo, PRG_ERR,
756                              _("Server SSL certificate didn't match: %s\n"), fingerprint);
757                 return -EINVAL;
758         }
759         return 0;
760 }
761
762 static int match_hostname_elem(const char *hostname, int helem_len,
763                                const char *match, int melem_len)
764 {
765         if (!helem_len && !melem_len)
766                 return 0;
767
768         if (!helem_len || !melem_len)
769                 return -1;
770
771
772         if (match[0] == '*') {
773                 int i;
774
775                 for (i = 1 ; i <= helem_len; i++) {
776                         if (!match_hostname_elem(hostname + i, helem_len - i,
777                                                  match + 1, melem_len - 1))
778                                 return 0;
779                 }
780                 return -1;
781         }
782
783         /* From the NetBSD (5.1) man page for ctype(3):
784            Values of type char or signed char must first be cast to unsigned char,
785            to ensure that the values are within the correct range.  The result
786            should then be cast to int to avoid warnings from some compilers.
787            We do indeed get warning "array subscript has type 'char'" without
788            the casts. Ick. */
789         if (toupper((int)(unsigned char)hostname[0]) ==
790             toupper((int)(unsigned char)match[0]))
791                 return match_hostname_elem(hostname + 1, helem_len - 1,
792                                            match + 1, melem_len - 1);
793
794         return -1;
795 }
796
797 static int match_hostname(const char *hostname, const char *match)
798 {
799         while (*match) {
800                 const char *h_dot, *m_dot;
801                 int helem_len, melem_len;
802
803                 h_dot = strchr(hostname, '.');
804                 m_dot = strchr(match, '.');
805                 
806                 if (h_dot && m_dot) {
807                         helem_len = h_dot - hostname + 1;
808                         melem_len = m_dot - match + 1;
809                 } else if (!h_dot && !m_dot) {
810                         helem_len = strlen(hostname);
811                         melem_len = strlen(match);
812                 } else
813                         return -1;
814
815
816                 if (match_hostname_elem(hostname, helem_len,
817                                         match, melem_len))
818                         return -1;
819
820                 hostname += helem_len;
821                 match += melem_len;
822         }
823         if (*hostname)
824                 return -1;
825
826         return 0;
827 }
828
829 /* cf. RFC2818 and RFC2459 */
830 static int match_cert_hostname(struct openconnect_info *vpninfo, X509 *peer_cert)
831 {
832         STACK_OF(GENERAL_NAME) *altnames;
833         X509_NAME *subjname;
834         ASN1_STRING *subjasn1;
835         char *subjstr = NULL;
836         int addrlen = 0;
837         int i, altdns = 0;
838         char addrbuf[sizeof(struct in6_addr)];
839         int ret;
840
841         /* Allow GEN_IP in the certificate only if we actually connected
842            by IP address rather than by name. */
843         if (inet_pton(AF_INET, vpninfo->hostname, addrbuf) > 0)
844                 addrlen = 4;
845         else if (inet_pton(AF_INET6, vpninfo->hostname, addrbuf) > 0)
846                 addrlen = 16;
847         else if (vpninfo->hostname[0] == '[' &&
848                  vpninfo->hostname[strlen(vpninfo->hostname)-1] == ']') {
849                 char *p = &vpninfo->hostname[strlen(vpninfo->hostname)-1];
850                 *p = 0;
851                 if (inet_pton(AF_INET6, vpninfo->hostname + 1, addrbuf) > 0)
852                         addrlen = 16;
853                 *p = ']';
854         }
855
856         altnames = X509_get_ext_d2i(peer_cert, NID_subject_alt_name,
857                                     NULL, NULL);
858         for (i = 0; i < sk_GENERAL_NAME_num(altnames); i++) {
859                 const GENERAL_NAME *this = sk_GENERAL_NAME_value(altnames, i);
860
861                 if (this->type == GEN_DNS) {
862                         char *str;
863
864                         int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
865                         if (len < 0)
866                                 continue;
867
868                         altdns = 1;
869
870                         /* We don't like names with embedded NUL */
871                         if (strlen(str) != len)
872                                 continue;
873
874                         if (!match_hostname(vpninfo->hostname, str)) {
875                                 vpn_progress(vpninfo, PRG_TRACE,
876                                              _("Matched DNS altname '%s'\n"),
877                                              str);
878                                 GENERAL_NAMES_free(altnames);
879                                 OPENSSL_free(str);
880                                 return 0;
881                         } else {
882                                 vpn_progress(vpninfo, PRG_TRACE,
883                                              _("No match for altname '%s'\n"),
884                                              str);
885                         }
886                         OPENSSL_free(str);
887                 } else if (this->type == GEN_IPADD && addrlen) {
888                         char host[80];
889                         int family;
890
891                         if (this->d.ip->length == 4) {
892                                 family = AF_INET;
893                         } else if (this->d.ip->length == 16) {
894                                 family = AF_INET6;
895                         } else {
896                                 vpn_progress(vpninfo, PRG_ERR,
897                                              _("Certificate has GEN_IPADD altname with bogus length %d\n"),
898                                              this->d.ip->length);
899                                 continue;
900                         }
901                         
902                         /* We only do this for the debug messages */
903                         inet_ntop(family, this->d.ip->data, host, sizeof(host));
904
905                         if (this->d.ip->length == addrlen &&
906                             !memcmp(addrbuf, this->d.ip->data, addrlen)) {
907                                 vpn_progress(vpninfo, PRG_TRACE,
908                                              _("Matched %s address '%s'\n"),
909                                              (family == AF_INET6)?"IPv6":"IPv4",
910                                              host);
911                                 GENERAL_NAMES_free(altnames);
912                                 return 0;
913                         } else {
914                                 vpn_progress(vpninfo, PRG_TRACE,
915                                              _("No match for %s address '%s'\n"),
916                                              (family == AF_INET6)?"IPv6":"IPv4",
917                                              host);
918                         }
919                 } else if (this->type == GEN_URI) {
920                         char *str;
921                         char *url_proto, *url_host, *url_path, *url_host2;
922                         int url_port;
923                         int len = ASN1_STRING_to_UTF8((void *)&str, this->d.ia5);
924
925                         if (len < 0)
926                                 continue;
927
928                         /* We don't like names with embedded NUL */
929                         if (strlen(str) != len)
930                                 continue;
931
932                         if (internal_parse_url(str, &url_proto, &url_host, &url_port, &url_path, 0)) {
933                                 OPENSSL_free(str);
934                                 continue;
935                         }
936
937                         if (!url_proto || strcasecmp(url_proto, "https"))
938                                 goto no_uri_match;
939
940                         if (url_port != vpninfo->port)
941                                 goto no_uri_match;
942
943                         /* Leave url_host as it was so that it can be freed */
944                         url_host2 = url_host;
945                         if (addrlen == 16 && vpninfo->hostname[0] != '[' &&
946                             url_host[0] == '[' && url_host[strlen(url_host)-1] == ']') {
947                                 /* Cope with https://[IPv6]/ when the hostname is bare IPv6 */
948                                 url_host[strlen(url_host)-1] = 0;
949                                 url_host2++;
950                         }
951
952                         if (strcasecmp(vpninfo->hostname, url_host2))
953                                 goto no_uri_match;
954
955                         if (url_path) {
956                                 vpn_progress(vpninfo, PRG_TRACE,
957                                              _("URI '%s' has non-empty path; ignoring\n"),
958                                              str);
959                                 goto no_uri_match_silent;
960                         }
961                         vpn_progress(vpninfo, PRG_TRACE,
962                                      _("Matched URI '%s'\n"),
963                                      str);
964                         free(url_proto);
965                         free(url_host);
966                         free(url_path);
967                         OPENSSL_free(str);
968                         GENERAL_NAMES_free(altnames);
969                         return 0;
970
971                 no_uri_match:
972                         vpn_progress(vpninfo, PRG_TRACE,
973                                      _("No match for URI '%s'\n"),
974                                      str);
975                 no_uri_match_silent:
976                         free(url_proto);
977                         free(url_host);
978                         free(url_path);
979                         OPENSSL_free(str);
980                 }
981         }
982         GENERAL_NAMES_free(altnames);
983
984         /* According to RFC2818, we don't use the legacy subject name if
985            there was an altname with DNS type. */
986         if (altdns) {
987                 vpn_progress(vpninfo, PRG_ERR,
988                              _("No altname in peer cert matched '%s'\n"),
989                              vpninfo->hostname);
990                 return -EINVAL;
991         }
992
993         subjname = X509_get_subject_name(peer_cert);
994         if (!subjname) {
995                 vpn_progress(vpninfo, PRG_ERR,
996                              _("No subject name in peer cert!\n"));
997                 return -EINVAL;
998         }
999
1000         /* Find the _last_ (most specific) commonName */
1001         i = -1;
1002         while (1) {
1003                 int j = X509_NAME_get_index_by_NID(subjname, NID_commonName, i);
1004                 if (j >= 0)
1005                         i = j;
1006                 else
1007                         break;
1008         }
1009
1010         subjasn1 = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subjname, i));
1011
1012         i = ASN1_STRING_to_UTF8((void *)&subjstr, subjasn1);
1013
1014         if (!subjstr || strlen(subjstr) != i) {
1015                 vpn_progress(vpninfo, PRG_ERR,
1016                              _("Failed to parse subject name in peer cert\n"));
1017                 return -EINVAL;
1018         }
1019         ret = 0;
1020
1021         if (match_hostname(vpninfo->hostname, subjstr)) {
1022                 vpn_progress(vpninfo, PRG_ERR,
1023                              _("Peer cert subject mismatch ('%s' != '%s')\n"),
1024                              subjstr, vpninfo->hostname);
1025                 ret = -EINVAL;
1026         } else {
1027                 vpn_progress(vpninfo, PRG_TRACE,
1028                              _("Matched peer certificate subject name '%s'\n"),
1029                              subjstr);
1030         }
1031
1032         OPENSSL_free(subjstr);                    
1033         return ret;
1034 }
1035
1036 static int verify_peer(struct openconnect_info *vpninfo, SSL *https_ssl)
1037 {
1038         X509 *peer_cert;
1039         int ret;
1040
1041         peer_cert = SSL_get_peer_certificate(https_ssl);
1042
1043         if (vpninfo->servercert) {
1044                 /* If given a cert fingerprint on the command line, that's
1045                    all we look for */
1046                 ret = check_server_cert(vpninfo, peer_cert);
1047         } else {
1048                 int vfy = SSL_get_verify_result(https_ssl);
1049                 const char *err_string = NULL;
1050
1051                 if (vfy != X509_V_OK)
1052                         err_string = X509_verify_cert_error_string(vfy);
1053                 else if (match_cert_hostname(vpninfo, peer_cert))
1054                         err_string = _("certificate does not match hostname");
1055
1056                 if (err_string) {
1057                         vpn_progress(vpninfo, PRG_INFO,
1058                                      _("Server certificate verify failed: %s\n"),
1059                                      err_string);
1060
1061                         if (vpninfo->validate_peer_cert)
1062                                 ret = vpninfo->validate_peer_cert(vpninfo->cbdata,
1063                                                                   peer_cert,
1064                                                                   err_string);
1065                         else
1066                                 ret = -EINVAL;
1067                 } else {
1068                         ret = 0;
1069                 }
1070         }
1071         X509_free(peer_cert);
1072
1073         return ret;
1074 }
1075
1076 static void workaround_openssl_certchain_bug(struct openconnect_info *vpninfo,
1077                                              SSL *ssl)
1078 {
1079         /* OpenSSL has problems with certificate chains -- if there are
1080            multiple certs with the same name, it doesn't necessarily
1081            choose the _right_ one. (RT#1942)
1082            Pick the right ones for ourselves and add them manually. */
1083         X509 *cert = SSL_get_certificate(ssl);
1084         X509 *cert2;
1085         X509_STORE *store = SSL_CTX_get_cert_store(vpninfo->https_ctx);
1086         X509_STORE_CTX ctx;
1087
1088         if (!cert || !store)
1089                 return;
1090
1091         /* If we already have 'supporting' certs, don't add them again */
1092         if (vpninfo->https_ctx->extra_certs)
1093                 return;
1094
1095         if (!X509_STORE_CTX_init(&ctx, store, NULL, NULL))
1096                 return;
1097
1098         while (ctx.get_issuer(&cert2, &ctx, cert) == 1) {
1099                 char buf[200];
1100                 if (cert2 == cert)
1101                         break;
1102                 if (X509_check_issued(cert2, cert2) == X509_V_OK)
1103                         break;
1104                 cert = cert2;
1105                 X509_NAME_oneline(X509_get_subject_name(cert),
1106                                   buf, sizeof(buf));
1107                 vpn_progress(vpninfo, PRG_DEBUG,
1108                              _("Extra cert from cafile: '%s'\n"), buf);
1109                 SSL_CTX_add_extra_chain_cert(vpninfo->https_ctx, cert);
1110         }
1111         X509_STORE_CTX_cleanup(&ctx);
1112 }
1113
1114 #if OPENSSL_VERSION_NUMBER >= 0x00908000
1115 static int ssl_app_verify_callback(X509_STORE_CTX *ctx, void *arg)
1116 {
1117         /* We've seen certificates in the wild which don't have the
1118            purpose fields filled in correctly */
1119         X509_VERIFY_PARAM_set_purpose(ctx->param, X509_PURPOSE_ANY);
1120         return X509_verify_cert(ctx);
1121 }
1122 #endif
1123
1124 static int check_certificate_expiry(struct openconnect_info *vpninfo)
1125 {
1126         ASN1_TIME *notAfter;
1127         const char *reason = NULL;
1128         time_t t;
1129         int i;
1130
1131         if (!vpninfo->cert_x509)
1132                 return 0;
1133
1134         t = time(NULL);
1135         notAfter = X509_get_notAfter(vpninfo->cert_x509);
1136         i = X509_cmp_time(notAfter, &t);
1137         if (!i) {
1138                 vpn_progress(vpninfo, PRG_ERR,
1139                              _("Error in client cert notAfter field\n"));
1140                 return -EINVAL;
1141         } else if (i < 0) {
1142                 reason = _("Client certificate has expired at");
1143         } else {
1144                 t += vpninfo->cert_expire_warning;
1145                 i = X509_cmp_time(notAfter, &t);
1146                 if (i < 0) {
1147                         reason = _("Client certificate expires soon at");
1148                 }
1149         }
1150         if (reason) {
1151                 BIO *bp = BIO_new(BIO_s_mem());
1152                 BUF_MEM *bm;
1153                 const char *expiry = _("<error>");
1154                 char zero = 0;
1155
1156                 if (bp) {
1157                         ASN1_TIME_print(bp, notAfter);
1158                         BIO_write(bp, &zero, 1);
1159                         BIO_get_mem_ptr(bp, &bm);
1160                         expiry = bm->data;
1161                 }
1162                 vpn_progress(vpninfo, PRG_ERR, "%s: %s\n", reason, expiry);
1163                 if (bp)
1164                         BIO_free(bp);
1165         }
1166         return 0;
1167 }
1168 int openconnect_open_https(struct openconnect_info *vpninfo)
1169 {
1170         method_const SSL_METHOD *ssl3_method;
1171         SSL *https_ssl;
1172         BIO *https_bio;
1173         int ssl_sock;
1174         int err;
1175
1176         if (vpninfo->https_ssl)
1177                 return 0;
1178
1179         if (vpninfo->peer_cert) {
1180                 X509_free(vpninfo->peer_cert);
1181                 vpninfo->peer_cert = NULL;
1182         }
1183
1184         ssl_sock = connect_https_socket(vpninfo);
1185         if (ssl_sock < 0)
1186                 return ssl_sock;
1187
1188         ssl3_method = TLSv1_client_method();
1189         if (!vpninfo->https_ctx) {
1190                 vpninfo->https_ctx = SSL_CTX_new(ssl3_method);
1191
1192                 /* Some servers (or their firewalls) really don't like seeing
1193                    extensions. */
1194 #ifdef SSL_OP_NO_TICKET
1195                 SSL_CTX_set_options (vpninfo->https_ctx, SSL_OP_NO_TICKET);
1196 #endif
1197
1198                 if (vpninfo->cert) {
1199                         err = load_certificate(vpninfo);
1200                         if (err) {
1201                                 vpn_progress(vpninfo, PRG_ERR,
1202                                              _("Loading certificate failed. Aborting.\n"));
1203                                 return err;
1204                         }
1205                         check_certificate_expiry(vpninfo);
1206                 }
1207
1208                 /* We just want to do:
1209                    SSL_CTX_set_purpose(vpninfo->https_ctx, X509_PURPOSE_ANY); 
1210                    ... but it doesn't work with OpenSSL < 0.9.8k because of 
1211                    problems with inheritance (fixed in v1.1.4.6 of
1212                    crypto/x509/x509_vpm.c) so we have to play silly buggers
1213                    instead. This trick doesn't work _either_ in < 0.9.7 but
1214                    I don't know of _any_ workaround which will, and can't
1215                    be bothered to find out either. */
1216 #if OPENSSL_VERSION_NUMBER >= 0x00908000
1217                 SSL_CTX_set_cert_verify_callback(vpninfo->https_ctx,
1218                                                  ssl_app_verify_callback, NULL);
1219 #endif
1220                 SSL_CTX_set_default_verify_paths(vpninfo->https_ctx);
1221
1222                 if (vpninfo->cafile) {
1223                         if (!SSL_CTX_load_verify_locations(vpninfo->https_ctx, vpninfo->cafile, NULL)) {
1224                                 vpn_progress(vpninfo, PRG_ERR,
1225                                              _("Failed to open CA file '%s'\n"),
1226                                              vpninfo->cafile);
1227                                 openconnect_report_ssl_errors(vpninfo);
1228                                 close(ssl_sock);
1229                                 return -EINVAL;
1230                         }
1231                 }
1232
1233         }
1234         https_ssl = SSL_new(vpninfo->https_ctx);
1235         workaround_openssl_certchain_bug(vpninfo, https_ssl);
1236
1237         https_bio = BIO_new_socket(ssl_sock, BIO_NOCLOSE);
1238         BIO_set_nbio(https_bio, 1);
1239         SSL_set_bio(https_ssl, https_bio, https_bio);
1240
1241         vpn_progress(vpninfo, PRG_INFO, _("SSL negotiation with %s\n"),
1242                      vpninfo->hostname);
1243
1244         while ((err = SSL_connect(https_ssl)) <= 0) {
1245                 fd_set wr_set, rd_set;
1246                 int maxfd = ssl_sock;
1247                 
1248                 FD_ZERO(&wr_set);
1249                 FD_ZERO(&rd_set);
1250
1251                 err = SSL_get_error(https_ssl, err);
1252                 if (err == SSL_ERROR_WANT_READ)
1253                         FD_SET(ssl_sock, &rd_set);
1254                 else if (err == SSL_ERROR_WANT_WRITE)
1255                         FD_SET(ssl_sock, &wr_set);
1256                 else {
1257                         vpn_progress(vpninfo, PRG_ERR, _("SSL connection failure\n"));
1258                         openconnect_report_ssl_errors(vpninfo);
1259                         SSL_free(https_ssl);
1260                         close(ssl_sock);
1261                         return -EINVAL;
1262                 }
1263
1264                 if (vpninfo->cancel_fd != -1) {
1265                         FD_SET(vpninfo->cancel_fd, &rd_set);
1266                         if (vpninfo->cancel_fd > ssl_sock)
1267                                 maxfd = vpninfo->cancel_fd;
1268                 }
1269                 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
1270                 if (vpninfo->cancel_fd != -1 &&
1271                     FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
1272                         vpn_progress(vpninfo, PRG_ERR, _("SSL connection cancelled\n"));
1273                         SSL_free(https_ssl);
1274                         close(ssl_sock);
1275                         return -EINVAL;
1276                 }
1277         }
1278
1279         if (verify_peer(vpninfo, https_ssl)) {
1280                 SSL_free(https_ssl);
1281                 close(ssl_sock);
1282                 return -EINVAL;
1283         }
1284
1285         vpninfo->ssl_fd = ssl_sock;
1286         vpninfo->https_ssl = https_ssl;
1287
1288         /* Stash this now, because it might not be available later if the
1289            server has disconnected. */
1290         vpninfo->peer_cert = SSL_get_peer_certificate(vpninfo->https_ssl);
1291
1292         vpn_progress(vpninfo, PRG_INFO, _("Connected to HTTPS on %s\n"),
1293                      vpninfo->hostname);
1294
1295         return 0;
1296 }
1297
1298 void openconnect_close_https(struct openconnect_info *vpninfo, int final)
1299 {
1300         if (vpninfo->peer_cert) {
1301                 X509_free(vpninfo->peer_cert);
1302                 vpninfo->peer_cert = NULL;
1303         }
1304         if (vpninfo->https_ssl) {
1305                 SSL_free(vpninfo->https_ssl);
1306                 vpninfo->https_ssl = NULL;
1307         }
1308         if (vpninfo->ssl_fd != -1) {
1309                 close(vpninfo->ssl_fd);
1310                 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds);
1311                 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
1312                 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds);
1313                 vpninfo->ssl_fd = -1;
1314         }
1315         if (final && vpninfo->https_ctx) {
1316                 SSL_CTX_free(vpninfo->https_ctx);
1317                 vpninfo->https_ctx = NULL;
1318         }
1319 }
1320
1321 void openconnect_init_ssl(void)
1322 {
1323         SSL_library_init ();
1324         ERR_clear_error ();
1325         SSL_load_error_strings ();
1326         OpenSSL_add_all_algorithms ();
1327 }
1328
1329 char *openconnect_get_cert_details(struct openconnect_info *vpninfo,
1330                                    OPENCONNECT_X509 *cert)
1331 {
1332         BIO *bp = BIO_new(BIO_s_mem());
1333         BUF_MEM *certinfo;
1334         char zero = 0;
1335         char *ret;
1336
1337         X509_print_ex(bp, cert, 0, 0);
1338         BIO_write(bp, &zero, 1);
1339         BIO_get_mem_ptr(bp, &certinfo);
1340
1341         ret = strdup(certinfo->data);
1342         BIO_free(bp);
1343         return ret;
1344 }
1345
1346
1347 int openconnect_local_cert_md5(struct openconnect_info *vpninfo,
1348                                char *buf)
1349 {
1350         buf[0] = 0;
1351
1352         if (!vpninfo->cert_x509)
1353                 return -EIO;
1354
1355         if (get_cert_md5_fingerprint(vpninfo, vpninfo->cert_x509, buf))
1356                 return -EIO;
1357
1358         return 0;
1359 }