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