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