]> www.infradead.org Git - users/dwmw2/openconnect.git/commitdiff
Add password to pin callback
authorTom Carroll <incentivedesign@gmail.com>
Sat, 25 Apr 2020 06:47:33 +0000 (23:47 -0700)
committerTom Carroll <incentivedesign@gmail.com>
Wed, 6 May 2020 08:54:26 +0000 (01:54 -0700)
There are (at least) two passwords, one for TLS session and another for
the multiple certificate-based authentication challenge. Add password
parameter to the pin callback.

Signed-off-by: Tom Carroll <incentivedesign@gmail.com>
gnutls.c
openconnect-internal.h

index b40fa64a773334cf98ebda1ef8c6b96684481e1d..0127dc05c39c7c2965cfa1af8b2ca9cbcc763392 100644 (file)
--- a/gnutls.c
+++ b/gnutls.c
 #endif
 
 #if defined(HAVE_P11KIT) || defined(HAVE_GNUTLS_SYSTEM_KEYS)
-static int pin_callback(void *user, int attempt, const char *token_uri,
-                              const char *token_label, unsigned int flags,
-                              char *pin, size_t pin_max);
+/**
+ * pin callback context
+ *
+ * Password (first_pass) is notably part of the context
+ */
+struct oc_pin_ctx {
+       gnutls_pin_callback_t cb;
+       void *cb_arg;
+
+       struct openconnect_info *vpninfo;
+       char *first_pass;
+       struct oc_pin_ctx *next;
+};
+
+static struct oc_pin_ctx *pinctx_new(
+       struct openconnect_info *vpninfo,
+       const char *password);
+
+static void pinctx_free(struct oc_pin_ctx *ctx);
+
+static void release_pin_ctx(struct openconnect_info *vpninfo);
 #endif /* HAVE_P11KIT || HAVE_GNUTLS_SYSTEM_KEYS */
 
 #include "gnutls.h"
@@ -1244,6 +1262,7 @@ static int load_keycert(struct openconnect_info *vpninfo,
        gnutls_x509_crl_t crl = NULL;
        gnutls_x509_crt_t last_cert, cert = NULL;
        gnutls_x509_crt_t *extra_certs = NULL, *supporting_certs = NULL;
+       struct oc_pin_ctx *pinctx = NULL;
        unsigned int nr_supporting_certs = 0, nr_extra_certs = 0;
        int err; /* GnuTLS error */
        int ret;
@@ -1334,11 +1353,17 @@ static int load_keycert(struct openconnect_info *vpninfo,
                        goto out;
                }
 
-               gnutls_x509_crt_set_pin_function(cert, pin_callback, vpninfo);
+               err = 0;
+               pinctx = pinctx_new(vpninfo, password);
+               if (pinctx == NULL)
+                       err = GNUTLS_E_MEMORY_ERROR;
+               if (err >= 0) {
+                       gnutls_x509_crt_set_pin_function(cert, pinctx->cb, pinctx->cb_arg);
 
-               /* Yes, even for *system* URLs the only API GnuTLS offers us is
+                       /* Yes, even for *system* URLs the only API GnuTLS offers us is
                   ...import_pkcs11_url(). */
-               err = gnutls_x509_crt_import_pkcs11_url(cert, cert_url, 0);
+                       err = gnutls_x509_crt_import_pkcs11_url(cert, cert_url, 0);
+               }
                if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
                        err = gnutls_x509_crt_import_pkcs11_url(cert, cert_url,
                                                                GNUTLS_PKCS11_OBJ_FLAG_LOGIN);
@@ -1350,6 +1375,9 @@ static int load_keycert(struct openconnect_info *vpninfo,
                        ret = -EIO;
                        goto out;
                }
+               pinctx->next = vpninfo->pin_ctx;
+               vpninfo->pin_ctx = pinctx;
+               pinctx = NULL;
                goto got_certs;
        }
 #endif /* HAVE_P11KIT || HAVE_GNUTLS_SYSTEM_KEYS */
@@ -1436,9 +1464,14 @@ static int load_keycert(struct openconnect_info *vpninfo,
                        goto out;
                }
 
