Clean up GnuTLS load_certificate() and improve comments
[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 our caller
492            can free them after gnutls_certificate_set_key() has been called.
493            So 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 extra_certs[] that
498            correspond to the certs that we're stealing.
499            We know certs[0] was already stolen by the load_certificate()
500            function so we might as well start at certs[1]. */
501         for (i = 1; i < nr_certs; i++) {
502                 int j;
503                 for (j = 0; j < nr_extra_certs; j++) {
504                         if (vpninfo->my_certs[i] == extra_certs[j]) {
505                                 extra_certs[j] = NULL;
506                                 break;
507                         }
508                 }
509         }
510
511         gnutls_certificate_set_retrieve_function(vpninfo->https_cred,
512                                                  gtls_cert_cb);
513         vpninfo->my_pkey = pkey;
514
515         return 0;
516 }
517 #else /* !SET_KEY */
518
519 /* For GnuTLS 3+ this is saner than the GnuTLS 2.12 version. But still we
520    have to convert the array of X509 certificates to gnutls_pcert_st for
521    ourselves. There's no function that takes a gnutls_privkey_t as the key
522    and gnutls_x509_crt_t certificates. */
523 static int assign_privkey(struct openconnect_info *vpninfo,
524                           gnutls_privkey_t pkey,
525                           gnutls_x509_crt_t *certs,
526                           unsigned int nr_certs,
527                           gnutls_x509_crt_t *extra_certs,
528                           unsigned int nr_extra_certs)
529 {
530         gnutls_pcert_st *pcerts = calloc(nr_certs, sizeof(*pcerts));
531         int i, err;
532
533         if (!pcerts)
534                 return GNUTLS_E_MEMORY_ERROR;
535
536         for (i=0 ; i < nr_certs; i++) {
537                 err = gnutls_pcert_import_x509(pcerts + i, certs[i], 0);
538                 if (err) {
539                         vpn_progress(vpninfo, PRG_ERR,
540                                      _("Importing X509 certificate failed: %s\n"),
541                                      gnutls_strerror(err));
542                         goto free_pcerts;
543                 }
544         }
545
546         err = gnutls_certificate_set_key(vpninfo->https_cred, NULL, 0,
547                                          pcerts, nr_certs, pkey);
548         if (err) {
549                 vpn_progress(vpninfo, PRG_ERR,
550                              _("Setting PKCS#11 certificate failed: %s\n"),
551                              gnutls_strerror(err));
552         free_pcerts:
553                 for (i=0 ; i < nr_certs; i++)
554                         gnutls_pcert_deinit(pcerts + i);
555                 free (pcerts);
556         }
557         return err;
558 }
559 #endif /* !SET_KEY */
560 #endif /* (P11KIT || TROUSERS) */
561
562 static int load_certificate(struct openconnect_info *vpninfo)
563 {
564         gnutls_datum_t fdata;
565         gnutls_x509_privkey_t key = NULL;
566 #if defined (HAVE_P11KIT) || defined (HAVE_TROUSERS)
567         gnutls_privkey_t pkey = NULL;
568         gnutls_datum_t pkey_sig = {NULL, 0};
569         void *dummy_hash_data = &load_certificate;
570 #endif
571 #ifdef HAVE_P11KIT
572         char *cert_url = (char *)vpninfo->cert;
573         char *key_url = (char *)vpninfo->sslkey;
574         gnutls_pkcs11_privkey_t p11key = NULL;
575 #endif
576         gnutls_x509_crl_t crl = NULL;
577         gnutls_x509_crt_t last_cert, cert = NULL;
578         gnutls_x509_crt_t *extra_certs = NULL, *supporting_certs = NULL;
579         unsigned int nr_supporting_certs = 0, nr_extra_certs = 0;
580         unsigned int certs_to_free = 0; /* How many of supporting_certs */
581         int err; /* GnuTLS error */
582         int ret;
583         int i;
584         int cert_is_p11 = 0, key_is_p11 = 0;
585         unsigned char key_id[20];
586         size_t key_id_size = sizeof(key_id);
587         char name[80];
588
589         fdata.data = NULL;
590
591         key_is_p11 = !strncmp(vpninfo->sslkey, "pkcs11:", 7);
592         cert_is_p11 = !strncmp(vpninfo->cert, "pkcs11:", 7);
593
594 #ifndef HAVE_P11KIT
595         if (key_is_p11 || cert_is_p11) {
596                 vpn_progress(vpninfo, PRG_ERR,
597                              _("This binary built without PKCS#11 support\n"));
598                 return -EINVAL;
599         }
600 #else
601         /* Install PIN handler if either certificate or key are coming from PKCS#11 */
602         if (key_is_p11 || cert_is_p11) {
603                 CK_OBJECT_CLASS class;
604                 CK_ATTRIBUTE attr;
605                 char pin_source[40];
606                 P11KitUri *uri;
607
608                 sprintf(pin_source, "openconnect:%p", vpninfo);
609                 p11_kit_pin_register_callback(pin_source, pin_callback, vpninfo, NULL);
610
611                 uri = p11_kit_uri_new();
612
613                 attr.type = CKA_CLASS;
614                 attr.pValue = &class;
615                 attr.ulValueLen = sizeof(class);
616
617                 /* Add appropriate pin-source and object-type attributes to
618                    both certificate and key URLs, unless they already exist. */
619                 if (cert_is_p11 &&
620                     !p11_kit_uri_parse(cert_url, P11_KIT_URI_FOR_OBJECT, uri)) {
621                         if (!p11_kit_uri_get_pin_source(uri))
622                                 p11_kit_uri_set_pin_source(uri, pin_source);
623                         if (!p11_kit_uri_get_attribute(uri, CKA_CLASS)) {
624                                 class = CKO_CERTIFICATE;
625                                 p11_kit_uri_set_attribute(uri, &attr);
626                         }
627                         p11_kit_uri_format(uri, P11_KIT_URI_FOR_OBJECT, &cert_url);
628                 }
629
630                 if (key_is_p11 &&
631                     !p11_kit_uri_parse(key_url, P11_KIT_URI_FOR_OBJECT, uri)) {
632                         if (!p11_kit_uri_get_pin_source(uri))
633                                 p11_kit_uri_set_pin_source(uri, pin_source);
634                         if (!p11_kit_uri_get_attribute(uri, CKA_CLASS)) {
635                                 class = CKO_PRIVATE_KEY;
636                                 p11_kit_uri_set_attribute(uri, &attr);
637                         }
638                         p11_kit_uri_format(uri, P11_KIT_URI_FOR_OBJECT, &key_url);
639                 }
640
641                 p11_kit_uri_free(uri);
642         }
643
644         /* Load certificate(s) first... */
645         if (cert_is_p11) {
646                 vpn_progress(vpninfo, PRG_TRACE,
647                              _("Using PKCS#11 certificate %s\n"), cert_url);
648
649                 err = gnutls_x509_crt_init(&cert);
650                 if (err) {
651                         ret = -ENOMEM;
652                         goto out;
653                 }
654                 err = gnutls_x509_crt_import_pkcs11_url(cert, cert_url, 0);
655                 if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
656                         err = gnutls_x509_crt_import_pkcs11_url(cert, cert_url,
657                                                                 GNUTLS_PKCS11_OBJ_FLAG_LOGIN);
658                 if (err) {
659                         vpn_progress(vpninfo, PRG_ERR,
660                                      _("Error loading certificate from PKCS#11: %s\n"),
661                                      gnutls_strerror(err));
662                         ret = -EIO;
663                         goto out;
664                 }
665                 goto got_certs;
666         }
667 #endif /* HAVE_P11KIT */
668
669         /* OK, not a PKCS#11 certificate so it must be coming from a file... */
670         vpn_progress(vpninfo, PRG_TRACE,
671                      _("Using certificate file %s\n"), vpninfo->cert);
672
673         /* Load file contents */
674         ret = load_datum(vpninfo, &fdata, vpninfo->cert);
675         if (ret)
676                 return ret;
677
678         /* Is it PKCS#12? */
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 either a single certificate in 'cert', or an array of
736            them in extra_certs[]. Next we look for the private key ... */
737 #if defined (HAVE_P11KIT)
738         if (key_is_p11) {
739                 vpn_progress(vpninfo, PRG_TRACE,
740                              _("Using PKCS#11 key %s\n"), key_url);
741
742                 err = gnutls_pkcs11_privkey_init(&p11key);
743                 if (err) {
744                         vpn_progress(vpninfo, PRG_ERR,
745                                      _("Error initialising PKCS#11 key structure: %s\n"),
746                                      gnutls_strerror(err));
747                         ret = -EIO;
748                         goto out;
749                 }
750
751                 err = gnutls_pkcs11_privkey_import_url(p11key, key_url, 0);
752                 if (err) {
753                         vpn_progress(vpninfo, PRG_ERR,
754                                      _("Error importing PKCS#11 URL %s: %s\n"),
755                                      key_url, gnutls_strerror(err));
756                         gnutls_pkcs11_privkey_deinit(p11key);
757                         ret = -EIO;
758                         goto out;
759                 }
760
761                 err = gnutls_privkey_init(&pkey);
762                 if (err) {
763                         vpn_progress(vpninfo, PRG_ERR,
764                                      _("Error initialising private key structure: %s\n"),
765                                      gnutls_strerror(err));
766                         gnutls_pkcs11_privkey_deinit(p11key);
767                         ret = -EIO;
768                         goto out;
769                 }
770
771                 err = gnutls_privkey_import_pkcs11(pkey, p11key, GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE);
772                 if (err) {
773                         vpn_progress(vpninfo, PRG_ERR,
774                                      _("Error importing PKCS#11 key into private key structure: %s\n"),
775                                      gnutls_strerror(err));
776                         gnutls_pkcs11_privkey_deinit(p11key);
777                         ret = -EIO;
778                         goto out;
779                 }
780 #ifndef HAVE_GNUTLS_CERTIFICATE_SET_KEY
781                 /* This can be set now and doesn't need to be separately freed.
782                    It goes with the pkey. This is a PITA; it would be better
783                    if there was a way to get the p11key *back* from a privkey
784                    that we *know* is based on one. In fact, since this is only
785                    for GnuTLS 2.12 and we *know* the gnutls_privkey_st won't
786                    ever change there, so we *could* do something evil... but
787                    we won't :) */
788                 vpninfo->my_p11key = p11key;
789 #endif /* !SET_KEY */
790                 goto match_cert;
791         }
792 #endif /* HAVE_P11KIT */
793
794         /* OK, not a PKCS#11 key so it must be coming from a file... load the
795            file into memory, unless it's the same as the cert file and we
796            already loaded that. */
797         if (!fdata.data || vpninfo->sslkey != vpninfo->cert) {
798                 gnutls_free(fdata.data);
799                 fdata.data = NULL;
800
801                 vpn_progress(vpninfo, PRG_TRACE,
802                              _("Using private key file %s\n"), vpninfo->sslkey);
803
804                 ret = load_datum(vpninfo, &fdata, vpninfo->sslkey);
805                 if (ret)
806                         goto out;
807         }
808
809         /* Is it a PEM file with a TPM key blob? */
810         if (vpninfo->cert_type == CERT_TYPE_TPM ||
811             (vpninfo->cert_type == CERT_TYPE_UNKNOWN &&
812              strstr((char *)fdata.data, "-----BEGIN TSS KEY BLOB-----"))) {
813 #ifndef HAVE_TROUSERS
814                 vpn_progress(vpninfo, PRG_ERR,
815                              _("This version of OpenConnect was built without TPM support\n"));
816                 return -EINVAL;
817 #else
818                 ret = load_tpm_key(vpninfo, &fdata, &pkey, &pkey_sig);
819                 if (ret)
820                         goto out;
821
822                 goto match_cert;
823 #endif
824         }
825
826         /* OK, try other PEM files... */
827         gnutls_x509_privkey_init(&key);
828         /* Try PKCS#1 (and PKCS#8 without password) first. GnuTLS doesn't
829            support OpenSSL's old PKCS#1-based encrypted format. We should
830            probably check for it and give a more coherent failure mode. */
831         err = gnutls_x509_privkey_import(key, &fdata, GNUTLS_X509_FMT_PEM);
832         if (err) {
833                 /* If that fails, try PKCS#8 */
834                 char *pass = vpninfo->cert_password;
835
836                 /* Yay, just for fun this is *different* to PKCS#12. Where we could
837                    try an empty password there, in this case the empty-password case
838                    has already been *tried* by gnutls_x509_privkey_import(). If we
839                    just call gnutls_x509_privkey_import_pkcs8() with a NULL password,
840                    it'll SEGV. You have to set the GNUTLS_PKCS_PLAIN flag if you want
841                    to try without a password. Passing NULL evidently isn't enough of
842                    a hint. And in GnuTLS 3.1 where that crash has been fixed, passing
843                    NULL will cause it to return GNUTLS_E_ENCRYPTED_STRUCTURE (a new
844                    error code) rather than GNUTLS_E_DECRYPTION_FAILED. So just pass ""
845                    instead of NULL, and don't worry about either case. */
846                 while ((err = gnutls_x509_privkey_import_pkcs8(key, &fdata,
847                                                                GNUTLS_X509_FMT_PEM,
848                                                                pass?pass:"", 0))) {
849                         if (err != GNUTLS_E_DECRYPTION_FAILED) {
850                                 vpn_progress(vpninfo, PRG_ERR,
851                                              _("Failed to load private key as PKCS#8: %s\n"),
852                                              gnutls_strerror(err));
853                                 ret = -EINVAL;
854                                 goto out;
855                         }
856                         vpninfo->cert_password = NULL;
857                         if (pass) {
858                                 vpn_progress(vpninfo, PRG_ERR,
859                                              _("Failed to decrypt PKCS#8 certificate file\n"));
860                                 free(pass);
861                         }
862                         err = request_passphrase(vpninfo, "openconnect_pem",
863                                                  &pass, _("Enter PEM pass phrase:"));
864                         if (err) {
865                                 ret = -EINVAL;
866                                 goto out;
867                         }
868                 }
869                 free(pass);
870                 vpninfo->cert_password = NULL;
871         }
872
873         /* Now attempt to make sure we use the *correct* certificate, to match
874            the key. Since we have a software key, we can easily query it and
875            compare its key_id with each certificate till we find a match. */
876         err = gnutls_x509_privkey_get_key_id(key, 0, key_id, &key_id_size);
877         if (err) {
878                 vpn_progress(vpninfo, PRG_ERR,
879                              _("Failed to get key ID: %s\n"),
880                              gnutls_strerror(err));
881                 ret = -EINVAL;
882                 goto out;
883         }
884         /* If extra_certs[] is NULL, we have one candidate in 'cert' to check. */
885         for (i = 0; i < (extra_certs?nr_extra_certs:1); i++) {
886                 unsigned char cert_id[20];
887                 size_t cert_id_size = sizeof(cert_id);
888
889                 err = gnutls_x509_crt_get_key_id(extra_certs?extra_certs[i]:cert, 0, cert_id, &cert_id_size);
890                 if (err)
891                         continue;
892
893                 if (cert_id_size == key_id_size && !memcmp(cert_id, key_id, key_id_size)) {
894                         if (extra_certs) {
895                                 cert = extra_certs[i];
896
897                                 /* Move the rest of the array down */
898                                 for (; i < nr_extra_certs - 1; i++)
899                                         extra_certs[i] = extra_certs[i+1];
900
901                                 nr_extra_certs--;
902                         }
903                         goto got_key;
904                 }
905         }
906         /* There's no pkey (there's an x509 key), so even if p11-kit or trousers is
907            enabled we'll fall straight through the bit at match_cert: below, and go
908            directly to the bit where it prints the 'no match found' error and exits. */
909
910 #if defined (HAVE_P11KIT) || defined (HAVE_TROUSERS)
911  match_cert:
912         /* If we have a privkey from PKCS#11 or TPM, we can't do the simple comparison
913            of key ID that we do for software keys to find which certificate is a
914            match. So sign some dummy data and then check the signature against each
915            of the available certificates until we find the right one. */
916         if (pkey) {
917                 /* The TPM code may have already signed it, to test authorisation. We
918                    only sign here for PKCS#11 keys, in which case fdata might be
919                    empty too so point it at dummy data. */
920                 if (!pkey_sig.data) {
921                         if (!fdata.data) {
922                                 fdata.data = dummy_hash_data;
923                                 fdata.size = 20;
924                         }
925
926                         err = sign_dummy_data(vpninfo, pkey, &fdata, &pkey_sig);
927                         if (err) {
928                                 vpn_progress(vpninfo, PRG_ERR,
929                                              _("Error signing test data with private key: %s\n"),
930                                              gnutls_strerror(err));
931                                 ret = -EINVAL;
932                                 goto out;
933                         }
934                 }
935
936                 /* If extra_certs[] is NULL, we have one candidate in 'cert' to check. */
937                 for (i=0; i < (extra_certs?nr_extra_certs:1); i++) {
938                         gnutls_pubkey_t pubkey;
939
940                         gnutls_pubkey_init(&pubkey);
941                         err = gnutls_pubkey_import_x509(pubkey, extra_certs?extra_certs[i]:cert, 0);
942                         if (err) {
943                                 vpn_progress(vpninfo, PRG_ERR,
944                                              _("Error validating signature against certificate: %s\n"),
945                                              gnutls_strerror(err));
946                                 /* We'll probably fail shortly if we don't find it. */
947                                 gnutls_pubkey_deinit(pubkey);
948                                 continue;
949                         }
950                         err = gnutls_pubkey_verify_data(pubkey, 0, &fdata, &pkey_sig);
951                         gnutls_pubkey_deinit(pubkey);
952
953                         if (err >= 0) {
954                                 if (extra_certs) {
955                                         cert = extra_certs[i];
956
957                                         /* Move the rest of the array down */
958                                         for (; i < nr_extra_certs - 1; i++)
959                                                 extra_certs[i] = extra_certs[i+1];
960
961                                         nr_extra_certs--;
962                                 }
963                                 gnutls_free(pkey_sig.data);
964                                 goto got_key;
965                         }
966                 }
967                 gnutls_free(pkey_sig.data);
968         }
969 #endif /* P11KIT || TROUSERS */
970
971         /* We shouldn't reach this. It means that we didn't find *any* matching cert */
972         vpn_progress(vpninfo, PRG_ERR,
973                      _("No SSL certificate found to match private key\n"));
974         ret = -EINVAL;
975         goto out;
976
977         /********************************************************************/
978  got_key:
979         /* Now we have a key in either 'key' or 'pkey', a matching cert in 'cert',
980            and potentially a list of other certs in 'extra_certs[]'. If we loaded
981            a PKCS#12 file we may have a trust chain in 'supporting_certs[]' too. */
982         check_certificate_expiry(vpninfo, cert);
983         get_cert_name(cert, name, sizeof(name));
984         vpn_progress(vpninfo, PRG_INFO, _("Using client certificate '%s'\n"),
985                      name);
986
987         if (crl) {
988                 err = gnutls_certificate_set_x509_crl(vpninfo->https_cred, &crl, 1);
989                 if (err) {
990                         vpn_progress(vpninfo, PRG_ERR,
991                                      _("Setting certificate recovation list failed: %s\n"),
992                                      gnutls_strerror(err));
993                         ret = -EINVAL;
994                         goto out;
995                 }
996         }
997
998         /* OpenSSL has problems with certificate chains — if there are
999            multiple certs with the same name, it doesn't necessarily
1000            choose the _right_ one. (RT#1942)
1001            Pick the right ones for ourselves and add them manually. */
1002
1003         if (nr_supporting_certs) {
1004                 /* We already got a bunch of certs from PKCS#12 file. Remember
1005                    how many need to be freed when we're done, since we'll
1006                    expand the supporting_certs array with more from the cafile
1007                    and extra_certs[] array if we can, and those extra certs
1008                    must not be freed (twice). */
1009                 last_cert = supporting_certs[nr_supporting_certs-1];
1010                 certs_to_free = nr_supporting_certs;
1011         } else {
1012                 last_cert = cert;
1013                 certs_to_free = nr_supporting_certs = 1;
1014         }
1015         while (1) {
1016                 gnutls_x509_crt_t issuer;
1017
1018                 for (i = 0; i < nr_extra_certs; i++) {
1019                         if (gnutls_x509_crt_check_issuer(last_cert, extra_certs[i]) &&
1020                             !check_issuer_sanity(last_cert, extra_certs[i]))
1021                                 break;
1022                 }
1023
1024                 if (i < nr_extra_certs) {
1025                         /* We found the next cert in the chain in extra_certs[] */
1026                         issuer = extra_certs[i];
1027                 } else {
1028                         /* Look for it in the system trust cafile too. */
1029                         err = gnutls_certificate_get_issuer(vpninfo->https_cred,
1030                                                             last_cert, &issuer, 0);
1031                         if (err)
1032                                 break;
1033
1034                         /* The check_issuer_sanity() function works fine as a workaround where
1035                            it was used above, but when gnutls_certificate_get_issuer() returns
1036                            a bogus cert, there's nothing we can do to fix it up. We don't get
1037                            to iterate over all the available certs like we can over our own
1038                            list. */
1039                         if (check_issuer_sanity(last_cert, issuer)) {
1040                                 /* Hm, is there a bug reference for this? Or just the git commit
1041                                    reference (c1ef7efb in master, 5196786c in gnutls_3_0_x-2)? */
1042                                 vpn_progress(vpninfo, PRG_ERR,
1043                                              _("WARNING: GnuTLS returned incorrect issuer certs; authentication may fail!\n"));
1044                                 break;
1045                         }
1046                 }
1047
1048                 if (issuer == last_cert) {
1049                         /* Don't actually include the root CA. If they don't already trust it,
1050                            then handing it to them isn't going to help. But don't omit the
1051                            original certificate if it's self-signed. */
1052                         if (nr_supporting_certs > 1)
1053                                 nr_supporting_certs--;
1054                         break;
1055                 }
1056
1057                 /* OK, we found a new cert to add to our chain. */
1058                 supporting_certs = gnutls_realloc(supporting_certs,
1059                                                   sizeof(cert) * ++nr_supporting_certs);
1060                 if (!supporting_certs) {
1061                         vpn_progress(vpninfo, PRG_ERR,
1062                                      _("Failed to allocate memory for supporting certificates\n"));
1063                         /* The world is probably about to end, but try without them anyway */
1064                         certs_to_free = 0;
1065                         ret = -ENOMEM;
1066                         goto out;
1067                 }
1068
1069                 /* First time we actually allocated an array? Copy the first cert into it */
1070                 if (nr_supporting_certs == 2)
1071                         supporting_certs[0] = cert;
1072
1073                 /* Append the new one */
1074                 supporting_certs[nr_supporting_certs-1] = issuer;
1075                 last_cert = issuer;
1076         }
1077         for (i = 1; i < nr_supporting_certs; i++) {
1078                 get_cert_name(supporting_certs[i], name, sizeof(name));
1079
1080                 vpn_progress(vpninfo, PRG_DEBUG,
1081                              _("Adding supporting CA '%s'\n"), name);
1082         }
1083
1084         /* OK, now we've checked the cert expiry and warned the user if it's
1085            going to expire soon, and we've built up as much of a trust chain
1086            in supporting_certs[] as we can find, to help the server work around
1087            OpenSSL RT#1942. Set up the GnuTLS credentials with the appropriate
1088            key and certs. GnuTLS makes us do this differently for X509 privkeys
1089            vs. TPM/PKCS#11 "generic" privkeys, and the latter is particularly
1090            'fun' for GnuTLS 2.12... */
1091 #if defined (HAVE_P11KIT) || defined (HAVE_TROUSERS)
1092         if (pkey) {
1093                 err = assign_privkey(vpninfo, pkey,
1094                                      supporting_certs ? supporting_certs : &cert,
1095                                      nr_supporting_certs,
1096                                      extra_certs, nr_extra_certs);
1097                 if (!err) {
1098                         pkey = NULL; /* we gave it away, and potentially also some
1099                                         of extra_certs[] may have been zeroed. */
1100                 }
1101         } else
1102 #endif /* P11KIT || TROUSERS */
1103                 err = gnutls_certificate_set_x509_key(vpninfo->https_cred,
1104                                                       supporting_certs ? supporting_certs : &cert,
1105                                                       nr_supporting_certs, key);
1106
1107         if (err) {
1108                 vpn_progress(vpninfo, PRG_ERR,
1109                              _("Setting certificate failed: %s\n"),
1110                              gnutls_strerror(err));
1111                 ret = -EIO;
1112         } else
1113                 ret = 0;
1114  out:
1115         if (crl)
1116                 gnutls_x509_crl_deinit(crl);
1117         if (key)
1118                 gnutls_x509_privkey_deinit(key);
1119         if (supporting_certs) {
1120                 for (i = 0; i < certs_to_free; i++) {
1121                         if (supporting_certs[i])
1122                                 gnutls_x509_crt_deinit(supporting_certs[i]);
1123                 }
1124                 gnutls_free(supporting_certs);
1125         } else if (cert) {
1126                 /* Not if supporting_certs. It's supporting_certs[0] then and
1127                    was already freed. */
1128                 gnutls_x509_crt_deinit(cert);
1129         }
1130         for (i = 0; i < nr_extra_certs; i++) {
1131                 if (extra_certs[i])
1132                         gnutls_x509_crt_deinit(extra_certs[i]);
1133         }
1134         gnutls_free(extra_certs);
1135
1136 #if defined (HAVE_P11KIT) || defined (HAVE_TROUSERS)
1137         if (pkey && pkey != OPENCONNECT_TPM_PKEY)
1138                 gnutls_privkey_deinit(pkey);
1139         /* If we support arbitrary privkeys, we might have abused fdata.data
1140            just to point to something to hash. Don't free it in that case! */
1141         if (fdata.data != dummy_hash_data)
1142 #endif
1143                 gnutls_free(fdata.data);
1144
1145 #ifdef HAVE_P11KIT
1146         if (cert_url != vpninfo->cert)
1147                 free(cert_url);
1148         if (key_url != vpninfo->sslkey)
1149                 free(key_url);
1150 #endif
1151         return ret;
1152 }
1153
1154 static int get_cert_fingerprint(struct openconnect_info *vpninfo,
1155                                 gnutls_x509_crt_t cert,
1156                                 gnutls_digest_algorithm_t algo,
1157                                 char *buf)
1158 {
1159         unsigned char md[256];
1160         size_t md_size = sizeof(md);
1161         unsigned int i;
1162
1163         if (gnutls_x509_crt_get_fingerprint(cert, algo, md, &md_size))
1164                 return -EIO;
1165
1166         for (i=0; i < md_size; i++)
1167                 sprintf(&buf[i*2], "%02X", md[i]);
1168
1169         return 0;
1170 }
1171
1172 int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
1173                              OPENCONNECT_X509 *cert, char *buf)
1174 {
1175         return get_cert_fingerprint(vpninfo, cert, GNUTLS_DIG_MD5, buf);
1176 }
1177
1178 int openconnect_get_cert_sha1(struct openconnect_info *vpninfo,
1179                               OPENCONNECT_X509 *cert, char *buf)
1180 {
1181         return get_cert_fingerprint(vpninfo, cert, GNUTLS_DIG_SHA1, buf);
1182 }
1183
1184 char *openconnect_get_cert_details(struct openconnect_info *vpninfo,
1185                                    OPENCONNECT_X509 *cert)
1186 {
1187         gnutls_datum_t buf;
1188         char *ret;
1189
1190         if (gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL, &buf))
1191                 return NULL;
1192         
1193         /* Just in case gnutls_free() isn't free(), we can't steal it. */
1194         ret = strdup((char *)buf.data);
1195         gnutls_free(buf.data);
1196         
1197         return ret;
1198 }
1199
1200 int openconnect_get_cert_DER(struct openconnect_info *vpninfo,
1201                              OPENCONNECT_X509 *cert, unsigned char **buf)
1202 {
1203         size_t l = 0;
1204         unsigned char *ret = NULL;
1205
1206         if (gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, ret, &l) != 
1207             GNUTLS_E_SHORT_MEMORY_BUFFER)
1208                 return -EIO;
1209
1210         ret = malloc(l);
1211         if (!ret)
1212                 return -ENOMEM;
1213
1214         if (gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, ret, &l)) {
1215                 free(ret);
1216                 return -EIO;
1217         }
1218         *buf = ret;
1219         return l;
1220 }
1221
1222 static int verify_peer(gnutls_session_t session)
1223 {
1224         struct openconnect_info *vpninfo = gnutls_session_get_ptr(session);
1225         const gnutls_datum_t *cert_list;
1226         gnutls_x509_crt_t cert;
1227         unsigned int status, cert_list_size;
1228         const char *reason = NULL;
1229         int err;
1230
1231         if (vpninfo->peer_cert) {
1232                 gnutls_x509_crt_deinit(vpninfo->peer_cert);
1233                 vpninfo->peer_cert = NULL;
1234         }
1235
1236         cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
1237         if (!cert_list) {
1238                 vpn_progress(vpninfo, PRG_ERR, _("Server presented no certificate\n"));
1239                 return GNUTLS_E_CERTIFICATE_ERROR;
1240         }
1241
1242         if (vpninfo->servercert) {
1243                 unsigned char sha1bin[SHA1_SIZE];
1244                 char fingerprint[(SHA1_SIZE * 2) + 1];
1245                 int i;
1246                 
1247                 err = openconnect_sha1(sha1bin, cert_list[0].data, cert_list[0].size);
1248                 if (err) {
1249                         vpn_progress(vpninfo, PRG_ERR,
1250                                      _("Could not calculate SHA1 of server's certificate\n"));
1251                         return GNUTLS_E_CERTIFICATE_ERROR;
1252                 }
1253                 for (i=0; i < SHA1_SIZE; i++)
1254                         sprintf(&fingerprint[i*2], "%02X", sha1bin[i]);
1255
1256                 if (strcasecmp(vpninfo->servercert, fingerprint)) {
1257                         vpn_progress(vpninfo, PRG_ERR,
1258                                      _("Server SSL certificate didn't match: %s\n"), fingerprint);
1259                         return GNUTLS_E_CERTIFICATE_ERROR;
1260                 }
1261                 return 0;
1262         }
1263
1264         err = gnutls_certificate_verify_peers2 (session, &status);
1265         if (err) {
1266                 vpn_progress(vpninfo, PRG_ERR, _("Error checking server cert status\n"));
1267                 return GNUTLS_E_CERTIFICATE_ERROR;
1268         }
1269
1270         if (status & GNUTLS_CERT_REVOKED)
1271                 reason = _("certificate revoked");
1272         else if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
1273                 reason = _("signer not found");
1274         else if (status & GNUTLS_CERT_SIGNER_NOT_CA)
1275                 reason = _("signer not a CA certificate");
1276         else if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
1277                 reason = _("insecure algorithm");
1278         else if (status & GNUTLS_CERT_NOT_ACTIVATED)
1279                 reason = _("certificate not yet activated");
1280         else if (status & GNUTLS_CERT_EXPIRED)
1281                 reason = _("certificate expired");
1282         else if (status & GNUTLS_CERT_INVALID)
1283                 /* If this is set and no other reason, it apparently means
1284                    that signature verification failed. Not entirely sure
1285                    why we don't just set a bit for that too. */
1286                 reason = _("signature verification failed");
1287
1288         err = gnutls_x509_crt_init(&cert);
1289         if (err) {
1290                 vpn_progress(vpninfo, PRG_ERR, _("Error initialising X509 cert structure\n"));
1291                 return GNUTLS_E_CERTIFICATE_ERROR;
1292         }
1293
1294         err = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
1295         if (err) {
1296                 vpn_progress(vpninfo, PRG_ERR, _("Error importing server's cert\n"));
1297                 gnutls_x509_crt_deinit(cert);
1298                 return GNUTLS_E_CERTIFICATE_ERROR;
1299         }
1300
1301         if (!reason && !gnutls_x509_crt_check_hostname(cert, vpninfo->hostname))
1302                 reason = _("certificate does not match hostname");
1303
1304         if (reason) {
1305                 vpn_progress(vpninfo, PRG_INFO, "Server certificate verify failed: %s\n",
1306                              reason);
1307                 if (vpninfo->validate_peer_cert)
1308                         err = vpninfo->validate_peer_cert(vpninfo->cbdata,
1309                                                           cert,
1310                                                           reason) ? GNUTLS_E_CERTIFICATE_ERROR : 0;
1311                 else
1312                         err = GNUTLS_E_CERTIFICATE_ERROR;
1313         }
1314
1315         vpninfo->peer_cert = cert;
1316
1317         return err;
1318 }
1319
1320
1321 int openconnect_open_https(struct openconnect_info *vpninfo)
1322 {
1323         int ssl_sock = -1;
1324         int err;
1325
1326         if (vpninfo->https_sess)
1327                 return 0;
1328
1329         ssl_sock = connect_https_socket(vpninfo);
1330         if (ssl_sock < 0)
1331                 return ssl_sock;
1332
1333         if (!vpninfo->https_cred) {
1334                 gnutls_certificate_allocate_credentials(&vpninfo->https_cred);
1335 #ifdef HAVE_GNUTLS_CERTIFICATE_SET_X509_SYSTEM_TRUST
1336                 gnutls_certificate_set_x509_system_trust(vpninfo->https_cred);
1337 #else
1338                 gnutls_certificate_set_x509_trust_file(vpninfo->https_cred,
1339                                                        "/etc/pki/tls/certs/ca-bundle.crt",
1340                                                        GNUTLS_X509_FMT_PEM);
1341 #endif
1342                 gnutls_certificate_set_verify_function (vpninfo->https_cred,
1343                                                         verify_peer);
1344
1345                 if (vpninfo->cafile) {
1346                         err = gnutls_certificate_set_x509_trust_file(vpninfo->https_cred,
1347                                                                      vpninfo->cafile,
1348                                                                      GNUTLS_X509_FMT_PEM);
1349                         if (err < 0) {
1350                                 vpn_progress(vpninfo, PRG_ERR,
1351                                              _("Failed to open CA file '%s': %s\n"),
1352                                              vpninfo->cafile, gnutls_strerror(err));
1353                                 close(ssl_sock);
1354                                 return -EINVAL;
1355                         }
1356                 }
1357
1358                 if (vpninfo->cert) {
1359                         err = load_certificate(vpninfo);
1360                         if (err) {
1361                                 vpn_progress(vpninfo, PRG_ERR,
1362                                              _("Loading certificate failed. Aborting.\n"));
1363                                 return err;
1364                         }
1365                 }
1366         }
1367         gnutls_init (&vpninfo->https_sess, GNUTLS_CLIENT);
1368         gnutls_session_set_ptr (vpninfo->https_sess, (void *) vpninfo);
1369 #if defined(HAVE_TROUSERS) && !defined(HAVE_GNUTLS_CERTIFICATE_SET_KEY)
1370         if (vpninfo->my_pkey == OPENCONNECT_TPM_PKEY)
1371                 gnutls_sign_callback_set(vpninfo->https_sess, gtls2_tpm_sign_cb, vpninfo);
1372 #endif
1373         err = gnutls_priority_set_direct (vpninfo->https_sess, "NONE:+VERS-TLS1.0:+SHA1:+AES-128-CBC:+RSA:+COMP-NULL:%COMPAT:%DISABLE_SAFE_RENEGOTIATION", NULL);
1374         if (err) {
1375                 vpn_progress(vpninfo, PRG_ERR,
1376                              _("Failed to set TLS priority string: %s\n"),
1377                              gnutls_strerror(err));
1378                 return -EIO;
1379         }
1380
1381         gnutls_record_disable_padding (vpninfo->https_sess);
1382         gnutls_credentials_set (vpninfo->https_sess, GNUTLS_CRD_CERTIFICATE, vpninfo->https_cred);
1383         gnutls_transport_set_ptr(vpninfo->https_sess, /* really? */(gnutls_transport_ptr_t)(long) ssl_sock);
1384
1385         vpn_progress(vpninfo, PRG_INFO, _("SSL negotiation with %s\n"),
1386                      vpninfo->hostname);
1387
1388         while ((err = gnutls_handshake (vpninfo->https_sess))) {
1389                 if (err == GNUTLS_E_AGAIN) {
1390                         fd_set rd_set, wr_set;
1391                         int maxfd = ssl_sock;
1392
1393                         FD_ZERO(&rd_set);
1394                         FD_ZERO(&wr_set);
1395
1396                         if (gnutls_record_get_direction(vpninfo->https_sess))
1397                                 FD_SET(ssl_sock, &wr_set);
1398                         else
1399                                 FD_SET(ssl_sock, &rd_set);
1400
1401                         if (vpninfo->cancel_fd != -1) {
1402                                 FD_SET(vpninfo->cancel_fd, &rd_set);
1403                                 if (vpninfo->cancel_fd > ssl_sock)
1404                                         maxfd = vpninfo->cancel_fd;
1405                         }
1406                         select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
1407                         if (vpninfo->cancel_fd != -1 &&
1408                             FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
1409                                 vpn_progress(vpninfo, PRG_ERR, _("SSL connection cancelled\n"));
1410                                 gnutls_deinit(vpninfo->https_sess);
1411                                 vpninfo->https_sess = NULL;
1412                                 close(ssl_sock);
1413                                 return -EINTR;
1414                         }
1415                 } else if (err == GNUTLS_E_INTERRUPTED || gnutls_error_is_fatal(err)) {
1416                         vpn_progress(vpninfo, PRG_ERR, _("SSL connection failure: %s\n"),
1417                                                          gnutls_strerror(err));
1418                         gnutls_deinit(vpninfo->https_sess);
1419                         vpninfo->https_sess = NULL;
1420                         close(ssl_sock);
1421                         return -EIO;
1422                 } else {
1423                         /* non-fatal error or warning. Ignore it and continue */
1424                         vpn_progress(vpninfo, PRG_TRACE,
1425                                      _("GnuTLS non-fatal return during handshake: %s\n"),
1426                                      gnutls_strerror(err));
1427                 }
1428         }
1429
1430         vpninfo->ssl_fd = ssl_sock;
1431
1432         vpn_progress(vpninfo, PRG_INFO, _("Connected to HTTPS on %s\n"),
1433                      vpninfo->hostname);
1434
1435         return 0;
1436 }
1437
1438 void openconnect_close_https(struct openconnect_info *vpninfo, int final)
1439 {
1440         if (vpninfo->peer_cert) {
1441                 gnutls_x509_crt_deinit(vpninfo->peer_cert);
1442                 vpninfo->peer_cert = NULL;
1443         }
1444         if (vpninfo->https_sess) {
1445                 gnutls_deinit(vpninfo->https_sess);
1446                 vpninfo->https_sess = NULL;
1447         }
1448         if (vpninfo->ssl_fd != -1) {
1449                 close(vpninfo->ssl_fd);
1450                 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds);
1451                 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
1452                 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds);
1453                 vpninfo->ssl_fd = -1;
1454         }
1455         if (final && vpninfo->https_cred) {
1456                 gnutls_certificate_free_credentials(vpninfo->https_cred);
1457                 vpninfo->https_cred = NULL;
1458 #ifdef HAVE_P11KIT
1459                 if (!strncmp(vpninfo->cert, "pkcs11:", 7) ||
1460                     !strncmp(vpninfo->sslkey, "pkcs11:", 7)) {
1461                         char pin_source[40];
1462
1463                         sprintf(pin_source, "openconnect:%p", vpninfo);
1464                         p11_kit_pin_unregister_callback(pin_source, pin_callback, vpninfo);
1465
1466                         while (vpninfo->pin_cache) {
1467                                 struct pin_cache *cache = vpninfo->pin_cache;
1468
1469                                 free(cache->token);
1470                                 memset(cache->pin, 0x5a, strlen(cache->pin));
1471                                 free(cache->pin);
1472                                 vpninfo->pin_cache = cache->next;
1473                                 free(cache);
1474                         }
1475                 }
1476 #endif
1477 #ifdef HAVE_TROUSERS
1478                 if (vpninfo->tpm_key_policy) {
1479                         Tspi_Context_CloseObject(vpninfo->tpm_context, vpninfo->tpm_key_policy);
1480                         vpninfo->tpm_key = 0;
1481                 }
1482                 if (vpninfo->tpm_key) {
1483                         Tspi_Context_CloseObject(vpninfo->tpm_context, vpninfo->tpm_key);
1484                         vpninfo->tpm_key = 0;
1485                 }
1486                 if (vpninfo->srk_policy) {
1487                         Tspi_Context_CloseObject(vpninfo->tpm_context, vpninfo->srk_policy);
1488                         vpninfo->srk_policy = 0;
1489                 }
1490                 if (vpninfo->srk) {
1491                         Tspi_Context_CloseObject(vpninfo->tpm_context, vpninfo->srk);
1492                         vpninfo->srk = 0;
1493                 }
1494                 if (vpninfo->tpm_context) {
1495                         Tspi_Context_Close(vpninfo->tpm_context);
1496                         vpninfo->tpm_context = 0;
1497                 }
1498 #endif
1499 #ifndef HAVE_GNUTLS_CERTIFICATE_SET_KEY
1500                 if (vpninfo->my_pkey && vpninfo->my_pkey != OPENCONNECT_TPM_PKEY) {
1501                         gnutls_privkey_deinit(vpninfo->my_pkey);
1502                         vpninfo->my_pkey = NULL;
1503                         /* my_p11key went with it */
1504                 }
1505                 if (vpninfo->my_certs) {
1506                         int i;
1507                         for (i = 0; i < vpninfo->nr_my_certs; i++)
1508                                 gnutls_x509_crt_deinit(vpninfo->my_certs[i]);
1509                         free(vpninfo->my_certs);
1510                         vpninfo->my_certs = NULL;
1511                 }
1512 #endif
1513         }
1514 }
1515
1516 void openconnect_init_ssl(void)
1517 {
1518         gnutls_global_init();
1519 }
1520
1521 int openconnect_sha1(unsigned char *result, void *data, int datalen)
1522 {
1523         gnutls_datum_t d;
1524         size_t shalen = SHA1_SIZE;
1525
1526         d.data = data;
1527         d.size = datalen;
1528         if (gnutls_fingerprint(GNUTLS_DIG_SHA1, &d, result, &shalen))
1529                 return -1;
1530
1531         return 0;
1532 }
1533
1534 int openconnect_random(void *bytes, int len)
1535 {
1536         if (gnutls_rnd(GNUTLS_RND_RANDOM, bytes, len))
1537                 return -EIO;
1538         return 0;
1539 }
1540
1541 int openconnect_local_cert_md5(struct openconnect_info *vpninfo,
1542                                char *buf)
1543 {
1544         const gnutls_datum_t *d;
1545         size_t md5len = 16;
1546
1547         buf[0] = 0;
1548
1549         d = gnutls_certificate_get_ours(vpninfo->https_sess);
1550         if (!d)
1551                 return -EIO;
1552
1553         if (gnutls_fingerprint(GNUTLS_DIG_MD5, d, buf, &md5len))
1554                 return -EIO;
1555
1556         return 0;
1557 }
1558
1559 #ifdef HAVE_P11KIT
1560 static P11KitPin *pin_callback(const char *pin_source, P11KitUri *pin_uri,
1561                         const char *pin_description,
1562                         P11KitPinFlags flags,
1563                         void *_vpninfo)
1564 {
1565         struct openconnect_info *vpninfo = _vpninfo;
1566         struct pin_cache **cache = &vpninfo->pin_cache;
1567         struct oc_auth_form f;
1568         struct oc_form_opt o;
1569         char message[1024];
1570         char *uri;
1571         P11KitPin *pin;
1572         int ret;
1573
1574         if (!vpninfo || !vpninfo->process_auth_form)
1575                 return NULL;
1576
1577         if (p11_kit_uri_format(pin_uri, P11_KIT_URI_FOR_TOKEN, &uri))
1578                 return NULL;
1579         
1580         while (*cache) {
1581                 if (!strcmp(uri, (*cache)->token)) {
1582                         free(uri);
1583                         uri = NULL;
1584                         if ((*cache)->pin) {
1585                                 if ((flags & P11_KIT_PIN_FLAGS_RETRY) != P11_KIT_PIN_FLAGS_RETRY)
1586                                         return p11_kit_pin_new_for_string((*cache)->pin);
1587                                 memset((*cache)->pin, 0x5a, strlen((*cache)->pin));
1588                                 free((*cache)->pin);
1589                                 (*cache)->pin = NULL;
1590                         }
1591                         break;
1592                 }
1593         }
1594         if (!*cache) {
1595                 *cache = calloc(1, sizeof(struct pin_cache));
1596                 if (!*cache) {
1597                         free(uri);
1598                         return NULL;
1599                 }
1600                 (*cache)->token = uri;
1601         }
1602
1603         memset(&f, 0, sizeof(f));
1604         f.auth_id = (char *)"pkcs11_pin";
1605         f.opts = &o;
1606
1607         message[sizeof(message)-1] = 0;
1608         snprintf(message, sizeof(message) - 1, _("PIN required for %s"), pin_description);
1609         f.message = message;
1610         
1611         /* 
1612          * In p11-kit <= 0.12, these flags are *odd*.
1613          * RETRY is 0xa, FINAL_TRY is 0x14 and MANY_TRIES is 0x28.
1614          * So don't treat it like a sane bitmask. Fixed in
1615          * http://cgit.freedesktop.org/p11-glue/p11-kit/commit/?id=59774b11
1616          */
1617         if ((flags & P11_KIT_PIN_FLAGS_RETRY) == P11_KIT_PIN_FLAGS_RETRY)
1618                 f.error = (char *)_("Wrong PIN");
1619
1620         if ((flags & P11_KIT_PIN_FLAGS_FINAL_TRY) == P11_KIT_PIN_FLAGS_FINAL_TRY)
1621                 f.banner = (char *)_("This is the final try before locking!");
1622         else if ((flags & P11_KIT_PIN_FLAGS_MANY_TRIES) == P11_KIT_PIN_FLAGS_MANY_TRIES)
1623                 f.banner = (char *)_("Only a few tries left before locking!");
1624
1625         o.next = NULL;
1626         o.type = OC_FORM_OPT_PASSWORD;
1627         o.name = (char *)"pkcs11_pin";
1628         o.label = (char *)_("Enter PIN:");
1629         o.value = NULL;
1630
1631         ret = vpninfo->process_auth_form(vpninfo->cbdata, &f);
1632         if (ret || !o.value)
1633                 return NULL;
1634
1635         pin = p11_kit_pin_new_for_string(o.value);
1636         (*cache)->pin = o.value;
1637
1638         return pin;
1639 }
1640 #endif