2 * OpenConnect (SSL + DTLS) VPN client
4 * Copyright © 2008-2012 Intel Corporation.
6 * Author: David Woodhouse <dwmw2@infradead.org>
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.
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.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to:
20 * Free Software Foundation, Inc.
21 * 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301 USA
25 #include <sys/types.h>
27 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
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
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>
53 #include <trousers/tss.h>
54 #include <trousers/trousers.h>
57 #include <p11-kit/p11-kit.h>
58 #include <p11-kit/pkcs11.h>
59 #include <p11-kit/pin.h>
61 static P11KitPin *pin_callback(const char *pin_source, P11KitUri *pin_uri,
62 const char *pin_description,
68 #include "openconnect-internal.h"
70 /* Helper functions for reading/writing lines over SSL.
71 We could use cURL for the HTTP stuff, but it's overkill */
73 int openconnect_SSL_write(struct openconnect_info *vpninfo, char *buf, size_t len)
75 size_t orig_len = len;
78 int done = gnutls_record_send(vpninfo->https_sess, buf, len);
81 else if (done != GNUTLS_E_AGAIN) {
82 vpn_progress(vpninfo, PRG_ERR, _("Failed to write to SSL socket: %s"),
83 gnutls_strerror(done));
86 fd_set wr_set, rd_set;
87 int maxfd = vpninfo->ssl_fd;
92 if (gnutls_record_get_direction(vpninfo->https_sess))
93 FD_SET(vpninfo->ssl_fd, &wr_set);
95 FD_SET(vpninfo->ssl_fd, &rd_set);
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;
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"));
113 int openconnect_SSL_read(struct openconnect_info *vpninfo, char *buf, size_t len)
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;
121 if (done != GNUTLS_E_AGAIN) {
122 vpn_progress(vpninfo, PRG_ERR, _("Failed to read from SSL socket: %s"),
123 gnutls_strerror(done));
129 if (gnutls_record_get_direction(vpninfo->https_sess))
130 FD_SET(vpninfo->ssl_fd, &wr_set);
132 FD_SET(vpninfo->ssl_fd, &rd_set);
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;
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"));
150 int openconnect_SSL_gets(struct openconnect_info *vpninfo, char *buf, size_t len)
159 ret = gnutls_record_recv(vpninfo->https_sess, buf + i, 1);
161 if (buf[i] == '\n') {
163 if (i && buf[i-1] == '\r') {
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));
181 fd_set rd_set, wr_set;
182 int maxfd = vpninfo->ssl_fd;
187 if (gnutls_record_get_direction(vpninfo->https_sess))
188 FD_SET(vpninfo->ssl_fd, &wr_set);
190 FD_SET(vpninfo->ssl_fd, &rd_set);
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;
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"));
210 static int check_certificate_expiry(struct openconnect_info *vpninfo, gnutls_x509_crt_t cert)
212 const char *reason = NULL;
213 time_t expires = gnutls_x509_crt_get_expiration_time(cert);
214 time_t now = time(NULL);
217 vpn_progress(vpninfo, PRG_ERR,
218 _("Could not extract expiration time of certificate\n"));
223 reason = _("Client certificate has expired at");
224 else if (expires < now + vpninfo->cert_expire_warning)
225 reason = _("Client certificate expires soon at");
231 gmtime_r(&expires, &tm);
232 strftime(buf, 80, "%a, %d %b %Y %T %Z", &tm);
234 vpn_progress(vpninfo, PRG_ERR, "%s: %s\n", reason, buf);
239 /* For systems that don't support O_CLOEXEC, just don't bother.
240 It's not open for long anyway. */
245 static int load_datum(struct openconnect_info *vpninfo,
246 gnutls_datum_t *datum, const char *fname)
251 fd = open(fname, O_RDONLY|O_CLOEXEC);
254 vpn_progress(vpninfo, PRG_ERR,
255 _("Failed to open key/certificate file %s: %s\n"),
256 fname, strerror(err));
259 if (fstat(fd, &st)) {
261 vpn_progress(vpninfo, PRG_ERR,
262 _("Failed to stat key/certificate file %s: %s\n"),
263 fname, strerror(err));
267 datum->size = st.st_size;
268 datum->data = gnutls_malloc(st.st_size + 1);
270 vpn_progress(vpninfo, PRG_ERR,
271 _("Failed to allocate certificate buffer\n"));
276 if (read(fd, datum->data, datum->size) != datum->size) {
278 vpn_progress(vpninfo, PRG_ERR,
279 _("Failed to read certificate into memory: %s\n"),
282 gnutls_free(datum->data);
285 datum->data[st.st_size] = 0;
290 /* A non-zero, non-error return to make load_certificate() continue and
291 interpreting the file as other types */
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)
307 err = gnutls_pkcs12_init(&p12);
309 vpn_progress(vpninfo, PRG_ERR,
310 _("Failed to setup PKCS#12 data structure: %s\n"),
311 gnutls_strerror(err));
315 err = gnutls_pkcs12_import(p12, datum, GNUTLS_X509_FMT_DER, 0);
317 gnutls_pkcs12_deinit(p12);
318 if (vpninfo->cert_type == CERT_TYPE_UNKNOWN)
320 vpn_progress(vpninfo, PRG_ERR,
321 _("Failed to import PKCS#12 file: %s\n"),
322 gnutls_strerror(err));
326 pass = vpninfo->cert_password;
327 while ((err = gnutls_pkcs12_verify_mac(p12, pass)) == GNUTLS_E_MAC_VERIFY_FAILED) {
329 vpn_progress(vpninfo, PRG_ERR,
330 _("Failed to decrypt PKCS#12 certificate file\n"));
332 vpninfo->cert_password = NULL;
333 err = request_passphrase(vpninfo, "openconnect_pkcs12", &pass,
334 _("Enter PKCS#12 pass phrase:"));
336 gnutls_pkcs12_deinit(p12);
340 /* If it wasn't GNUTLS_E_MAC_VERIFY_FAILED, then the problem wasn't just a
341 bad password. Give up. */
346 gnutls_pkcs12_deinit(p12);
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... */
357 vpn_progress(vpninfo, level,
358 _("Failed to process PKCS#12 file: %s\n"),
359 gnutls_strerror(err));
362 err = gnutls_pkcs12_simple_parse(p12, pass, key, chain, chain_len,
363 extra_certs, extra_certs_len, crl, 0);
365 vpninfo->cert_password = NULL;
367 gnutls_pkcs12_deinit(p12);
369 vpn_progress(vpninfo, PRG_ERR,
370 _("Failed to load PKCS#12 certificate: %s\n"),
371 gnutls_strerror(err));
377 /* Older versions of GnuTLS didn't actually bother to check this, so we'll
379 static int check_issuer_sanity(gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer)
381 #if GNUTLS_VERSION_NUMBER > 0x300014
384 unsigned char id1[512], id2[512];
385 size_t id1_size = 512, id2_size = 512;
388 err = gnutls_x509_crt_get_authority_key_id(cert, id1, &id1_size, NULL);
392 err = gnutls_x509_crt_get_subject_key_id(issuer, id2, &id2_size, NULL);
395 if (id1_size == id2_size && !memcmp(id1, id2, id1_size))
403 static int count_x509_certificates(gnutls_datum_t *datum)
406 char *p = (char *)datum->data;
409 p = strstr(p, "-----BEGIN ");
413 if (!strncmp(p, "CERTIFICATE", 11) ||
414 !strncmp(p, "X509 CERTIFICATE", 16))
420 static int get_cert_name(gnutls_x509_crt_t cert, char *name, size_t namelen)
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)) {
426 snprintf(name, namelen-1, "<unknown>");
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
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) {
444 struct openconnect_info *vpninfo = gnutls_session_get_ptr(sess);
445 int algo = GNUTLS_PK_RSA; /* TPM */
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);
455 for (i = 0; i < pk_algos_length; i++) {
456 if (algo == pk_algos[i])
459 if (i == pk_algos_length)
460 return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
462 st->cert_type = GNUTLS_CRT_X509;
463 st->cert.x509 = vpninfo->my_certs;
464 st->ncerts = vpninfo->nr_my_certs;
470 static int assign_privkey_gtls2(struct openconnect_info *vpninfo,
471 gnutls_privkey_t pkey,
472 gnutls_x509_crt_t *certs,
473 unsigned int nr_certs,
474 gnutls_x509_crt_t *extra_certs,
475 unsigned int nr_extra_certs)
479 vpninfo->my_certs = gnutls_calloc(nr_certs, sizeof(*certs));
480 if (!vpninfo->my_certs)
481 return GNUTLS_E_MEMORY_ERROR;
483 memcpy(vpninfo->my_certs, certs, nr_certs * sizeof(*certs));
484 vpninfo->nr_my_certs = nr_certs;
486 /* We are *keeping* the certs, unlike in GnuTLS 3 where we can
487 free them after calling gnutls_certificate_set_key(). So
488 first wipe the 'certs' array (which is either '&cert' or
489 'supporting_certs' in load_certificate())... */
490 memset(certs, 0, nr_certs * sizeof(*certs));
492 /* ... and then also zero out the entries in the extra_certs
493 array that correspond to certs that were added into the
494 supporting_certs array (but above the certs_to_free index).
496 The first one is 'cert', which was already stolen by the
497 load_certificate() function and put into our certs[0]..
499 for (i = 1; i < nr_certs; i++) {
501 for (j = 0; j < nr_extra_certs; j++) {
502 if (vpninfo->my_certs[i] == extra_certs[j]) {
503 extra_certs[j] = NULL;
509 gnutls_certificate_set_retrieve_function(vpninfo->https_cred,
511 vpninfo->my_pkey = pkey;
516 static int assign_privkey_gtls3(struct openconnect_info *vpninfo,
517 gnutls_privkey_t pkey,
518 gnutls_x509_crt_t *certs,
519 unsigned int nr_certs)
521 /* Ug. If we got a gnutls_privkey_t from PKCS#11 rather than the
522 gnutls_x509_privkey_t that we get from PEM or PKCS#12 files, then
523 we can't use gnutls_certificate_set_x509_key(). Instead we have
524 to convert our chain of X509 certificates to gnutls_pcert_st and
525 then use gnutls_certificate_set_key() with that instead. */
526 gnutls_pcert_st *pcerts = calloc(nr_certs, sizeof(*pcerts));
530 return GNUTLS_E_MEMORY_ERROR;
532 for (i=0 ; i < nr_certs; i++) {
533 err = gnutls_pcert_import_x509(pcerts + i, certs[i], 0);
535 vpn_progress(vpninfo, PRG_ERR,
536 _("Importing X509 certificate failed: %s\n"),
537 gnutls_strerror(err));
542 err = gnutls_certificate_set_key(vpninfo->https_cred, NULL, 0,
543 pcerts, nr_certs, pkey);
545 vpn_progress(vpninfo, PRG_ERR,
546 _("Setting PKCS#11 certificate failed: %s\n"),
547 gnutls_strerror(err));
549 for (i=0 ; i < nr_certs; i++)
550 gnutls_pcert_deinit(pcerts + i);
555 #endif /* !SET_KEY */
556 #endif /* (P11KIT || TROUSERS) */
558 static int load_certificate(struct openconnect_info *vpninfo)
560 gnutls_datum_t fdata;
561 gnutls_x509_privkey_t key = NULL;
562 #if defined (HAVE_P11KIT) || defined (HAVE_TROUSERS)
563 gnutls_privkey_t pkey = NULL;
564 gnutls_datum_t pkey_sig = {NULL, 0};
565 void *dummy_hash_data = &load_certificate;
568 char *cert_url = (char *)vpninfo->cert;
569 char *key_url = (char *)vpninfo->sslkey;
570 gnutls_pkcs11_privkey_t p11key = NULL;
572 gnutls_x509_crl_t crl = NULL;
573 gnutls_x509_crt_t last_cert, cert = NULL;
574 gnutls_x509_crt_t *extra_certs = NULL, *supporting_certs = NULL;
575 unsigned int nr_supporting_certs = 0, nr_extra_certs = 0;
576 unsigned int certs_to_free = 0; /* How many of supporting_certs */
577 int err; /* GnuTLS error */
580 int cert_is_p11 = 0, key_is_p11 = 0;
581 unsigned char key_id[20];
582 size_t key_id_size = sizeof(key_id);
587 key_is_p11 = !strncmp(vpninfo->sslkey, "pkcs11:", 7);
588 cert_is_p11 = !strncmp(vpninfo->cert, "pkcs11:", 7);
590 /* Install PIN handler if either certificate or key are coming from PKCS#11 */
591 if (key_is_p11 || cert_is_p11) {
593 CK_OBJECT_CLASS class;
598 sprintf(pin_source, "openconnect:%p", vpninfo);
599 p11_kit_pin_register_callback(pin_source, pin_callback, vpninfo, NULL);
601 uri = p11_kit_uri_new();
603 attr.type = CKA_CLASS;
604 attr.pValue = &class;
605 attr.ulValueLen = sizeof(class);
607 /* Add appropriate pin-source and object-type attributes to
608 both certificate and key URLs, unless they already exist. */
610 !p11_kit_uri_parse(cert_url, P11_KIT_URI_FOR_OBJECT, uri)) {
611 if (!p11_kit_uri_get_pin_source(uri))
612 p11_kit_uri_set_pin_source(uri, pin_source);
613 if (!p11_kit_uri_get_attribute(uri, CKA_CLASS)) {
614 class = CKO_CERTIFICATE;
615 p11_kit_uri_set_attribute(uri, &attr);
617 p11_kit_uri_format(uri, P11_KIT_URI_FOR_OBJECT, &cert_url);
621 !p11_kit_uri_parse(key_url, P11_KIT_URI_FOR_OBJECT, uri)) {
622 if (!p11_kit_uri_get_pin_source(uri))
623 p11_kit_uri_set_pin_source(uri, pin_source);
624 if (!p11_kit_uri_get_attribute(uri, CKA_CLASS)) {
625 class = CKO_PRIVATE_KEY;
626 p11_kit_uri_set_attribute(uri, &attr);
628 p11_kit_uri_format(uri, P11_KIT_URI_FOR_OBJECT, &key_url);
631 p11_kit_uri_free(uri);
633 vpn_progress(vpninfo, PRG_ERR,
634 _("This binary built without PKCS#11 support\n"));
639 /* Load certificate(s) first... */
642 vpn_progress(vpninfo, PRG_TRACE,
643 _("Using PKCS#11 certificate %s\n"), cert_url);
645 err = gnutls_x509_crt_init(&cert);
650 err = gnutls_x509_crt_import_pkcs11_url(cert, cert_url, 0);
651 if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
652 err = gnutls_x509_crt_import_pkcs11_url(cert, cert_url,
653 GNUTLS_PKCS11_OBJ_FLAG_LOGIN);
655 vpn_progress(vpninfo, PRG_ERR,
656 _("Error loading certificate from PKCS#11: %s\n"),
657 gnutls_strerror(err));
663 #endif /* HAVE_P11KIT */
665 vpn_progress(vpninfo, PRG_TRACE,
666 _("Using certificate file %s\n"), vpninfo->cert);
668 ret = load_datum(vpninfo, &fdata, vpninfo->cert);
672 if (!key_is_p11 && (vpninfo->cert_type == CERT_TYPE_PKCS12 ||
673 vpninfo->cert_type == CERT_TYPE_UNKNOWN)) {
674 /* PKCS#12 should actually contain certificates *and* private key */
675 ret = load_pkcs12_certificate(vpninfo, &fdata, &key,
676 &supporting_certs, &nr_supporting_certs,
677 &extra_certs, &nr_extra_certs,
682 if (nr_supporting_certs) {
683 cert = supporting_certs[0];
686 vpn_progress(vpninfo, PRG_ERR,
687 _("PKCS#11 file contained no certificate\n"));
692 /* It returned NOT_PKCS12.
693 Fall through to try PEM formats. */
696 /* We need to know how many there are in *advance*; it won't just allocate
697 the array for us :( */
698 nr_extra_certs = count_x509_certificates(&fdata);
700 nr_extra_certs = 1; /* wtf? Oh well, we'll fail later... */
702 extra_certs = calloc(nr_extra_certs, sizeof(cert));
708 err = gnutls_x509_crt_list_import(extra_certs, &nr_extra_certs, &fdata,
709 GNUTLS_X509_FMT_PEM, 0);
712 if (!err || err == GNUTLS_E_NO_CERTIFICATE_FOUND)
713 reason = _("No certificate found in file");
715 reason = gnutls_strerror(err);
717 vpn_progress(vpninfo, PRG_ERR,
718 _("Loading certificate failed: %s\n"),
723 nr_extra_certs = err;
728 /* Now we have the certificate(s) and we're looking for the private key... */
729 #if defined (HAVE_P11KIT)
731 vpn_progress(vpninfo, PRG_TRACE,
732 _("Using PKCS#11 key %s\n"), key_url);
734 err = gnutls_pkcs11_privkey_init(&p11key);
736 vpn_progress(vpninfo, PRG_ERR,
737 _("Error initialising PKCS#11 key structure: %s\n"),
738 gnutls_strerror(err));
743 err = gnutls_pkcs11_privkey_import_url(p11key, key_url, 0);
745 vpn_progress(vpninfo, PRG_ERR,
746 _("Error importing PKCS#11 URL %s: %s\n"),
747 key_url, gnutls_strerror(err));
748 gnutls_pkcs11_privkey_deinit(p11key);
753 err = gnutls_privkey_init(&pkey);
755 vpn_progress(vpninfo, PRG_ERR,
756 _("Error initialising private key structure: %s\n"),
757 gnutls_strerror(err));
758 gnutls_pkcs11_privkey_deinit(p11key);
763 err = gnutls_privkey_import_pkcs11(pkey, p11key, GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE);
765 vpn_progress(vpninfo, PRG_ERR,
766 _("Error importing PKCS#11 key into private key structure: %s\n"),
767 gnutls_strerror(err));
768 gnutls_pkcs11_privkey_deinit(p11key);
777 /* We're loading the private key from a file. Load the file into memory
778 unless it's the same as the certificate and we already loaded that. */
779 if (!fdata.data || vpninfo->sslkey != vpninfo->cert) {
780 gnutls_free(fdata.data);
783 vpn_progress(vpninfo, PRG_TRACE,
784 _("Using private key file %s\n"), vpninfo->sslkey);
786 ret = load_datum(vpninfo, &fdata, vpninfo->sslkey);
791 if (vpninfo->cert_type == CERT_TYPE_TPM ||
792 (vpninfo->cert_type == CERT_TYPE_UNKNOWN &&
793 strstr((char *)fdata.data, "-----BEGIN TSS KEY BLOB-----"))) {
794 #ifndef HAVE_TROUSERS
795 vpn_progress(vpninfo, PRG_ERR,
796 _("This version of OpenConnect was built without TPM support\n"));
799 ret = load_tpm_key(vpninfo, &fdata, &pkey, &pkey_sig);
807 gnutls_x509_privkey_init(&key);
808 /* Try PKCS#1 (and PKCS#8 without password) first. GnuTLS doesn't
809 support OpenSSL's old PKCS#1-based encrypted format. We should
810 probably check for it and give a more coherent failure mode. */
811 err = gnutls_x509_privkey_import(key, &fdata, GNUTLS_X509_FMT_PEM);
813 /* If that fails, try PKCS#8 */
814 char *pass = vpninfo->cert_password;
816 /* Yay, just for fun this is *different* to PKCS#12. Where we could
817 try an empty password there, in this case the empty-password case
818 has already been *tried* by gnutls_x509_privkey_import(). If we
819 just call gnutls_x509_privkey_import_pkcs8() with a NULL password,
820 it'll SEGV. You have to set the GNUTLS_PKCS_PLAIN flag if you want
821 to try without a password. Passing NULL evidently isn't enough of
822 a hint. And in GnuTLS 3.1 where that crash has been fixed, passing
823 NULL will cause it to return GNUTLS_E_ENCRYPTED_STRUCTURE (a new
824 error code) rather than GNUTLS_E_DECRYPTION_FAILED. So just pass ""
825 instead of NULL, and don't worry about either case. */
826 while ((err = gnutls_x509_privkey_import_pkcs8(key, &fdata,
829 if (err != GNUTLS_E_DECRYPTION_FAILED) {
830 vpn_progress(vpninfo, PRG_ERR,
831 _("Failed to load private key as PKCS#8: %s\n"),
832 gnutls_strerror(err));
836 vpninfo->cert_password = NULL;
838 vpn_progress(vpninfo, PRG_ERR,
839 _("Failed to decrypt PKCS#8 certificate file\n"));
842 err = request_passphrase(vpninfo, "openconnect_pem",
843 &pass, _("Enter PEM pass phrase:"));
850 vpninfo->cert_password = NULL;
853 /* Now attempt to make sure we use the *correct* certificate, to match the key */
854 err = gnutls_x509_privkey_get_key_id(key, 0, key_id, &key_id_size);
856 vpn_progress(vpninfo, PRG_ERR,
857 _("Failed to get key ID: %s\n"),
858 gnutls_strerror(err));
862 for (i = 0; i < (extra_certs?nr_extra_certs:1); i++) {
863 unsigned char cert_id[20];
864 size_t cert_id_size = sizeof(cert_id);
866 err = gnutls_x509_crt_get_key_id(extra_certs?extra_certs[i]:cert, 0, cert_id, &cert_id_size);
870 if (cert_id_size == key_id_size && !memcmp(cert_id, key_id, key_id_size)) {
872 cert = extra_certs[i];
874 /* Move the rest of the array down */
875 for (; i < nr_extra_certs - 1; i++)
876 extra_certs[i] = extra_certs[i+1];
883 /* There's no pkey (there's an x509 key), so we'll fall straight through the
884 * bit at match_cert: below, and go directly to the bit where it prints the
885 * 'no match found' error and exits. */
887 #if defined (HAVE_P11KIT) || defined (HAVE_TROUSERS)
889 /* If we have a privkey from PKCS#11 or TPM, we can't do the simple comparison
890 of key ID that we do for software keys to find which certificate is a
891 match. So sign some dummy data and then check the signature against each
892 of the available certificates until we find the right one. */
894 /* The TPM code may have already signed it, to test authorisation. We
895 only sign here for PKCS#11 keys, in which case fdata might be
896 empty too so point it at dummy data. */
897 if (!pkey_sig.data) {
899 fdata.data = dummy_hash_data;
903 err = sign_dummy_data(vpninfo, pkey, &fdata, &pkey_sig);
905 vpn_progress(vpninfo, PRG_ERR,
906 _("Error signing test data with private key: %s\n"),
907 gnutls_strerror(err));
913 for (i=0; i < (extra_certs?nr_extra_certs:1); i++) {
914 gnutls_pubkey_t pubkey;
916 gnutls_pubkey_init(&pubkey);
917 err = gnutls_pubkey_import_x509(pubkey, extra_certs?extra_certs[i]:cert, 0);
919 vpn_progress(vpninfo, PRG_ERR,
920 _("Error validating signature against certificate: %s\n"),
921 gnutls_strerror(err));
922 /* We'll probably fail shortly if we don't find it. */
923 gnutls_pubkey_deinit(pubkey);
926 err = gnutls_pubkey_verify_data(pubkey, 0, &fdata, &pkey_sig);
927 gnutls_pubkey_deinit(pubkey);
931 cert = extra_certs[i];
933 /* Move the rest of the array down */
934 for (; i < nr_extra_certs - 1; i++)
935 extra_certs[i] = extra_certs[i+1];
939 gnutls_free(pkey_sig.data);
943 gnutls_free(pkey_sig.data);
945 #endif /* P11KIT || TROUSERS */
947 /* We shouldn't reach this. It means that we didn't find *any* matching cert */
948 vpn_progress(vpninfo, PRG_ERR,
949 _("No SSL certificate found to match private key\n"));
953 /********************************************************************/
955 /* Now we have both cert(s) and key, and we should be ready to go. */
956 check_certificate_expiry(vpninfo, cert);
957 get_cert_name(cert, name, sizeof(name));
958 vpn_progress(vpninfo, PRG_INFO, _("Using client certificate '%s'\n"),
962 err = gnutls_certificate_set_x509_crl(vpninfo->https_cred, &crl, 1);
964 vpn_progress(vpninfo, PRG_ERR,
965 _("Setting certificate recovation list failed: %s\n"),
966 gnutls_strerror(err));
972 /* OpenSSL has problems with certificate chains — if there are
973 multiple certs with the same name, it doesn't necessarily
974 choose the _right_ one. (RT#1942)
975 Pick the right ones for ourselves and add them manually. */
977 if (nr_supporting_certs) {
978 /* We already got a bunch of certs from PKCS#12 file.
979 Remember how many need to be freed when we're done,
980 since we'll expand the supporting_certs array with
981 more from the cafile if we can. */
982 last_cert = supporting_certs[nr_supporting_certs-1];
983 certs_to_free = nr_supporting_certs;
986 certs_to_free = nr_supporting_certs = 1;
989 gnutls_x509_crt_t issuer;
991 for (i = 0; i < nr_extra_certs; i++) {
992 if (gnutls_x509_crt_check_issuer(last_cert, extra_certs[i]) &&
993 !check_issuer_sanity(last_cert, extra_certs[i]))
997 if (i < nr_extra_certs) {
998 issuer = extra_certs[i];
1000 err = gnutls_certificate_get_issuer(vpninfo->https_cred,
1001 last_cert, &issuer, 0);
1006 /* The check_issuer_sanity() function works fine as a workaround where
1007 it was used above, but when gnutls_certificate_get_issuer() returns
1008 a bogus cert, there's nothing we can do to fix it up. We don't get
1009 to iterate over all the available certs like we can over our own
1011 if (check_issuer_sanity(last_cert, issuer)) {
1012 /* Hm, is there a bug reference for this? Or just the git commit
1013 reference (c1ef7efb in master, 5196786c in gnutls_3_0_x-2)? */
1014 vpn_progress(vpninfo, PRG_ERR,
1015 _("WARNING: GnuTLS returned incorrect issuer certs; authentication may fail!\n"));
1019 if (issuer == last_cert) {
1020 /* Don't actually include the root CA. If they don't already trust it,
1021 then handing it to them isn't going to help. But don't omit the
1022 original certificate if it's self-signed. */
1023 if (nr_supporting_certs > 1)
1024 nr_supporting_certs--;
1028 /* OK, we found a new cert to add to our chain. */
1029 supporting_certs = gnutls_realloc(supporting_certs,
1030 sizeof(cert) * ++nr_supporting_certs);
1031 if (!supporting_certs) {
1032 vpn_progress(vpninfo, PRG_ERR,
1033 _("Failed to allocate memory for supporting certificates\n"));
1034 /* The world is probably about to end, but try without them anyway */
1040 /* First time we actually allocated an array? Copy the first cert into it */
1041 if (nr_supporting_certs == 2)
1042 supporting_certs[0] = cert;
1044 /* Append the new one */
1045 supporting_certs[nr_supporting_certs-1] = issuer;
1049 for (i = 1; i < nr_supporting_certs; i++) {
1050 get_cert_name(supporting_certs[i], name, sizeof(name));
1052 vpn_progress(vpninfo, PRG_DEBUG,
1053 _("Adding supporting CA '%s'\n"), name);
1056 #if defined (HAVE_P11KIT) || defined (HAVE_TROUSERS)
1058 #if defined(HAVE_GNUTLS_CERTIFICATE_SET_KEY)
1059 err = assign_privkey_gtls3(vpninfo, pkey, supporting_certs?:&cert, nr_supporting_certs);
1064 #else /* !HAVE_GNUTLS_CERTIFICATE_SET_KEY so fake it using sign_callback */
1066 vpninfo->my_p11key = p11key;
1068 err = assign_privkey_gtls2(vpninfo, pkey, supporting_certs?:&cert, nr_supporting_certs,
1069 extra_certs, nr_extra_certs);
1075 pkey = NULL; /* we gave it away, along with pcerts */
1077 #endif /* P11KIT || TROUSERS */
1078 err = gnutls_certificate_set_x509_key(vpninfo->https_cred,
1079 supporting_certs ? supporting_certs : &cert,
1080 supporting_certs ? nr_supporting_certs : 1,
1084 vpn_progress(vpninfo, PRG_ERR,
1085 _("Setting certificate failed: %s\n"),
1086 gnutls_strerror(err));
1092 gnutls_x509_crl_deinit(crl);
1094 gnutls_x509_privkey_deinit(key);
1095 if (supporting_certs) {
1096 for (i = 0; i < certs_to_free; i++) {
1097 if (supporting_certs[i])
1098 gnutls_x509_crt_deinit(supporting_certs[i]);
1100 gnutls_free(supporting_certs);
1102 /* Not if supporting_certs. It's supporting_certs[0] then and
1103 was already freed. */
1104 gnutls_x509_crt_deinit(cert);
1106 for (i = 0; i < nr_extra_certs; i++) {
1108 gnutls_x509_crt_deinit(extra_certs[i]);
1110 gnutls_free(extra_certs);
1111 #if defined (HAVE_P11KIT) || defined (HAVE_TROUSERS)
1112 if (pkey && pkey != OPENCONNECT_TPM_PKEY)
1113 gnutls_privkey_deinit(pkey);
1114 if (fdata.data != dummy_hash_data)
1115 #endif /* It's conditional if we support arbitrary privkeys: */
1116 gnutls_free(fdata.data);
1118 if (cert_url != vpninfo->cert)
1120 if (key_url != vpninfo->sslkey)
1126 static int get_cert_fingerprint(struct openconnect_info *vpninfo,
1127 gnutls_x509_crt_t cert,
1128 gnutls_digest_algorithm_t algo,
1131 unsigned char md[256];
1132 size_t md_size = sizeof(md);
1135 if (gnutls_x509_crt_get_fingerprint(cert, algo, md, &md_size))
1138 for (i=0; i < md_size; i++)
1139 sprintf(&buf[i*2], "%02X", md[i]);
1144 int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
1145 OPENCONNECT_X509 *cert, char *buf)
1147 return get_cert_fingerprint(vpninfo, cert, GNUTLS_DIG_MD5, buf);
1150 int openconnect_get_cert_sha1(struct openconnect_info *vpninfo,
1151 OPENCONNECT_X509 *cert, char *buf)
1153 return get_cert_fingerprint(vpninfo, cert, GNUTLS_DIG_SHA1, buf);
1156 char *openconnect_get_cert_details(struct openconnect_info *vpninfo,
1157 OPENCONNECT_X509 *cert)
1162 if (gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL, &buf))
1165 /* Just in case gnutls_free() isn't free(), we can't steal it. */
1166 ret = strdup((char *)buf.data);
1167 gnutls_free(buf.data);
1172 int openconnect_get_cert_DER(struct openconnect_info *vpninfo,
1173 OPENCONNECT_X509 *cert, unsigned char **buf)
1176 unsigned char *ret = NULL;
1178 if (gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, ret, &l) !=
1179 GNUTLS_E_SHORT_MEMORY_BUFFER)
1186 if (gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, ret, &l)) {
1194 static int verify_peer(gnutls_session_t session)
1196 struct openconnect_info *vpninfo = gnutls_session_get_ptr(session);
1197 const gnutls_datum_t *cert_list;
1198 gnutls_x509_crt_t cert;
1199 unsigned int status, cert_list_size;
1200 const char *reason = NULL;
1203 if (vpninfo->peer_cert) {
1204 gnutls_x509_crt_deinit(vpninfo->peer_cert);
1205 vpninfo->peer_cert = NULL;
1208 cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
1210 vpn_progress(vpninfo, PRG_ERR, _("Server presented no certificate\n"));
1211 return GNUTLS_E_CERTIFICATE_ERROR;
1214 if (vpninfo->servercert) {
1215 unsigned char sha1bin[SHA1_SIZE];
1216 char fingerprint[(SHA1_SIZE * 2) + 1];
1219 err = openconnect_sha1(sha1bin, cert_list[0].data, cert_list[0].size);
1221 vpn_progress(vpninfo, PRG_ERR,
1222 _("Could not calculate SHA1 of server's certificate\n"));
1223 return GNUTLS_E_CERTIFICATE_ERROR;
1225 for (i=0; i < SHA1_SIZE; i++)
1226 sprintf(&fingerprint[i*2], "%02X", sha1bin[i]);
1228 if (strcasecmp(vpninfo->servercert, fingerprint)) {
1229 vpn_progress(vpninfo, PRG_ERR,
1230 _("Server SSL certificate didn't match: %s\n"), fingerprint);
1231 return GNUTLS_E_CERTIFICATE_ERROR;
1236 err = gnutls_certificate_verify_peers2 (session, &status);
1238 vpn_progress(vpninfo, PRG_ERR, _("Error checking server cert status\n"));
1239 return GNUTLS_E_CERTIFICATE_ERROR;
1242 if (status & GNUTLS_CERT_REVOKED)
1243 reason = _("certificate revoked");
1244 else if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
1245 reason = _("signer not found");
1246 else if (status & GNUTLS_CERT_SIGNER_NOT_CA)
1247 reason = _("signer not a CA certificate");
1248 else if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
1249 reason = _("insecure algorithm");
1250 else if (status & GNUTLS_CERT_NOT_ACTIVATED)
1251 reason = _("certificate not yet activated");
1252 else if (status & GNUTLS_CERT_EXPIRED)
1253 reason = _("certificate expired");
1254 else if (status & GNUTLS_CERT_INVALID)
1255 /* If this is set and no other reason, it apparently means
1256 that signature verification failed. Not entirely sure
1257 why we don't just set a bit for that too. */
1258 reason = _("signature verification failed");
1260 err = gnutls_x509_crt_init(&cert);
1262 vpn_progress(vpninfo, PRG_ERR, _("Error initialising X509 cert structure\n"));
1263 return GNUTLS_E_CERTIFICATE_ERROR;
1266 err = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
1268 vpn_progress(vpninfo, PRG_ERR, _("Error importing server's cert\n"));
1269 gnutls_x509_crt_deinit(cert);
1270 return GNUTLS_E_CERTIFICATE_ERROR;
1273 if (!reason && !gnutls_x509_crt_check_hostname(cert, vpninfo->hostname))
1274 reason = _("certificate does not match hostname");
1277 vpn_progress(vpninfo, PRG_INFO, "Server certificate verify failed: %s\n",
1279 if (vpninfo->validate_peer_cert)
1280 err = vpninfo->validate_peer_cert(vpninfo->cbdata,
1282 reason) ? GNUTLS_E_CERTIFICATE_ERROR : 0;
1284 err = GNUTLS_E_CERTIFICATE_ERROR;
1287 vpninfo->peer_cert = cert;
1293 int openconnect_open_https(struct openconnect_info *vpninfo)
1298 if (vpninfo->https_sess)
1301 ssl_sock = connect_https_socket(vpninfo);
1305 if (!vpninfo->https_cred) {
1306 gnutls_certificate_allocate_credentials(&vpninfo->https_cred);
1307 #ifdef HAVE_GNUTLS_CERTIFICATE_SET_X509_SYSTEM_TRUST
1308 gnutls_certificate_set_x509_system_trust(vpninfo->https_cred);
1310 gnutls_certificate_set_x509_trust_file(vpninfo->https_cred,
1311 "/etc/pki/tls/certs/ca-bundle.crt",
1312 GNUTLS_X509_FMT_PEM);
1314 gnutls_certificate_set_verify_function (vpninfo->https_cred,
1317 if (vpninfo->cafile) {
1318 err = gnutls_certificate_set_x509_trust_file(vpninfo->https_cred,
1320 GNUTLS_X509_FMT_PEM);
1322 vpn_progress(vpninfo, PRG_ERR,
1323 _("Failed to open CA file '%s': %s\n"),
1324 vpninfo->cafile, gnutls_strerror(err));
1330 if (vpninfo->cert) {
1331 err = load_certificate(vpninfo);
1333 vpn_progress(vpninfo, PRG_ERR,
1334 _("Loading certificate failed. Aborting.\n"));
1339 gnutls_init (&vpninfo->https_sess, GNUTLS_CLIENT);
1340 gnutls_session_set_ptr (vpninfo->https_sess, (void *) vpninfo);
1341 #if defined(HAVE_TROUSERS) && !defined(HAVE_GNUTLS_CERTIFICATE_SET_KEY)
1342 if (vpninfo->my_pkey == OPENCONNECT_TPM_PKEY)
1343 gnutls_sign_callback_set(vpninfo->https_sess, gtls2_tpm_sign_cb, vpninfo);
1345 err = gnutls_priority_set_direct (vpninfo->https_sess, "NONE:+VERS-TLS1.0:+SHA1:+AES-128-CBC:+RSA:+COMP-NULL:%COMPAT:%DISABLE_SAFE_RENEGOTIATION", NULL);
1347 vpn_progress(vpninfo, PRG_ERR,
1348 _("Failed to set TLS priority string: %s\n"),
1349 gnutls_strerror(err));
1353 gnutls_record_disable_padding (vpninfo->https_sess);
1354 gnutls_credentials_set (vpninfo->https_sess, GNUTLS_CRD_CERTIFICATE, vpninfo->https_cred);
1355 gnutls_transport_set_ptr(vpninfo->https_sess, /* really? */(gnutls_transport_ptr_t)(long) ssl_sock);
1357 vpn_progress(vpninfo, PRG_INFO, _("SSL negotiation with %s\n"),
1360 while ((err = gnutls_handshake (vpninfo->https_sess))) {
1361 if (err == GNUTLS_E_AGAIN) {
1362 fd_set rd_set, wr_set;
1363 int maxfd = ssl_sock;
1368 if (gnutls_record_get_direction(vpninfo->https_sess))
1369 FD_SET(ssl_sock, &wr_set);
1371 FD_SET(ssl_sock, &rd_set);
1373 if (vpninfo->cancel_fd != -1) {
1374 FD_SET(vpninfo->cancel_fd, &rd_set);
1375 if (vpninfo->cancel_fd > ssl_sock)
1376 maxfd = vpninfo->cancel_fd;
1378 select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
1379 if (vpninfo->cancel_fd != -1 &&
1380 FD_ISSET(vpninfo->cancel_fd, &rd_set)) {
1381 vpn_progress(vpninfo, PRG_ERR, _("SSL connection cancelled\n"));
1382 gnutls_deinit(vpninfo->https_sess);
1383 vpninfo->https_sess = NULL;
1387 } else if (err == GNUTLS_E_INTERRUPTED || gnutls_error_is_fatal(err)) {
1388 vpn_progress(vpninfo, PRG_ERR, _("SSL connection failure: %s\n"),
1389 gnutls_strerror(err));
1390 gnutls_deinit(vpninfo->https_sess);
1391 vpninfo->https_sess = NULL;
1395 /* non-fatal error or warning. Ignore it and continue */
1396 vpn_progress(vpninfo, PRG_TRACE,
1397 _("GnuTLS non-fatal return during handshake: %s\n"),
1398 gnutls_strerror(err));
1402 vpninfo->ssl_fd = ssl_sock;
1404 vpn_progress(vpninfo, PRG_INFO, _("Connected to HTTPS on %s\n"),
1410 void openconnect_close_https(struct openconnect_info *vpninfo, int final)
1412 if (vpninfo->peer_cert) {
1413 gnutls_x509_crt_deinit(vpninfo->peer_cert);
1414 vpninfo->peer_cert = NULL;
1416 if (vpninfo->https_sess) {
1417 gnutls_deinit(vpninfo->https_sess);
1418 vpninfo->https_sess = NULL;
1420 if (vpninfo->ssl_fd != -1) {
1421 close(vpninfo->ssl_fd);
1422 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_rfds);
1423 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
1424 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_efds);
1425 vpninfo->ssl_fd = -1;
1427 if (final && vpninfo->https_cred) {
1428 gnutls_certificate_free_credentials(vpninfo->https_cred);
1429 vpninfo->https_cred = NULL;
1431 if (!strncmp(vpninfo->cert, "pkcs11:", 7) ||
1432 !strncmp(vpninfo->sslkey, "pkcs11:", 7)) {
1433 char pin_source[40];
1435 sprintf(pin_source, "openconnect:%p", vpninfo);
1436 p11_kit_pin_unregister_callback(pin_source, pin_callback, vpninfo);
1438 while (vpninfo->pin_cache) {
1439 struct pin_cache *cache = vpninfo->pin_cache;
1442 memset(cache->pin, 0x5a, strlen(cache->pin));
1444 vpninfo->pin_cache = cache->next;
1449 #ifdef HAVE_TROUSERS
1450 if (vpninfo->tpm_key_policy) {
1451 Tspi_Context_CloseObject(vpninfo->tpm_context, vpninfo->tpm_key_policy);
1452 vpninfo->tpm_key = 0;
1454 if (vpninfo->tpm_key) {
1455 Tspi_Context_CloseObject(vpninfo->tpm_context, vpninfo->tpm_key);
1456 vpninfo->tpm_key = 0;
1458 if (vpninfo->srk_policy) {
1459 Tspi_Context_CloseObject(vpninfo->tpm_context, vpninfo->srk_policy);
1460 vpninfo->srk_policy = 0;
1463 Tspi_Context_CloseObject(vpninfo->tpm_context, vpninfo->srk);
1466 if (vpninfo->tpm_context) {
1467 Tspi_Context_Close(vpninfo->tpm_context);
1468 vpninfo->tpm_context = 0;
1471 #ifndef HAVE_GNUTLS_CERTIFICATE_SET_KEY
1472 if (vpninfo->my_pkey && vpninfo->my_pkey != OPENCONNECT_TPM_PKEY) {
1473 gnutls_privkey_deinit(vpninfo->my_pkey);
1474 vpninfo->my_pkey = NULL;
1475 /* my_p11key went with it */
1477 if (vpninfo->my_certs) {
1479 for (i = 0; i < vpninfo->nr_my_certs; i++)
1480 gnutls_x509_crt_deinit(vpninfo->my_certs[i]);
1481 free(vpninfo->my_certs);
1482 vpninfo->my_certs = NULL;
1488 void openconnect_init_ssl(void)
1490 gnutls_global_init();
1493 int openconnect_sha1(unsigned char *result, void *data, int datalen)
1496 size_t shalen = SHA1_SIZE;
1500 if (gnutls_fingerprint(GNUTLS_DIG_SHA1, &d, result, &shalen))
1506 int openconnect_random(void *bytes, int len)
1508 if (gnutls_rnd(GNUTLS_RND_RANDOM, bytes, len))
1513 int openconnect_local_cert_md5(struct openconnect_info *vpninfo,
1516 const gnutls_datum_t *d;
1521 d = gnutls_certificate_get_ours(vpninfo->https_sess);
1525 if (gnutls_fingerprint(GNUTLS_DIG_MD5, d, buf, &md5len))
1532 static P11KitPin *pin_callback(const char *pin_source, P11KitUri *pin_uri,
1533 const char *pin_description,
1534 P11KitPinFlags flags,
1537 struct openconnect_info *vpninfo = _vpninfo;
1538 struct pin_cache **cache = &vpninfo->pin_cache;
1539 struct oc_auth_form f;
1540 struct oc_form_opt o;
1546 if (!vpninfo || !vpninfo->process_auth_form)
1549 if (p11_kit_uri_format(pin_uri, P11_KIT_URI_FOR_TOKEN, &uri))
1553 if (!strcmp(uri, (*cache)->token)) {
1556 if ((*cache)->pin) {
1557 if ((flags & P11_KIT_PIN_FLAGS_RETRY) != P11_KIT_PIN_FLAGS_RETRY)
1558 return p11_kit_pin_new_for_string((*cache)->pin);
1559 memset((*cache)->pin, 0x5a, strlen((*cache)->pin));
1560 free((*cache)->pin);
1561 (*cache)->pin = NULL;
1567 *cache = calloc(1, sizeof(struct pin_cache));
1572 (*cache)->token = uri;
1575 memset(&f, 0, sizeof(f));
1576 f.auth_id = (char *)"pkcs11_pin";
1579 message[sizeof(message)-1] = 0;
1580 snprintf(message, sizeof(message) - 1, _("PIN required for %s"), pin_description);
1581 f.message = message;
1584 * In p11-kit <= 0.12, these flags are *odd*.
1585 * RETRY is 0xa, FINAL_TRY is 0x14 and MANY_TRIES is 0x28.
1586 * So don't treat it like a sane bitmask. Fixed in
1587 * http://cgit.freedesktop.org/p11-glue/p11-kit/commit/?id=59774b11
1589 if ((flags & P11_KIT_PIN_FLAGS_RETRY) == P11_KIT_PIN_FLAGS_RETRY)
1590 f.error = (char *)_("Wrong PIN");
1592 if ((flags & P11_KIT_PIN_FLAGS_FINAL_TRY) == P11_KIT_PIN_FLAGS_FINAL_TRY)
1593 f.banner = (char *)_("This is the final try before locking!");
1594 else if ((flags & P11_KIT_PIN_FLAGS_MANY_TRIES) == P11_KIT_PIN_FLAGS_MANY_TRIES)
1595 f.banner = (char *)_("Only a few tries left before locking!");
1598 o.type = OC_FORM_OPT_PASSWORD;
1599 o.name = (char *)"pkcs11_pin";
1600 o.label = (char *)_("Enter PIN:");
1603 ret = vpninfo->process_auth_form(vpninfo->cbdata, &f);
1604 if (ret || !o.value)
1607 pin = p11_kit_pin_new_for_string(o.value);
1608 (*cache)->pin = o.value;