-               gnutls_privkey_set_pin_function(pkey, pin_callback, vpninfo);
-
-               err = gnutls_privkey_import_url(pkey, key_path, 0);
+               err = 0;
+               pinctx = pinctx_new(vpninfo, password);
+               if (pinctx == NULL)
+                       err = GNUTLS_E_MEMORY_ERROR;
+               if (err >= 0) {
+                       gnutls_privkey_set_pin_function(pkey, pinctx->cb, pinctx->cb_arg);
+                       err = gnutls_privkey_import_url(pkey, key_path, 0);
+               }
                if (err) {
                        vpn_progress(vpninfo, PRG_ERR,
                            _("Error importing system key %s: %s\n"),
@@ -1446,6 +1479,9 @@ static int load_keycert(struct openconnect_info *vpninfo,
                        ret = -EIO;
                        goto out;
                }
+               pinctx->next = vpninfo->pin_ctx;
+               vpninfo->pin_ctx = pinctx;
+               pinctx = NULL;
                goto match_cert;
        }
 #endif /* HAVE_GNUTLS_SYSTEM_KEYS */
@@ -1463,9 +1499,14 @@ static int load_keycert(struct openconnect_info *vpninfo,
                        goto out;
                }
 
-               gnutls_pkcs11_privkey_set_pin_function(p11key, pin_callback, vpninfo);
-
-               err = gnutls_pkcs11_privkey_import_url(p11key, key_url, 0);
+               err = 0;
+               pinctx = pinctx_new(vpninfo, password);
+               if (pinctx == NULL)
+                       err = GNUTLS_E_MEMORY_ERROR;
+               if (err >= 0) {
+                       gnutls_pkcs11_privkey_set_pin_function(p11key, pinctx->cb, pinctx->cb_arg);
+                       err = gnutls_pkcs11_privkey_import_url(p11key, key_url, 0);
+               }
 
                /* Annoyingly, some tokens don't even admit the *existence* of
                   the key until they're logged in. And thus a search doesn't
@@ -1593,6 +1634,9 @@ static int load_keycert(struct openconnect_info *vpninfo,
                        ret = -EIO;
                        goto out;
                }
+               pinctx->next = vpninfo->pin_ctx;
+               vpninfo->pin_ctx = pinctx;
+               pinctx = NULL;
                goto match_cert;
        }
 #endif /* HAVE_P11KIT */
@@ -1956,6 +2000,8 @@ static int load_keycert(struct openconnect_info *vpninfo,
        free_datum(&fdata);
        free_datum(&pkey_sig);
 
+       pinctx_free(pinctx);
+
        if (cert_url != cert_path)
                free(cert_url);
        if (key_url != key_path)
@@ -2754,6 +2800,9 @@ void openconnect_close_https(struct openconnect_info *vpninfo, int final)
 #ifdef HAVE_TSS2
                release_tpm2_ctx(vpninfo);
 #endif
+#if defined(HAVE_P11KIT) || defined(HAVE_GNUTLS_SYSTEM_KEYS)
+               release_pin_ctx(vpninfo);
+#endif /* defined(HAVE_P11KIT) || defined(HAVE_GNUTLS_SYSTEM_KEYS) */
        }
 }
 
@@ -2870,18 +2919,15 @@ static int request_pin(struct openconnect_info *vpninfo, char **ppin,
        return 0;
 }
 
