From 276cf337346e0ea111883a05bc00f764d201d6ab Mon Sep 17 00:00:00 2001 From: Alejandro Soto Date: Sun, 29 Jun 2025 11:35:57 -0600 Subject: [PATCH 2/2] gnutls: implement token insertion and PKCS#11 PIN prompts --- conn/gnutls.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/conn/gnutls.c b/conn/gnutls.c index 379580871..32ad1ae85 100644 --- a/conn/gnutls.c +++ b/conn/gnutls.c @@ -29,6 +29,7 @@ #include "config.h" #include +#include #include #include #include @@ -39,10 +40,14 @@ #include "mutt/lib.h" #include "config/lib.h" #include "core/lib.h" -#include "lib.h" #include "connaccount.h" #include "connection.h" +#include "editor/lib.h" #include "globals.h" +#include "gui/lib.h" +#include "history/lib.h" +#include "lib.h" +#include "mutt.h" #include "muttlib.h" #include "ssl.h" @@ -84,6 +89,64 @@ struct TlsSockData gnutls_certificate_credentials_t xcred; }; +int tls_pkcs11_token_callback(void *userdata, const char *label, unsigned retry) +{ + (void) userdata; + + if (OptNoCurses) { + mutt_error(_("Unable to prompt for PKCS#11 token insertion in batch mode")); + return GNUTLS_E_INVALID_REQUEST; + } + + char msg[256] = { 0 }; + + size_t len = 0; + if (retry > 0) + len += snprintf(msg, sizeof msg, _("[Not found - attempt %u] "), retry + 1); + + snprintf(msg + len, sizeof msg - len, _("Insert PKCS#11 token '%s' and press any key..."), label); + + mutt_any_key_to_continue(msg); + return 0; +} + +int tls_pin_callback(void *userdata, int attempt, const char *url, const char *label, + unsigned int flags, char *pin, size_t pin_max) +{ + (void) url; + const intptr_t is_token = (intptr_t) userdata; + + if (OptNoCurses) { + mutt_error(_("Unable to prompt for pin in batch mode")); + return GNUTLS_E_INVALID_REQUEST; + } + + char prompt[256] = { 0 }; + + size_t len = 0; + if (attempt > 0) + len += snprintf(prompt, sizeof prompt, _("[Attempt %d] "), attempt + 1); + + if (flags & GNUTLS_PIN_FINAL_TRY) + len += mutt_str_copy(prompt + len, _("FINAL TRY - "), sizeof prompt - len); + + if (is_token) + snprintf(prompt + len, sizeof prompt - len, _("Pin for PKCS#11 token '%s': "), label); + else + snprintf(prompt + len, sizeof prompt - len, _("Password for certificate '%s': "), label); + + struct Buffer *buf = buf_pool_get(); + const int rc = mw_get_field(prompt, buf, MUTT_COMP_PASS | MUTT_COMP_UNBUFFERED, + HC_OTHER, NULL, NULL); + mutt_str_copy(pin, buf_string(buf), pin_max); + buf_pool_release(&buf); + + if (rc != 0) + return GNUTLS_E_APPLICATION_ERROR_MIN; + + return 0; +} + /** * tls_init - Set up Gnu TLS * @retval 0 Success @@ -104,6 +167,10 @@ static int tls_init(void) return -1; } + const intptr_t is_token = 1; + gnutls_pkcs11_set_pin_function(tls_pin_callback, (void *)is_token); + gnutls_pkcs11_set_token_function(tls_pkcs11_token_callback, NULL); + init_complete = true; return 0; } @@ -904,6 +971,9 @@ static int tls_negotiate(struct Connection *conn) mutt_debug(LL_DEBUG2, "Using client certificate %s, key %s\n", c_ssl_client_cert, c_ssl_client_key); gnutls_certificate_set_x509_key_file(data->xcred, c_ssl_client_cert, c_ssl_client_key, GNUTLS_X509_FMT_PEM); + + const intptr_t is_token = 0; + gnutls_certificate_set_pin_function(data->xcred, tls_pin_callback, (void *)is_token); } #ifdef HAVE_DECL_GNUTLS_VERIFY_DISABLE_TIME_CHECKS -- 2.49.0