2a2379e5c4b25fef3a24996f1cbb31028b39d301
[platform/upstream/openconnect.git] / gnutls.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 <sys/types.h>
26 #include <sys/stat.h>
27 #include <sys/socket.h>
28 #include <netdb.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <stdio.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 #include <errno.h>
37 #include <stdarg.h>
38 #include <stdlib.h>
39
40 #ifndef HAVE_GNUTLS_CERTIFICATE_SET_KEY
41 /* Shut up about gnutls_sign_callback_set() being deprecated. We only use it
42    in the GnuTLS 2.12 case, and there just isn't another way of doing it. */
43 #define GNUTLS_INTERNAL_BUILD 1
44 #endif
45
46 #include <gnutls/gnutls.h>
47 #include <gnutls/x509.h>
48 #include <gnutls/crypto.h>
49 #include <gnutls/pkcs12.h>
50 #include <gnutls/abstract.h>
51
52 #ifdef HAVE_TROUSERS
53 #include <trousers/tss.h>
54 #include <trousers/trousers.h>
55 #endif
56 #ifdef HAVE_P11KIT
57 #include <p11-kit/p11-kit.h>
58 #include <p11-kit/pkcs11.h>
59 #include <p11-kit/pin.h>
60
61 static P11KitPin *pin_callback(const char *pin_source, P11KitUri *pin_uri,
62                                const char *pin_description,
63                                P11KitPinFlags flags,
64                                void *_vpninfo);
65 #endif
66
67 #include "gnutls.h"
68 #include "openconnect-internal.h"
69
70 /* Helper functions for reading/writing lines over SSL.
71    We could use cURL for the HTTP stuff, but it's overkill */
72
73 int openconnect_SSL_write(struct openconnect_info *vpninfo, char *buf, size_t len)
74 {
75         size_t orig_len = len;
76
77         while (len) {
78                 int done = gnutls_record_send(vpninfo->https_sess, buf, len);
79                 if (done > 0)
80                         len -= done;
81                 else if (done != GNUTLS_E_AGAIN) {
82                         vpn_progress(vpninfo, PRG_ERR, _("Failed to write to SSL socket: %s"),
83                                      gnutls_strerror(done));
84                         return -EIO;
85                 } else {
86                         fd_set wr_set, rd_set;
87                         int maxfd = vpninfo->ssl_fd;
88
89                         FD_ZERO(&wr_set);
90                         FD_ZERO(&rd_set);
91                         
92                         if (gnutls_record_get_direction(vpninfo->https_sess))
93                                 FD_SET(vpninfo->ssl_fd, &wr_set);
94                         else
95                                 FD_SET(vpninfo->ssl_fd, &rd_set);
96
97                         if (vpninfo->cancel_fd != -1) {
98                                 FD_SET(vpninfo->cancel_fd, &rd_set);
99                                 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
100                                         maxfd = vpninfo->cancel_fd;
101                         }
102                         select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
103                         if (vpninfo->cancel_fd != -1 &&
104                             FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
105                                 vpn_progress(vpninfo, PRG_ERR, _("SSL write cancelled\n"));
106                                 return -EINTR;
107                         }
108                 }
109         }
110         return orig_len;
111 }
112
113 int openconnect_SSL_read(struct openconnect_info *vpninfo, char *buf, size_t len)
114 {
115         int done;
116
117         while ((done = gnutls_record_recv(vpninfo->https_sess, buf, len)) < 0) {
118                 fd_set wr_set, rd_set;
119                 int maxfd = vpninfo->ssl_fd;
120
121                 if (done != GNUTLS_E_AGAIN) {
122                         vpn_progress(vpninfo, PRG_ERR, _("Failed to read from SSL socket: %s"),
123                                      gnutls_strerror(done));
124                         return -EIO;
125                 } else {
126                         FD_ZERO(&wr_set);
127                         FD_ZERO(&rd_set);
128                         
129                         if (gnutls_record_get_direction(vpninfo->https_sess))
130                                 FD_SET(vpninfo->ssl_fd, &wr_set);
131                         else
132                                 FD_SET(vpninfo->ssl_fd, &rd_set);
133
134                         if (vpninfo->cancel_fd != -1) {
135                                 FD_SET(vpninfo->cancel_fd, &rd_set);
136                                 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
137                                         maxfd = vpninfo->cancel_fd;
138                         }
139                         select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
140                         if (vpninfo->cancel_fd != -1 &&
141                             FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
142                                 vpn_progress(vpninfo, PRG_ERR, _("SSL read cancelled\n"));
143                                 return -EINTR;
144                         }
145                 }
146         }
147         return done;
148 }
149
150 int openconnect_SSL_gets(struct openconnect_info *vpninfo, char *buf, size_t len)
151 {
152         int i = 0;
153         int ret;
154
155         if (len < 2)
156                 return -EINVAL;
157
158         while (1) {
159                 ret = gnutls_record_recv(vpninfo->https_sess, buf + i, 1);
160                 if (ret == 1) {
161                         if (buf[i] == '\n') {
162                                 buf[i] = 0;
163                                 if (i && buf[i-1] == '\r') {
164                                         buf[i-1] = 0;
165                                         i--;
166                                 }
167                                 return i;
168                         }
169                         i++;
170
171                         if (i >= len - 1) {
172                                 buf[i] = 0;
173                                 return i;
174                         }
175                 } else if (ret != GNUTLS_E_AGAIN) {
176                         vpn_progress(vpninfo, PRG_ERR, _("Failed to read from SSL socket: %s\n"),
177                                      gnutls_strerror(ret));
178                         ret = -EIO;
179                         break;
180                 } else {
181                         fd_set rd_set, wr_set;
182                         int maxfd = vpninfo->ssl_fd;
183                         
184                         FD_ZERO(&rd_set);
185                         FD_ZERO(&wr_set);
186                         
187                         if (gnutls_record_get_direction(vpninfo->https_sess))
188                                 FD_SET(vpninfo->ssl_fd, &wr_set);
189                         else
190                                 FD_SET(vpninfo->ssl_fd, &rd_set);
191
192                         if (vpninfo->cancel_fd != -1) {
193                                 FD_SET(vpninfo->cancel_fd, &rd_set);
194                                 if (vpninfo->cancel_fd > vpninfo->ssl_fd)
195                                         maxfd = vpninfo->cancel_fd;
196                         }
197                         select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
198                         if (vpninfo->cancel_fd != -1 &&
199                             FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
200                                 vpn_progress(vpninfo, PRG_ERR, _("SSL read cancelled\n"));
201                                 ret = -EINTR;
202                                 break;
203                         }
204                 }
205         }
206         buf[i] = 0;
207         return i ?: ret;
208 }
209
210 static int check_certificate_expiry(struct openconnect_info *vpninfo, gnutls_x509_crt_t cert)
211 {
212         const char *reason = NULL;
213         time_t expires = gnutls_x509_crt_get_expiration_time(cert);
214         time_t now = time(NULL);
215
216         if (expires == -1) {
217                 vpn_progress(vpninfo, PRG_ERR,
218                              _("Could not extract expiration time of certificate\n"));
219                 return -EINVAL;
220         }
221
222         if (expires < now)
223                 reason = _("Client certificate has expired at");
224         else if (expires < now + vpninfo->cert_expire_warning)
225                 reason = _("Client certificate expires soon at");
226
227         if (reason) {
228                 struct tm tm;
229                 char buf[80];
230
231                 gmtime_r(&expires, &tm);
232                 strftime(buf, 80, "%a, %d %b %Y %T %Z", &tm);
233
234                 vpn_progress(vpninfo, PRG_ERR, "%s: %s\n", reason, buf);
235         }
236         return 0;
237 }
238
239 /* For systems that don't support O_CLOEXEC, just don't bother.
240    It's not open for long anyway. */
241 #ifndef O_CLOEXEC
242 #define O_CLOEXEC
243 #endif
244
245 static int load_datum(struct openconnect_info *vpninfo,
246                       gnutls_datum_t *datum, const char *fname)
247 {
248         struct stat st;
249         int fd, err;
250
251         fd = open(fname, O_RDONLY|O_CLOEXEC);
252         if (fd == -1) {
253                 err = errno;
254                 vpn_progress(vpninfo, PRG_ERR,
255                              _("Failed to open key/certificate file %s: %s\n"),
256                              fname, strerror(err));
257                 return -ENOENT;
258         }
259         if (fstat(fd, &st)) {
260                 err = errno;
261                 vpn_progress(vpninfo, PRG_ERR,
262                              _("Failed to stat key/certificate file %s: %s\n"),
263                              fname, strerror(err));
264                 close(fd);
265                 return -EIO;
266         }
267         datum->size = st.st_size;
268         datum->data = gnutls_malloc(st.st_size + 1);
269         if (!datum->data) {
270                 vpn_progress(vpninfo, PRG_ERR,
271                              _("Failed to allocate certificate buffer\n"));
272                 close(fd);
273                 return -ENOMEM;
274         }
275         errno = EAGAIN;
276         if (read(fd, datum->data, datum->size) != datum->size) {
277                 err = errno;
278                 vpn_progress(vpninfo, PRG_ERR,
279                              _("Failed to read certificate into memory: %s\n"),
280                              strerror(err));
281                 close(fd);
282                 gnutls_free(datum->data);
283                 return -EIO;
284         }
285         datum->data[st.st_size] = 0;
286         close(fd);
287         return 0;
288 }
289
290 /* A non-zero, non-error return to make load_certificate() continue and
291    interpreting the file as other types */
292 #define NOT_PKCS12      1
293
294 static int load_pkcs12_certificate(struct openconnect_info *vpninfo,
295                                    gnutls_datum_t *datum,
296                                    gnutls_x509_privkey_t *key,
297                                    gnutls_x509_crt_t **chain,
298                                    unsigned int *chain_len,
299                                    gnutls_x509_crt_t **extra_certs,
300                                    unsigned int *extra_certs_len,
301                                    gnutls_x509_crl_t *crl)
302 {
303         gnutls_pkcs12_t p12;
304         char *pass;
305         int err;
306
307         err = gnutls_pkcs12_init(&p12);
308         if (err) {
309                 vpn_progress(vpninfo, PRG_ERR,
310                              _("Failed to setup PKCS#12 data structure: %s\n"),
311                              gnutls_strerror(err));
312                 return -EIO;
313         }
314
315         err = gnutls_pkcs12_import(p12, datum, GNUTLS_X509_FMT_DER, 0);
316         if (err) {
317                 gnutls_pkcs12_deinit(p12);
318                 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN)
319                         return NOT_PKCS12;
320                 vpn_progress(vpninfo, PRG_ERR,
321                              _("Failed to import PKCS#12 file: %s\n"),
322                              gnutls_strerror(err));
323                 return -EINVAL;
324         }
325
326         pass = vpninfo->cert_password;
327         while ((err = gnutls_pkcs12_verify_mac(p12, pass)) == GNUTLS_E_MAC_VERIFY_FAILED) {
328                 if (pass)
329                         vpn_progress(vpninfo, PRG_ERR,
330                                      _("Failed to decrypt PKCS#12 certificate file\n"));
331                 free(pass);
332                 vpninfo->cert_password = NULL;
333                 err = request_passphrase(vpninfo, "openconnect_pkcs12", &pass,
334                                          _("Enter PKCS#12 pass phrase:"));
335                 if (err) {
336                         gnutls_pkcs12_deinit(p12);
337                         return -EINVAL;
338                 }
339         }
340         /* If it wasn't GNUTLS_E_MAC_VERIFY_FAILED, then the problem wasn't just a
341            bad password. Give up. */
342         if (err) {
343                 int level = PRG_ERR;
344                 int ret = -EINVAL;
345
346                 gnutls_pkcs12_deinit(p12);
347
348                 /* If the first attempt, and we didn't know for sure it was PKCS#12
349                    anyway, bail out and try loading it as something different. */
350                 if (pass == vpninfo->cert_password &&
351                     vpninfo->cert_type == CERT_TYPE_UNKNOWN) {
352                         /* Make it non-fatal... */
353                         level = PRG_TRACE;
354                         ret = NOT_PKCS12;
355                 }
356
357                 vpn_progress(vpninfo, level,
358                              _("Failed to process PKCS#12 file: %s\n"),
359                                gnutls_strerror(err));
360                 return ret;
361         }
362         err = gnutls_pkcs12_simple_parse(p12, pass, key, chain, chain_len,
363                                          extra_certs, extra_certs_len, crl, 0);
364         free(pass);
365         vpninfo->cert_password = NULL;
366
367         gnutls_pkcs12_deinit(p12);
368         if (err) {
369                 vpn_progress(vpninfo, PRG_ERR,
370                              _("Failed to load PKCS#12 certificate: %s\n"),
371                              gnutls_strerror(err));
372                 return -EINVAL;
373         }
374         return 0;
375 }
376
377 /* Older versions of GnuTLS didn't actually bother to check this, so we'll
378    do it for them. */
379 static int check_issuer_sanity(gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer)
380 {
381 #if GNUTLS_VERSION_NUMBER > 0x300014
382         return 0;
383 #else
384         unsigned char id1[512], id2[512];
385         size_t id1_size = 512, id2_size = 512;
386         int err;
387
388         err = gnutls_x509_crt_get_authority_key_id(cert, id1, &id1_size, NULL);
389         if (err)
390                 return 0;
391
392         err = gnutls_x509_crt_get_subject_key_id(issuer, id2, &id2_size, NULL);
393         if (err)
394                 return 0;
395         if (id1_size == id2_size && !memcmp(id1, id2, id1_size))
396                 return 0;
397
398         /* EEP! */
399         return -EIO;
400 #endif
401 }
402
403 static int count_x509_certificates(gnutls_datum_t *datum)
404 {
405         int count = 0;
406         char *p = (char *)datum->data;
407
408         while (p) {
409                 p = strstr(p, "-----BEGIN ");
410                 if (!p)
411                         break;
412                 p += 11;
413                 if (!strncmp(p, "CERTIFICATE", 11) ||
414                     !strncmp(p, "X509 CERTIFICATE", 16))
415                     count++;
416         }
417         return count;
418 }
419
420 static int get_cert_name(gnutls_x509_crt_t cert, char *name, size_t namelen)
421 {
422         if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME,
423                                           0, 0, name, &namelen) &&
424             gnutls_x509_crt_get_dn(cert, name, &namelen)) {
425                 name[namelen-1] = 0;
426                 snprintf(name, namelen-1, "<unknown>");
427                 return -EINVAL;
428         }
429         return 0;
430 }
431
432 #if defined (HAVE_P11KIT) || defined (HAVE_TROUSERS)
433 #ifndef HAVE_GNUTLS_CERTIFICATE_SET_KEY
434 /* For GnuTLS 2.12 even if we *have* a privkey (as we do for PKCS#11), we
435    can't register it. So we have to use the cert_callback function. This
436    just hands out the certificate chain we prepared in load_certificate().
437    If we have a pkey then return that too; otherwise leave the key NULL —
438    we'll also have registered a sign_callback for the session, which will
439    handle that. */
440 static int gtls_cert_cb(gnutls_session_t sess, const gnutls_datum_t *req_ca_dn,
441                         int nreqs, const gnutls_pk_algorithm_t *pk_algos,
442                         int pk_algos_length, gnutls_retr2_st *st) {
443
444         struct openconnect_info *vpninfo = gnutls_session_get_ptr(sess);
445         int algo = GNUTLS_PK_RSA; /* TPM */
446         int i;
447
448 #ifdef HAVE_P11KIT
449         if (vpninfo->my_p11key) {
450                 st->key_type = GNUTLS_PRIVKEY_PKCS11;
451                 st->key.pkcs11 = vpninfo->my_p11key;
452                 algo = gnutls_pkcs11_privkey_get_pk_algorithm(vpninfo->my_p11key, NULL);
453         };
454 #endif
455         for (i = 0; i < pk_algos_length; i++) {
456                 if (algo == pk_algos[i])
457                         break;
458         }
459         if (i == pk_algos_length)
460                 return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
461
462         st->cert_type = GNUTLS_CRT_X509;
463         st->cert.x509 = vpninfo->my_certs;
464         st->ncerts = vpninfo->nr_my_certs;
465         st->deinit_all = 0;
466
467         return 0;
468 }
469
470 /* For GnuTLS 2.12, this has to set the cert_callback to the function
471    above, which will return the pkey and certs on demand. Or in the
472    case of TPM we can't make a suitable pkey, so we have to set a
473    sign_callback too (which is done in openconnect_open_https() since
474    it has to be done on the *session*). */
475 static int assign_privkey(struct openconnect_info *vpninfo,
476                           gnutls_privkey_t pkey,
477                           gnutls_x509_crt_t *certs,
478                           unsigned int nr_certs,
479                           gnutls_x509_crt_t *extra_certs,
480                           unsigned int nr_extra_certs)
481 {
482         int i;
483
484         vpninfo->my_certs = gnutls_calloc(nr_certs, sizeof(*certs));
485         if (!vpninfo->my_certs)
486                 return GNUTLS_E_MEMORY_ERROR;
487
488         memcpy(vpninfo->my_certs, certs, nr_certs * sizeof(*certs));
489         vpninfo->nr_my_certs = nr_certs;
490
491         /* We are *keeping* the certs, unlike in GnuTLS 3 where we can
492            free them after calling gnutls_certificate_set_key(). So
493            first wipe the 'certs' array (which is either '&cert' or
494            'supporting_certs' in load_certificate())... */
495         memset(certs, 0, nr_certs * sizeof(*certs));
496
497         /* ... and then also zero out the entries in the extra_certs
498            array that correspond to certs that were added into the
499            supporting_certs array (but above the certs_to_free index).
500
501            The first one is 'cert', which was already stolen by the
502            load_certificate() function and put into our certs[0]..
503            So start at 1. */
504         for (i = 1; i < nr_certs; i++) {
505                 int j;
506                 for (j = 0; j < nr_extra_certs; j++) {
507                         if (vpninfo->my_certs[i] == extra_certs[j]) {
508                                 extra_certs[j] = NULL;
509                                 break;
510                         }
511                 }
512         }
513
514         gnutls_certificate_set_retrieve_function(vpninfo->https_cred,
515                                                  gtls_cert_cb);
516         vpninfo->my_pkey = pkey;
517
518         return 0;
519 }
520 #else /* !SET_KEY */
521
522 /* For GnuTLS 3+ this is saner than the GnuTLS 2.12 version. But still we
523    have to convert the array of X509 certificates to gnutls_pcert_st for
524    ourselves. There's no function that takes a gnutls_privkey_t as the key
525    and gnutls_x509_crt_t certificates. */
526 static int assign_privkey(struct openconnect_info *vpninfo,
527                           gnutls_privkey_t pkey,
528                           gnutls_x509_crt_t *certs,
529                           unsigned int nr_certs,
530                           gnutls_x509_crt_t *extra_certs,
531                           unsigned int nr_extra_certs)
532 {
533         gnutls_pcert_st *pcerts = calloc(nr_certs, sizeof(*pcerts));
534         int i, err;
535
536         if (!pcerts)
537                 return GNUTLS_E_MEMORY_ERROR;
538
539         for (i=0 ; i < nr_certs; i++) {
540                 err = gnutls_pcert_import_x509(pcerts + i, certs[i], 0);
541                 if (err) {
542                         vpn_progress(vpninfo, PRG_ERR,
543                                      _("Importing X509 certificate failed: %s\n"),
544                                      gnutls_strerror(err));
545                         goto free_pcerts;
546                 }
547         }
548
549         err = gnutls_certificate_set_key(vpninfo->https_cred, NULL, 0,
550                                          pcerts, nr_certs, pkey);
551         if (err) {
552                 vpn_progress(vpninfo, PRG_ERR,
553                              _("Setting PKCS#11 certificate failed: %s\n"),
554                              gnutls_strerror(err));
555         free_pcerts:
556                 for (i=0 ; i < nr_certs; i++)
557                         gnutls_pcert_deinit(pcerts + i);
558                 free (pcerts);
559         }
560         return err;
561 }
562 #endif /* !SET_KEY */
563 #endif /* (P11KIT || TROUSERS) */
564
565 static int load_certificate(struct openconnect_info *vpninfo)
566 {
567         gnutls_datum_t fdata;
568         gnutls_x509_privkey_t key = NULL;
569 #if defined (HAVE_P11KIT) || defined (HAVE_TROUSERS)
570         gnutls_privkey_t pkey = NULL;
571         gnutls_datum_t pkey_sig = {NULL, 0};
572         void *dummy_hash_data = &load_certificate;
573 #endif
574 #ifdef HAVE_P11KIT
575         char *cert_url = (char *)vpninfo->cert;
576         char *key_url = (char *)vpninfo->sslkey;
577         gnutls_pkcs11_privkey_t p11key = NULL;
578 #endif
579         gnutls_x509_crl_t crl = NULL;
580         gnutls_x509_crt_t last_cert, cert = NULL;
581         gnutls_x509_crt_t *extra_certs = NULL, *supporting_certs = NULL;
582         unsigned int nr_supporting_certs = 0, nr_extra_certs = 0;
583         unsigned int certs_to_free = 0; /* How many of supporting_certs */
584         int err; /* GnuTLS error */
585         int ret;
586         int i;
587         int cert_is_p11 = 0, key_is_p11 = 0;
588         unsigned char key_id[20];
589         size_t key_id_size = sizeof(key_id);
590         char name[80];
591
592         fdata.data = NULL;
593
594         key_is_p11 = !strncmp(vpninfo->sslkey, "pkcs11:", 7);
595         cert_is_p11 = !strncmp(vpninfo->cert, "pkcs11:", 7);
596
597         /* Install PIN handler if either certificate or key are coming from PKCS#11 */
598         if (key_is_p11 || cert_is_p11) {
599 #ifdef HAVE_P11KIT
600                 CK_OBJECT_CLASS class;
601                 CK_ATTRIBUTE attr;
602                 char pin_source[40];
603                 P11KitUri *uri;
604
605                 sprintf(pin_source, "openconnect:%p", vpninfo);
606                 p11_kit_pin_register_callback(pin_source, pin_callback, vpninfo, NULL);
607
608                 uri = p11_kit_uri_new();
609
610                 attr.type = CKA_CLASS;
611                 attr.pValue = &class;
612                 attr.ulValueLen = sizeof(class);
613
614                 /* Add appropriate pin-source and object-type attributes to
615                    both certificate and key URLs, unless they already exist. */
616                 if (cert_is_p11 &&
617                     !p11_kit_uri_parse(cert_url, P11_KIT_URI_FOR_OBJECT, uri)) {
618                         if (!p11_kit_uri_get_pin_source(uri))
619                                 p11_kit_uri_set_pin_source(uri, pin_source);
620                         if (!p11_kit_uri_get_attribute(uri, CKA_CLASS)) {
621                                 class = CKO_CERTIFICATE;
622                                 p11_kit_uri_set_attribute(uri, &attr);
623                         }
624                         p11_kit_uri_format(uri, P11_KIT_URI_FOR_OBJECT, &cert_url);
625                 }
626
627                 if (key_is_p11 &&
628                     !p11_kit_uri_parse(key_url, P11_KIT_URI_FOR_OBJECT, uri)) {
629                         if (!p11_kit_uri_get_pin_source(uri))
630                                 p11_kit_uri_set_pin_source(uri, pin_source);
631                         if (!p11_kit_uri_get_attribute(uri, CKA_CLASS)) {
632                                 class = CKO_PRIVATE_KEY;
633                                 p11_kit_uri_set_attribute(uri, &attr);
634                         }
635                         p11_kit_uri_format(uri, P11_KIT_URI_FOR_OBJECT, &key_url);
636                 }
637
638                 p11_kit_uri_free(uri);
639 #else
640                 vpn_progress(vpninfo, PRG_ERR,
641                              _("This binary built without PKCS#11 support\n"));
642                 return -EINVAL;
643 #endif
644         }
645
646         /* Load certificate(s) first... */
647 #ifdef HAVE_P11KIT
648         if (cert_is_p11) {
649                 vpn_progress(vpninfo, PRG_TRACE,
650                              _("Using PKCS#11 certificate %s\n"), cert_url);
651
652                 err = gnutls_x509_crt_init(&cert);
653                 if (err) {
654                         ret = -ENOMEM;
655                         goto out;
656                 }
657                 err = gnutls_x509_crt_import_pkcs11_url(cert, cert_url, 0);
658                 if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
659                         err = gnutls_x509_crt_import_pkcs11_url(cert, cert_url,
660                                                                 GNUTLS_PKCS11_OBJ_FLAG_LOGIN);
661                 if (err) {
662                         vpn_progress(vpninfo, PRG_ERR,
663                                      _("Error loading certificate from PKCS#11: %s\n"),
664                                      gnutls_strerror(err));
665                         ret = -EIO;
666                         goto out;
667                 }
668                 goto got_certs;
669         }
670 #endif /* HAVE_P11KIT */
671
672         vpn_progress(vpninfo, PRG_TRACE,
673                      _("Using certificate file %s\n"), vpninfo->cert);
674
675         ret = load_datum(vpninfo, &fdata, vpninfo->cert);
676         if (ret)
677                 return ret;
678
679         if (!key_is_p11 && (vpninfo->cert_type == CERT_TYPE_PKCS12 ||
680                             vpninfo->cert_type == CERT_TYPE_UNKNOWN)) {
681                 /* PKCS#12 should actually contain certificates *and* private key */
682                 ret = load_pkcs12_certificate(vpninfo, &fdata, &key,
683                                               &supporting_certs, &nr_supporting_certs,
684                                               &extra_certs, &nr_extra_certs,
685                                               &crl);
686                 if (ret < 0)
687                         goto out;
688                 else if (!ret) {
689                         if (nr_supporting_certs) {
690                                 cert = supporting_certs[0];
691                                 goto got_key;
692                         }
693                         vpn_progress(vpninfo, PRG_ERR,
694                                      _("PKCS#11 file contained no certificate\n"));
695                         ret = -EINVAL;
696                         goto out;
697                 }
698
699                 /* It returned NOT_PKCS12.
700                    Fall through to try PEM formats. */
701         }
702
703         /* We need to know how many there are in *advance*; it won't just allocate
704            the array for us :( */
705         nr_extra_certs = count_x509_certificates(&fdata);
706         if (!nr_extra_certs)
707                 nr_extra_certs = 1; /* wtf? Oh well, we'll fail later... */
708
709         extra_certs = calloc(nr_extra_certs, sizeof(cert));
710         if (!extra_certs) {
711                 nr_extra_certs = 0;
712                 ret = -ENOMEM;
713                 goto out;
714         }
715         err = gnutls_x509_crt_list_import(extra_certs, &nr_extra_certs, &fdata,
716                                           GNUTLS_X509_FMT_PEM, 0);
717         if (err <= 0) {
718                 const char *reason;
719                 if (!err || err == GNUTLS_E_NO_CERTIFICATE_FOUND)
720                         reason = _("No certificate found in file");
721                 else
722                         reason = gnutls_strerror(err);
723
724                 vpn_progress(vpninfo, PRG_ERR,
725                              _("Loading certificate failed: %s\n"),
726                              reason);
727                 ret = -EINVAL;
728                 goto out;
729         }
730         nr_extra_certs = err;
731         err = 0;
732
733         goto got_certs;
734  got_certs:
735         /* Now we have the certificate(s) and we're looking for the private key... */
736 #if defined (HAVE_P11KIT)
737         if (key_is_p11) {
738                 vpn_progress(vpninfo, PRG_TRACE,
739                              _("Using PKCS#11 key %s\n"), key_url);
740
741                 err = gnutls_pkcs11_privkey_init(&p11key);
742                 if (err) {
743                         vpn_progress(vpninfo, PRG_ERR,
744                                      _("Error initialising PKCS#11 key structure: %s\n"),
745                                      gnutls_strerror(err));
746                         ret = -EIO;
747                         goto out;
748                 }
749
750                 err = gnutls_pkcs11_privkey_import_url(p11key, key_url, 0);
751                 if (err) {
752                         vpn_progress(vpninfo, PRG_ERR,
753                                      _("Error importing PKCS#11 URL %s: %s\n"),
754                                      key_url, gnutls_strerror(err));
755                         gnutls_pkcs11_privkey_deinit(p11key);
756                         ret = -EIO;
757                         goto out;
758                 }
759
760                 err = gnutls_privkey_init(&pkey);
761                 if (err) {
762                         vpn_progress(vpninfo, PRG_ERR,
763                                      _("Error initialising private key structure: %s\n"),
764                                      gnutls_strerror(err));
765                         gnutls_pkcs11_privkey_deinit(p11key);
766                         ret = -EIO;
767                         goto out;
768                 }
769
770                 err = gnutls_privkey_import_pkcs11(pkey, p11key, GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE);
771                 if (err) {
772                         vpn_progress(vpninfo, PRG_ERR,
773                                      _("Error importing PKCS#11 key into private key structure: %s\n"),
774                                      gnutls_strerror(err));
775                         gnutls_pkcs11_privkey_deinit(p11key);
776                         ret = -EIO;
777                         goto out;
778                 }
779 #ifndef HAVE_GNUTLS_CERTIFICATE_SET_KEY
780                 /* This can be set now and doesn't need to be separately freed.
781                    It goes with the pkey. This is a PITA; it would be better
782                    if there was a way to get the p11key *back* from a privkey
783                    that we *know* is based on one. In fact, since this is only
784                    for GnuTLS 2.12 and we *know* the gnutls_privkey_st won't
785                    ever change there, so we *could* do something evil... but
786                    we won't :) */
787                 vpninfo->my_p11key = p11key;
788 #endif /* !SET_KEY */
789                 goto match_cert;
790         }
791 #endif /* HAVE_P11KIT */
792
793         /* We're loading the private key from a file. Load the file into memory
794            unless it's the same as the certificate and we already loaded that. */
795         if (!fdata.data || vpninfo->sslkey != vpninfo->cert) {
796                 gnutls_free(fdata.data);
797                 fdata.data = NULL;
798
799                 vpn_progress(vpninfo, PRG_TRACE,
800                              _("Using private key file %s\n"), vpninfo->sslkey);
801
802                 ret = load_datum(vpninfo, &fdata, vpninfo->sslkey);
803                 if (ret)
804                         goto out;
805         }
806
807         if (vpninfo->cert_type == CERT_TYPE_TPM ||
808             (vpninfo->cert_type == CERT_TYPE_UNKNOWN &&
809              strstr((char *)fdata.data, "-----BEGIN TSS KEY BLOB-----"))) {
810 #ifndef HAVE_TROUSERS
811                 vpn_progress(vpninfo, PRG_ERR,
812                              _("This version of OpenConnect was built without TPM support\n"));
813                 return -EINVAL;
814 #else
815                 ret = load_tpm_key(vpninfo, &fdata, &pkey, &pkey_sig);
816                 if (ret)
817                         goto out;
818
819                 goto match_cert;
820 #endif
821         }
822
823         gnutls_x509_privkey_init(&key);
824         /* Try PKCS#1 (and PKCS#8 without password) first. GnuTLS doesn't
825            support OpenSSL's old PKCS#1-based encrypted format. We should
826            probably check for it and give a more coherent failure mode. */
827         err = gnutls_x509_privkey_import(key, &fdata, GNUTLS_X509_FMT_PEM);
828         if (err) {
829                 /* If that fails, try PKCS#8 */
830                 char *pass = vpninfo->cert_password;
831
832                 /* Yay, just for fun this is *different* to PKCS#12. Where we could
833                    try an empty password there, in this case the empty-password case
834                    has already been *tried* by gnutls_x509_privkey_import(). If we
835                    just call gnutls_x509_privkey_import_pkcs8() with a NULL password,
836                    it'll SEGV. You have to set the GNUTLS_PKCS_PLAIN flag if you want
837                    to try without a password. Passing NULL evidently isn't enough of
838                    a hint. And in GnuTLS 3.1 where that crash has been fixed, passing
839                    NULL will cause it to return GNUTLS_E_ENCRYPTED_STRUCTURE (a new
840                    error code) rather than GNUTLS_E_DECRYPTION_FAILED. So just pass ""
841                    instead of NULL, and don't worry about either case. */
842                 while ((err = gnutls_x509_privkey_import_pkcs8(key, &fdata,
843                                                                GNUTLS_X509_FMT_PEM,
844                                                                pass?pass:"", 0))) {
845                         if (err != GNUTLS_E_DECRYPTION_FAILED) {
846                                 vpn_progress(vpninfo, PRG_ERR,
847                                              _("Failed to load private key as PKCS#8: %s\n"),
848                                              gnutls_strerror(err));
849                                 ret = -EINVAL;
850                                 goto out;
851                         }
852                         vpninfo->cert_password = NULL;
853                         if (pass) {
854                                 vpn_progress(vpninfo, PRG_ERR,
855                                              _("Failed to decrypt PKCS#8 certificate file\n"));
856                                 free(pass);
857                         }
858                         err = request_passphrase(vpninfo, "openconnect_pem",
859                                                  &pass, _("Enter PEM pass phrase:"));
860                         if (err) {
861                                 ret = -EINVAL;
862                                 goto out;
863                         }
864                 }
865                 free(pass);
866                 vpninfo->cert_password = NULL;
867         }
868
869         /* Now attempt to make sure we use the *correct* certificate, to match the key */
870         err = gnutls_x509_privkey_get_key_id(key, 0, key_id, &key_id_size);
871         if (err) {
872                 vpn_progress(vpninfo, PRG_ERR,
873                              _("Failed to get key ID: %s\n"),
874                              gnutls_strerror(err));
875                 ret = -EINVAL;
876                 goto out;
877         }
878         for (i = 0; i < (extra_certs?nr_extra_certs:1); i++) {
879                 unsigned char cert_id[20];
880                 size_t cert_id_size = sizeof(cert_id);
881
882                 err = gnutls_x509_crt_get_key_id(extra_certs?extra_certs[i]:cert, 0, cert_id, &cert_id_size);
883                 if (err)
884                         continue;
885
886                 if (cert_id_size == key_id_size && !memcmp(cert_id, key_id, key_id_size)) {
887                         if (extra_certs) {
888                                 cert = extra_certs[i];
889
890                                 /* Move the rest of the array down */
891                                 for (; i < nr_extra_certs - 1; i++)
892                                         extra_certs[i] = extra_certs[i+1];
893
894                                 nr_extra_certs--;
895                         }
896                         goto got_key;
897                 }
898         }
899         /* There's no pkey (there's an x509 key), so we'll fall straight through the
900          * bit at match_cert: below, and go directly to the bit where it prints the
901          * 'no match found' error and exits. */
902
903 #if defined (HAVE_P11KIT) || defined (HAVE_TROUSERS)
904  match_cert:
905         /* If we have a privkey from PKCS#11 or TPM, we can't do the simple comparison
906            of key ID that we do for software keys to find which certificate is a
907            match. So sign some dummy data and then check the signature against each
908            of the available certificates until we find the right one. */
909         if (pkey) {
910                 /* The TPM code may have already signed it, to test authorisation. We
911                    only sign here for PKCS#11 keys, in which case fdata might be
912                    empty too so point it at dummy data. */
913                 if (!pkey_sig.data) {
914                         if (!fdata.data) {
915                                 fdata.data = dummy_hash_data;
916                                 fdata.size = 20;
917                         }
918
919                         err = sign_dummy_data(vpninfo, pkey, &fdata, &pkey_sig);
920                         if (err) {
921                                 vpn_progress(vpninfo, PRG_ERR,
922                                              _("Error signing test data with private key: %s\n"),
923                                              gnutls_strerror(err));
924                                 ret = -EINVAL;
925                                 goto out;
926                         }
927                 }
928
929                 for (i=0; i < (extra_certs?nr_extra_certs:1); i++) {
930                         gnutls_pubkey_t pubkey;
931
932                         gnutls_pubkey_init(&pubkey);
933                         err = gnutls_pubkey_import_x509(pubkey, extra_certs?extra_certs[i]:cert, 0);
934                         if (err) {
935                                 vpn_progress(vpninfo, PRG_ERR,
936                                              _("Error validating signature against certificate: %s\n"),
937                                              gnutls_strerror(err));
938                                 /* We'll probably fail shortly if we don't find it. */
939                                 gnutls_pubkey_deinit(pubkey);
940                                 continue;
941                         }
942                         err = gnutls_pubkey_verify_data(pubkey, 0, &fdata, &pkey_sig);
943                         gnutls_pubkey_deinit(pubkey);
944
945                         if (err >= 0) {
946                                 if (extra_certs) {
947                                         cert = extra_certs[i];
948
949                                         /* Move the rest of the array down */
950                                         for (; i < nr_extra_certs - 1; i++)
951                                                 extra_certs[i] = extra_certs[i+1];
952
953                                         nr_extra_certs--;
954                                 }
955                                 gnutls_free(pkey_sig.data);
956                                 goto got_key;
957                         }
958                 }
959                 gnutls_free(pkey_sig.data);
960         }
961 #endif /* P11KIT || TROUSERS */
962
963         /* We shouldn't reach this. It means that we didn't find *any* matching cert */
964         vpn_progress(vpninfo, PRG_ERR,
965                      _("No SSL certificate found to match private key\n"));
966         ret = -EINVAL;
967         goto out;
968
969         /********************************************************************/
970  got_key:
971         /* Now we have both cert(s) and key, and we should be ready to go. */
972         check_certificate_expiry(vpninfo, cert);
973         get_cert_name(cert, name, sizeof(name));
974         vpn_progress(vpninfo, PRG_INFO, _("Using client certificate '%s'\n"),
975                      name);
976
977         if (crl) {
978                 err = gnutls_certificate_set_x509_crl(vpninfo->https_cred, &crl, 1);
979                 if (err) {
980                         vpn_progress(vpninfo, PRG_ERR,
981                                      _("Setting certificate recovation list failed: %s\n"),
982                                      gnutls_strerror(err));
983                         ret = -EINVAL;
984                         goto out;
985                 }
986         }
987
988         /* OpenSSL has problems with certificate chains — if there are
989            multiple certs with the same name, it doesn't necessarily
990            choose the _right_ one. (RT#1942)
991            Pick the right ones for ourselves and add them manually. */
992
993         if (nr_supporting_certs) {
994                 /* We already got a bunch of certs from PKCS#12 file. 
995                    Remember how many need to be freed when we're done,
996                    since we'll expand the supporting_certs array with
997                    more from the cafile if we can. */
998                 last_cert = supporting_certs[nr_supporting_certs-1];
999                 certs_to_free = nr_supporting_certs;
1000         } else {
1001                 last_cert = cert;
1002                 certs_to_free = nr_supporting_certs = 1;
1003         }
1004         while (1) {
1005                 gnutls_x509_crt_t issuer;
1006
1007                 for (i = 0; i < nr_extra_certs; i++) {
1008                         if (gnutls_x509_crt_check_issuer(last_cert, extra_certs[i]) &&
1009                             !check_issuer_sanity(last_cert, extra_certs[i]))
1010                                 break;
1011                 }
1012
1013                 if (i < nr_extra_certs) {
1014                         issuer = extra_certs[i];
1015                 } else {
1016                         err = gnutls_certificate_get_issuer(vpninfo->https_cred,
1017                                                             last_cert, &issuer, 0);
1018                         if (err)
1019                                 break;
1020                 }
1021
1022                 /* The check_issuer_sanity() function works fine as a workaround where
1023                    it was used above, but when gnutls_certificate_get_issuer() returns
1024                    a bogus cert, there's nothing we can do to fix it up. We don't get
1025                    to iterate over all the available certs like we can over our own
1026                    list. */
1027                 if (check_issuer_sanity(last_cert, issuer)) {
1028                         /* Hm, is there a bug reference for this? Or just the git commit
1029                            reference (c1ef7efb in master, 5196786c in gnutls_3_0_x-2)? */
1030                         vpn_progress(vpninfo, PRG_ERR,
1031                                      _("WARNING: GnuTLS returned incorrect issuer certs; authentication may fail!\n"));
1032                         break;
1033                 }
1034
1035                 if (issuer == last_cert) {
1036                         /* Don't actually include the root CA. If they don't already trust it,
1037                            then handing it to them isn't going to help. But don't omit the
1038                            original certificate if it's self-signed. */
1039                         if (nr_supporting_certs > 1)
1040                                 nr_supporting_certs--;
1041                         break;
1042                 }
1043
1044                 /* OK, we found a new cert to add to our chain. */
1045                 supporting_certs = gnutls_realloc(supporting_certs,
1046                                                   sizeof(cert) * ++nr_supporting_certs);
1047                 if (!supporting_certs) {
1048                         vpn_progress(vpninfo, PRG_ERR,
1049                                      _("Failed to allocate memory for supporting certificates\n"));
1050                         /* The world is probably about to end, but try without them anyway */
1051                         certs_to_free = 0;
1052                         ret = -ENOMEM;
1053                         goto out;
1054                 }
1055
1056                 /* First time we actually allocated an array? Copy the first cert into it */
1057                 if (nr_supporting_certs == 2)
1058                         supporting_certs[0] = cert;
1059
1060                 /* Append the new one */
1061                 supporting_certs[nr_supporting_certs-1] = issuer;
1062                 last_cert = issuer;
1063
1064         }
1065         for (i = 1; i < nr_supporting_certs; i++) {
1066                 get_cert_name(supporting_certs[i], name, sizeof(name));
1067
1068                 vpn_progress(vpninfo, PRG_DEBUG,
1069                              _("Adding supporting CA '%s'\n"), name);
1070         }
1071
1072 #if defined (HAVE_P11KIT) || defined (HAVE_TROUSERS)
1073         if (pkey) {
1074                 err = assign_privkey(vpninfo, pkey,
1075                                      supporting_certs?:&cert, nr_supporting_certs,
1076                                      extra_certs, nr_extra_certs);
1077                 if (err) {
1078                         ret = -EIO;
1079                         goto out;
1080                 }
1081                 pkey = NULL; /* we gave it away, along with pcerts */
1082         } else
1083 #endif /* P11KIT || TROUSERS */
1084                 err = gnutls_certificate_set_x509_key(vpninfo->https_cred,
1085                                                       supporting_certs ? supporting_certs : &cert,
1086                                                       supporting_certs ? nr_supporting_certs : 1,
1087                                                       key);
1088
1089         if (err) {
1090                 vpn_progress(vpninfo, PRG_ERR,
1091                              _("Setting certificate failed: %s\n"),
1092                              gnutls_strerror(err));
1093                 ret = -EIO;
1094         } else
1095                 ret = 0;
1096  out:
1097         if (crl)
1098                 gnutls_x509_crl_deinit(crl);
1099         if (key)
1100                 gnutls_x509_privkey_deinit(key);
1101         if (supporting_certs) {
1102                 for (i = 0; i < certs_to_free; i++) {
1103                         if (supporting_certs[i])
1104                                 gnutls_x509_crt_deinit(supporting_certs[i]);
1105                 }
1106                 gnutls_free(supporting_certs);
1107         } else if (cert) {
1108                 /* Not if supporting_certs. It's supporting_certs[0] then and
1109                    was already freed. */
1110                 gnutls_x509_crt_deinit(cert);
1111         }
1112         for (i = 0; i < nr_extra_certs; i++) {
1113                 if (extra_certs[i])
1114                         gnutls_x509_crt_deinit(extra_certs[i]);
1115         }
1116         gnutls_free(extra_certs);
1117 #if defined (HAVE_P11KIT) || defined (HAVE_TROUSERS)
1118         if (pkey && pkey != OPENCONNECT_TPM_PKEY)
1119                 gnutls_privkey_deinit(pkey);
1120         if (fdata.data != dummy_hash_data)
1121 #endif /* It's conditional if we support arbitrary privkeys: */
1122                 gnutls_free(fdata.data);
1123 #ifdef HAVE_P11KIT
1124         if (cert_url != vpninfo->cert)
1125                 free(cert_url);
1126         if (key_url != vpninfo->sslkey)
1127                 free(key_url);
1128 #endif
1129         return ret;
1130 }
1131
1132 static int get_cert_fingerprint(struct openconnect_info *vpninfo,
1133                                 gnutls_x509_crt_t cert,
1134                                 gnutls_digest_algorithm_t algo,
1135                                 char *buf)
1136 {
1137         unsigned char md[256];
1138         size_t md_size = sizeof(md);
1139         unsigned int i;
1140
1141         if (gnutls_x509_crt_get_fingerprint(cert, algo, md, &md_size))
1142                 return -EIO;
1143
1144         for (i=0; i < md_size; i++)
1145                 sprintf(&buf[i*2], "%02X", md[i]);
1146
1147         return 0;
1148 }
1149
1150 int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
1151                              OPENCONNECT_X509 *cert, char *buf)
1152 {
1153         return get_cert_fingerprint(vpninfo, cert, GNUTLS_DIG_MD5, buf);
1154 }
1155
1156 int openconnect_get_cert_sha1(struct openconnect_info *vpninfo,
1157                               OPENCONNECT_X509 *cert, char *buf)
1158 {
1159         return get_cert_fingerprint(vpninfo, cert, GNUTLS_DIG_SHA1, buf);
1160 }
1161
1162 char *openconnect_get_cert_details(struct openconnect_info *vpninfo,
1163                                    OPENCONNECT_X509 *cert)
1164 {
1165         gnutls_datum_t buf;
1166         char *ret;
1167
1168         if (gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL, &buf))
1169                 return NULL;
1170         
1171         /* Just in case gnutls_free() isn't free(), we can't steal it. */
1172         ret = strdup((char *)buf.data);
1173         gnutls_free(buf.data);
1174         
1175         return ret;
1176 }
1177
1178 int openconnect_get_cert_DER(struct openconnect_info *vpninfo,
1179                              OPENCONNECT_X509 *cert, unsigned char **buf)
1180 {
1181         size_t l = 0;
1182         unsigned char *ret = NULL;
1183
1184         if (gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, ret, &l) != 
1185             GNUTLS_E_SHORT_MEMORY_BUFFER)
1186                 return -EIO;
1187
1188         ret = malloc(l);
1189         if (!ret)
1190                 return -ENOMEM;
1191
1192         if (gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, ret, &l)) {
1193                 free(ret);
1194                 return -EIO;
1195         }
1196         *buf = ret;
1197         return l;
1198 }
1199
1200 static int verify_peer(gnutls_session_t session)
1201 {
1202         struct openconnect_info *vpninfo = gnutls_session_get_ptr(session);
1203         const gnutls_datum_t *cert_list;
1204         gnutls_x509_crt_t cert;
1205         unsigned int status, cert_list_size;
1206         const char *reason = NULL;
1207         int err;
1208
1209         if (vpninfo->peer_cert) {
1210                 gnutls_x509_crt_deinit(vpninfo->peer_cert);
1211                 vpninfo->peer_cert = NULL;
1212         }
1213
1214         cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
1215         if (!cert_list) {
1216                 vpn_progress(vpninfo, PRG_ERR, _("Server presented no certificate\n"));
1217                 return GNUTLS_E_CERTIFICATE_ERROR;
1218         }
1219
1220         if (vpninfo->servercert) {
1221                 unsigned char sha1bin[SHA1_SIZE];
1222                 char fingerprint[(SHA1_SIZE * 2) + 1];
1223                 int i;
1224                 
1225                 err = openconnect_sha1(sha1bin, cert_list[0].data, cert_list[0].size);
1226                 if (err) {
1227                         vpn_progress(vpninfo, PRG_ERR,
1228                                      _("Could not calculate SHA1 of server's certificate\n"));
1229                         return GNUTLS_E_CERTIFICATE_ERROR;
1230                 }
1231                 for (i=0; i < SHA1_SIZE; i++)
1232                         sprintf(&fingerprint[i*2], "%02X", sha1bin[i]);
1233
1234                 if (strcasecmp(vpninfo->servercert, fingerprint)) {
1235                         vpn_progress(vpninfo, PRG_ERR,
1236                                      _("Server SSL certificate didn't match: %s\n"), fingerprint);
1237                         return GNUTLS_E_CERTIFICATE_ERROR;
1238                 }
1239                 return 0;
1240         }
1241
1242         err = gnutls_certificate_verify_peers2 (session, &status);
1243         if (err) {
1244                 vpn_progress(vpninfo, PRG_ERR, _("Error checking server cert status\n"));
1245                 return GNUTLS_E_CERTIFICATE_ERROR;
1246         }
1247
1248         if (status & GNUTLS_CERT_REVOKED)
1249                 reason = _("certificate revoked");
1250         else if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
1251                 reason = _("signer not found");
1252         else if (status & GNUTLS_CERT_SIGNER_NOT_CA)
1253                 reason = _("signer not a CA certificate");
1254         else if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
1255                 reason = _("insecure algorithm");
1256         else if (status & GNUTLS_CERT_NOT_ACTIVATED)
1257                 reason = _("certificate not yet activated");
1258         else if (status & GNUTLS_CERT_EXPIRED)
1259                 reason = _("certificate expired");
1260         else if (status & GNUTLS_CERT_INVALID)
1261                 /* If this is set and no other reason, it apparently means
1262                    that signature verification failed. Not entirely sure
1263                    why we don't just set a bit for that too. */
1264                 reason = _("signature verification failed");
1265
1266         err = gnutls_x509_crt_init(&cert);
1267         if (err) {
1268                 vpn_progress(vpninfo, PRG_ERR, _("Error initialising X509 cert structure\n"));
1269                 return GNUTLS_E_CERTIFICATE_ERROR;
1270         }
1271
1272         err = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
1273         if (err) {
1274                 vpn_progress(vpninfo, PRG_ERR, _("Error importing server's cert\n"));
1275                 gnutls_x509_crt_deinit(cert);
1276                 return GNUTLS_E_CERTIFICATE_ERROR;
1277         }
1278
1279         if (!reason && !gnutls_x509_crt_check_hostname(cert, vpninfo->hostname))
1280                 reason = _("certificate does not match hostname");
1281
1282         if (reason) {
1283                 vpn_progress(vpninfo, PRG_INFO, "Server certificate verify failed: %s\n",
1284                              reason);
1285                 if (vpninfo->validate_peer_cert)
1286                         err = vpninfo->validate_peer_cert(vpninfo->cbdata,
1287                                                           cert,
1288                                                           reason) ? GNUTLS_E_CERTIFICATE_ERROR : 0;
1289                 else
1290                         err = GNUTLS_E_CERTIFICATE_ERROR;
1291         }
1292
1293         vpninfo->peer_cert = cert;
1294
1295         return err;
1296 }
1297
1298
1299 int openconnect_open_https(struct openconnect_info *vpninfo)
1300 {
1301         int ssl_sock = -1;
1302         int err;
1303
1304         if (vpninfo->https_sess)
1305                 return 0;
1306
1307         ssl_sock = connect_https_socket(vpninfo);
1308         if (ssl_sock < 0)
1309                 return ssl_sock;
1310
1311         if (!vpninfo->https_cred) {
1312                 gnutls_certificate_allocate_credentials(&vpninfo->https_cred);
1313 #ifdef HAVE_GNUTLS_CERTIFICATE_SET_X509_SYSTEM_TRUST
1314                 gnutls_certificate_set_x509_system_trust(vpninfo->https_cred);
1315 #else
1316                 gnutls_certificate_set_x509_trust_file(vpninfo->https_cred,
1317                                                        "/etc/pki/tls/certs/ca-bundle.crt",
1318                                                        GNUTLS_X509_FMT_PEM);
1319 #endif
1320                 gnutls_certificate_set_verify_function (vpninfo->https_cred,
1321                                                         verify_peer);
1322
1323                 if (vpninfo->cafile) {
1324                         err = gnutls_certificate_set_x509_trust_file(vpninfo->https_cred,
1325                                                                      vpninfo->cafile,
1326                                                                      GNUTLS_X509_FMT_PEM);
1327                         if (err < 0) {
1328                                 vpn_progress(vpninfo, PRG_ERR,
1329                                              _("Failed to open CA file '%s': %s\n"),
1330                                              vpninfo->cafile, gnutls_strerror(err));
1331                                 close(ssl_sock);
1332                                 return -EINVAL;
1333                         }
1334                 }
1335
1336                 if (vpninfo->cert) {
1337                         err = load_certificate(vpninfo);
1338                         if (err) {
1339                                 vpn_progress(vpninfo, PRG_ERR,
1340                                              _("Loading certificate failed. Aborting.\n"));
1341                                 return err;
1342                         }
1343                 }
1344         }
1345         gnutls_init (&vpninfo->https_sess, GNUTLS_CLIENT);
1346         gnutls_session_set_ptr (vpninfo->https_sess, (void *) vpninfo);
1347 #if defined(HAVE_TROUSERS) && !defined(HAVE_GNUTLS_CERTIFICATE_SET_KEY)
1348         if (vpninfo->my_pkey == OPENCONNECT_TPM_PKEY)
1349                 gnutls_sign_callback_set(vpninfo->https_sess, gtls2_tpm_sign_cb, vpninfo);
1350 #endif
1351         err = gnutls_priority_set_direct (vpninfo->https_sess, "NONE:+VERS-TLS1.0:+SHA1:+AES-128-CBC:+RSA:+COMP-NULL:%COMPAT:%DISABLE_SAFE_RENEGOTIATION", NULL);
1352         if (err) {
1353                 vpn_progress(vpninfo, PRG_ERR,
1354                              _("Failed to set TLS priority string: %s\n"),
1355                              gnutls_strerror(err));
1356                 return -EIO;
1357         }
1358
1359         gnutls_record_disable_padding (vpninfo->https_sess);
1360         gnutls_credentials_set (vpninfo->https_sess, GNUTLS_CRD_CERTIFICATE, vpninfo->https_cred);
1361         gnutls_transport_set_ptr(vpninfo->https_sess, /* really? */(gnutls_transport_ptr_t)(long) ssl_sock);
1362
1363         vpn_progress(vpninfo, PRG_INFO, _("SSL negotiation with %s\n"),
1364                      vpninfo->hostname);
1365
1366         while ((err = gnutls_handshake (vpninfo->https_sess))) {
1367                 if (err == GNUTLS_E_AGAIN) {
1368                         fd_set rd_set, wr_set;
1369                         int maxfd = ssl_sock;
1370                         
1371                         FD_ZERO(&rd_set);
1372                         FD_ZERO(&wr_set);
1373                         
1374                         if (gnutls_record_get_direction(vpninfo->https_sess))
1375                                 FD_SET(ssl_sock, &wr_set);
1376                         else
1377                                 FD_SET(ssl_sock, &rd_set);
1378
1379                         if (vpninfo->cancel_fd != -1) {
1380                                 FD_SET(vpninfo->cancel_fd, &rd_set);
1381                                 if (vpninfo->cancel_fd > ssl_sock)
1382                                         maxfd = vpninfo->cancel_fd;
1383                         }
1384                         select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
1385                         if (vpninfo->cancel_fd != -1 &&
1386                             FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
1387                                 vpn_progress(vpninfo, PRG_ERR, _("SSL connection cancelled\n"));
1388                                 gnutls_deinit(vpninfo->https_sess);
1389                                 vpninfo->https_sess = NULL;
1390                                 close(ssl_sock);
1391                                 return -EINTR;
1392                         }
1393                 } else if (err == GNUTLS_E_INTERRUPTED || gnutls_error_is_fatal(err)) {
1394                         vpn_progress(vpninfo, PRG_ERR, _("SSL connection failure: %s\n"),
1395                                                          gnutls_strerror(err));
1396                         gnutls_deinit(vpninfo->https_sess);
1397                         vpninfo->https_sess = NULL;
1398                         close(ssl_sock);
1399                         return -EIO;
1400                 } else {
1401                         /* non-fatal error or warning. Ignore it and continue */
1402                         vpn_progress(vpninfo, PRG_TRACE,
1403                                      _("GnuTLS non-fatal return during handshake: %s\n"),
1404                                      gnutls_strerror(err));
1405                 }
1406         }
1407
1408         vpninfo->ssl_fd = ssl_sock;
1409
1410         vpn_progress(vpninfo, PRG_INFO, _("Connected to HTTPS on %s\n"),
1411                      vpninfo->hostname);
1412
1413         return 0;
1414 }
1415
1416 void openconnect_close_https(struct openconnect_info *vpninfo, int final)
1417 {
1418         if (vpninfo->peer_cert) {
1419                 gnutls_x509_crt_deinit(vpninfo->peer_cert);
1420                 vpninfo->peer_cert = NULL;
1421         }
1422         if (vpninfo->https_sess) {
1423                 gnutls_deinit(vpninfo->https_sess);
1424                 vpninfo->https_sess = NULL;
1425         }
1426         if (vpninfo->ssl_fd != -1) {
1427                 close(vpninfo->ssl_fd);
1428                 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds);
1429                 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
1430                 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds);
1431                 vpninfo->ssl_fd = -1;
1432         }
1433         if (final && vpninfo->https_cred) {
1434                 gnutls_certificate_free_credentials(vpninfo->https_cred);
1435                 vpninfo->https_cred = NULL;
1436 #ifdef HAVE_P11KIT
1437                 if (!strncmp(vpninfo->cert, "pkcs11:", 7) ||
1438                     !strncmp(vpninfo->sslkey, "pkcs11:", 7)) {
1439                         char pin_source[40];
1440
1441                         sprintf(pin_source, "openconnect:%p", vpninfo);
1442                         p11_kit_pin_unregister_callback(pin_source, pin_callback, vpninfo);
1443
1444                         while (vpninfo->pin_cache) {
1445                                 struct pin_cache *cache = vpninfo->pin_cache;
1446
1447                                 free(cache->token);
1448                                 memset(cache->pin, 0x5a, strlen(cache->pin));
1449                                 free(cache->pin);
1450                                 vpninfo->pin_cache = cache->next;
1451                                 free(cache);
1452                         }
1453                 }
1454 #endif
1455 #ifdef HAVE_TROUSERS
1456                 if (vpninfo->tpm_key_policy) {
1457                         Tspi_Context_CloseObject(vpninfo->tpm_context, vpninfo->tpm_key_policy);
1458                         vpninfo->tpm_key = 0;
1459                 }
1460                 if (vpninfo->tpm_key) {
1461                         Tspi_Context_CloseObject(vpninfo->tpm_context, vpninfo->tpm_key);
1462                         vpninfo->tpm_key = 0;
1463                 }
1464                 if (vpninfo->srk_policy) {
1465                         Tspi_Context_CloseObject(vpninfo->tpm_context, vpninfo->srk_policy);
1466                         vpninfo->srk_policy = 0;
1467                 }
1468                 if (vpninfo->srk) {
1469                         Tspi_Context_CloseObject(vpninfo->tpm_context, vpninfo->srk);
1470                         vpninfo->srk = 0;
1471                 }
1472                 if (vpninfo->tpm_context) {
1473                         Tspi_Context_Close(vpninfo->tpm_context);
1474                         vpninfo->tpm_context = 0;
1475                 }
1476 #endif
1477 #ifndef HAVE_GNUTLS_CERTIFICATE_SET_KEY
1478                 if (vpninfo->my_pkey && vpninfo->my_pkey != OPENCONNECT_TPM_PKEY) {
1479                         gnutls_privkey_deinit(vpninfo->my_pkey);
1480                         vpninfo->my_pkey = NULL;
1481                         /* my_p11key went with it */
1482                 }
1483                 if (vpninfo->my_certs) {
1484                         int i;
1485                         for (i = 0; i < vpninfo->nr_my_certs; i++)
1486                                 gnutls_x509_crt_deinit(vpninfo->my_certs[i]);
1487                         free(vpninfo->my_certs);
1488                         vpninfo->my_certs = NULL;
1489                 }
1490 #endif
1491         }
1492 }
1493
1494 void openconnect_init_ssl(void)
1495 {
1496         gnutls_global_init();
1497 }
1498
1499 int openconnect_sha1(unsigned char *result, void *data, int datalen)
1500 {
1501         gnutls_datum_t d;
1502         size_t shalen = SHA1_SIZE;
1503
1504         d.data = data;
1505         d.size = datalen;
1506         if (gnutls_fingerprint(GNUTLS_DIG_SHA1, &d, result, &shalen))
1507                 return -1;
1508
1509         return 0;
1510 }
1511
1512 int openconnect_random(void *bytes, int len)
1513 {
1514         if (gnutls_rnd(GNUTLS_RND_RANDOM, bytes, len))
1515                 return -EIO;
1516         return 0;
1517 }
1518
1519 int openconnect_local_cert_md5(struct openconnect_info *vpninfo,
1520                                char *buf)
1521 {
1522         const gnutls_datum_t *d;
1523         size_t md5len = 16;
1524
1525         buf[0] = 0;
1526
1527         d = gnutls_certificate_get_ours(vpninfo->https_sess);
1528         if (!d)
1529                 return -EIO;
1530
1531         if (gnutls_fingerprint(GNUTLS_DIG_MD5, d, buf, &md5len))
1532                 return -EIO;
1533
1534         return 0;
1535 }
1536
1537 #ifdef HAVE_P11KIT
1538 static P11KitPin *pin_callback(const char *pin_source, P11KitUri *pin_uri,
1539                         const char *pin_description,
1540                         P11KitPinFlags flags,
1541                         void *_vpninfo)
1542 {
1543         struct openconnect_info *vpninfo = _vpninfo;
1544         struct pin_cache **cache = &vpninfo->pin_cache;
1545         struct oc_auth_form f;
1546         struct oc_form_opt o;
1547         char message[1024];
1548         char *uri;
1549         P11KitPin *pin;
1550         int ret;
1551
1552         if (!vpninfo || !vpninfo->process_auth_form)
1553                 return NULL;
1554
1555         if (p11_kit_uri_format(pin_uri, P11_KIT_URI_FOR_TOKEN, &uri))
1556                 return NULL;
1557         
1558         while (*cache) {
1559                 if (!strcmp(uri, (*cache)->token)) {
1560                         free(uri);
1561                         uri = NULL;
1562                         if ((*cache)->pin) {
1563                                 if ((flags & P11_KIT_PIN_FLAGS_RETRY) != P11_KIT_PIN_FLAGS_RETRY)
1564                                         return p11_kit_pin_new_for_string((*cache)->pin);
1565                                 memset((*cache)->pin, 0x5a, strlen((*cache)->pin));
1566                                 free((*cache)->pin);
1567                                 (*cache)->pin = NULL;
1568                         }
1569                         break;
1570                 }
1571         }
1572         if (!*cache) {
1573                 *cache = calloc(1, sizeof(struct pin_cache));
1574                 if (!*cache) {
1575                         free(uri);
1576                         return NULL;
1577                 }
1578                 (*cache)->token = uri;
1579         }
1580
1581         memset(&f, 0, sizeof(f));
1582         f.auth_id = (char *)"pkcs11_pin";
1583         f.opts = &o;
1584
1585         message[sizeof(message)-1] = 0;
1586         snprintf(message, sizeof(message) - 1, _("PIN required for %s"), pin_description);
1587         f.message = message;
1588         
1589         /* 
1590          * In p11-kit <= 0.12, these flags are *odd*.
1591          * RETRY is 0xa, FINAL_TRY is 0x14 and MANY_TRIES is 0x28.
1592          * So don't treat it like a sane bitmask. Fixed in
1593          * http://cgit.freedesktop.org/p11-glue/p11-kit/commit/?id=59774b11
1594          */
1595         if ((flags & P11_KIT_PIN_FLAGS_RETRY) == P11_KIT_PIN_FLAGS_RETRY)
1596                 f.error = (char *)_("Wrong PIN");
1597
1598         if ((flags & P11_KIT_PIN_FLAGS_FINAL_TRY) == P11_KIT_PIN_FLAGS_FINAL_TRY)
1599                 f.banner = (char *)_("This is the final try before locking!");
1600         else if ((flags & P11_KIT_PIN_FLAGS_MANY_TRIES) == P11_KIT_PIN_FLAGS_MANY_TRIES)
1601                 f.banner = (char *)_("Only a few tries left before locking!");
1602
1603         o.next = NULL;
1604         o.type = OC_FORM_OPT_PASSWORD;
1605         o.name = (char *)"pkcs11_pin";
1606         o.label = (char *)_("Enter PIN:");
1607         o.value = NULL;
1608
1609         ret = vpninfo->process_auth_form(vpninfo->cbdata, &f);
1610         if (ret || !o.value)
1611                 return NULL;
1612
1613         pin = p11_kit_pin_new_for_string(o.value);
1614         (*cache)->pin = o.value;
1615
1616         return pin;
1617 }
1618 #endif