-int pin_callback(void *user, int attempts, const char *token_uri,
-                              const char *token_label, unsigned int flags,
-                              char *pin, size_t pin_max)
+static int pin_callback_(struct openconnect_info *vpninfo,
+       char *first_pass, int attempts,
+       const char *token_uri, const char *token_label,
+       unsigned int flags, char *pin, size_t pin_max)
 {
-       struct openconnect_info *vpninfo = user;
        struct pin_cache *cache;
        size_t pinlen;
        int ret;
 
-       if (!vpninfo)
-               return GNUTLS_E_INVALID_REQUEST;
-
        if (token_uri == NULL || token_uri[0] == 0)
                token_uri = "(no URI)";
 
@@ -2897,28 +2943,25 @@ int pin_callback(void *user, int attempts, const char *token_uri,
         * Add entry for token_uri if one does not exist
         */
        if (cache == NULL) {
-               /**
-                * set myself up for a subsequent commit
-                */
-               const char *first_pass = vpninfo->cert_password;
-
                cache = calloc(1, sizeof *cache);
                if (cache == NULL)
                        return GNUTLS_E_MEMORY_ERROR;
                *cache =
-                       (struct pin_cache) { .pin = first_pass ? strdup(first_pass) : NULL,
-                         .token = strdup(token_uri),
-                         .next = vpninfo->pin_cache };
-               if ((first_pass && cache->pin == NULL)
-                   || cache->token == NULL) {
+                       (struct pin_cache) { .pin = first_pass,
+                                            .token = strdup(token_uri),
+                                            .next = vpninfo->pin_cache };
+               if (cache->token == NULL) {
                        free_pass(&cache->pin);
                        free(cache->token);
                        free(cache);
                        return GNUTLS_E_MEMORY_ERROR;
                }
                vpninfo->pin_cache = cache;
+               first_pass = NULL;
        }
 
+       free_pass(&first_pass);
+
        /**
         * Wrong PIN.
         */
@@ -2959,6 +3002,58 @@ int pin_callback(void *user, int attempts, const char *token_uri,
                return GNUTLS_E_PKCS11_PIN_ERROR;
        }
 }
+
+static int pin_callback(void *user, int attempts,
+       const char *token_uri, const char *token_label,
+       unsigned int flags, char *pin, size_t pin_max)
+{
+       struct oc_pin_ctx *cb = user;
+       int ret;
+
+       if (cb == NULL || cb->vpninfo == NULL)
+               return GNUTLS_E_INVALID_REQUEST;
+       ret = pin_callback_(cb->vpninfo, cb->first_pass, attempts,
+               token_uri, token_label, flags, pin, pin_max);
+       cb->first_pass = NULL;
+       return ret;
+}
+
+struct oc_pin_ctx *
+pinctx_new(struct openconnect_info *vpninfo, const char *password)
+{
+       struct oc_pin_ctx *pinctx;
+       char *first_pass = NULL;
+
+       if ((pinctx = malloc(sizeof *pinctx)) == NULL)
+               return NULL;
+       if (password && (first_pass = strdup(password)) == NULL) {
+               free(pinctx);
+               return NULL;
+       }
+       *pinctx = (struct oc_pin_ctx) { .cb = pin_callback,
+                                       .cb_arg = pinctx,
+                                       .vpninfo = vpninfo,
+                                       .first_pass = first_pass };
+       return pinctx;
+}
+
+void pinctx_free(struct oc_pin_ctx *pinctx)
+{
+       if (pinctx) {
+               free_pass(&pinctx->first_pass);
+               free(pinctx);
+       }
+}
+
+void release_pin_ctx(struct openconnect_info *vpninfo)
+{
+       struct oc_pin_ctx *pinctx;
+
+       while ((pinctx = vpninfo->pin_ctx)) {
+               vpninfo->pin_ctx = pinctx->next;
+               pinctx_free(pinctx);
+       }
+}
 #endif /* HAVE_P11KIT || HAVE_GNUTLS_SYSTEM_KEYS */
 
 #ifdef HAVE_LIBPCSCLITE
index b86b6cb24d7027bb78ab34389acbad082921a0b1..b3806136ee263710dbee7fd4fad52ebf89983430 100644 (file)
@@ -364,6 +364,7 @@ struct esp {
 struct oc_pcsc_ctx;
 struct oc_tpm1_ctx;
 struct oc_tpm2_ctx;
+struct oc_pin_ctx;
 
 struct openconnect_info {
        const struct vpn_proto *proto;
@@ -455,6 +456,8 @@ struct openconnect_info {
        char *key2;
        char *key2_password;
 
+       struct oc_pin_ctx *pin_ctx;
+
        int token_mode;
        int token_bypassed;
        int token_tries;