]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
x509: pin/password callback support for openssl encrypted private keys
authorCraig Gallek <cgallek@gmail.com>
Wed, 11 Aug 2021 16:54:37 +0000 (12:54 -0400)
committerCraig Gallek <cgallek@gmail.com>
Sun, 15 Aug 2021 14:20:31 +0000 (10:20 -0400)
This attempts to use the registered pin callback when the password for
an encrypted openssl private key is not supplied.  This matches the
functionality for PKCS8 sealed keys above and is similar to what openssl
does in this situation.

Signed-off-by: Craig Gallek <cgallek@gmail.com>
lib/x509/privkey.c
tests/key-openssl.c

index 0cc1c8b30cefef1d5fc61ab7e1641f1a7462fec5..570e5e425cbb6d1646e53fc98a0d1c8545e9e1af 100644 (file)
@@ -780,6 +780,16 @@ gnutls_x509_privkey_import2(gnutls_x509_privkey_t key,
                                    gnutls_x509_privkey_import_openssl(key,
                                                                       data,
                                                                       password);
+
+                               if (ret == GNUTLS_E_DECRYPTION_FAILED && password == NULL) {
+                                       /* use the callback if any */
+                                       memset(pin, 0, GNUTLS_PKCS11_MAX_PIN_LEN);
+                                       ret = _gnutls_retrieve_pin(&key->pin, "key:", "", 0, pin, sizeof(pin));
+                                       if (ret == 0) {
+                                               ret = gnutls_x509_privkey_import_openssl(key, data, pin);
+                                       }
+                               }
+
                                if (ret < 0) {
                                        gnutls_assert();
                                        goto cleanup;
index d2c8a724bb364a4121d5a74fafd8f4c6a218529c..10c1514fb6686f3a44c6858a1fdc9f8629e36a17 100644 (file)
@@ -95,6 +95,20 @@ const char key2[] =
     "F3bDyqlxSOm7uxF/K3YzI44v8/D8GGnLBTpN+ANBdiY=\n"
     "-----END RSA PRIVATE KEY-----\n";
 
+static int good_pwd_cb(void* userdata, int attempt, const char* token_url,
+                      const char* token_label, unsigned int flags,
+                      char* pin, size_t pin_max) {
+       snprintf(pin, pin_max, "%s", "123456");
+       return 0;
+}
+
+static int bad_pwd_cb(void* userdata, int attempt, const char* token_url,
+                     const char* token_label, unsigned int flags,
+                     char* pin, size_t pin_max) {
+       snprintf(pin, pin_max, "%s", "bad");
+       return 0;
+}
+
 void doit(void)
 {
        gnutls_x509_privkey_t pkey;
@@ -167,5 +181,62 @@ void doit(void)
        }
        gnutls_x509_privkey_deinit(pkey);
 
+       /*
+        * Pin callback passwords will only be used if the password supplied to
+        * gnutls_x509_privkey_import2 in NULL.  Consider possible combinations
+        * of passwords supplied via the import function/pin callback:
+        *  good/bad => success
+        *  NULL/good => success
+        *  NULL/bad  => failure
+        */
+
+       /* import_openssl good / callback bad => success */
+       ret = gnutls_x509_privkey_init(&pkey);
+       if (ret < 0)
+               fail("gnutls_x509_privkey_init: %d\n", ret);
+
+       gnutls_x509_privkey_set_pin_function(pkey, bad_pwd_cb, NULL);
+       key.data = (void *) key1;
+       key.size = sizeof(key1);
+       ret = gnutls_x509_privkey_import2(pkey, &key, GNUTLS_X509_FMT_PEM,
+                                         "123456", 0);
+       if (ret < 0) {
+               fail("gnutls_x509_privkey_import2 (good func/bad pin): %s\n",
+                    gnutls_strerror(ret));
+       }
+       gnutls_x509_privkey_deinit(pkey);
+
+       /* import_openssl NULL / callback good => success */
+       ret = gnutls_x509_privkey_init(&pkey);
+       if (ret < 0)
+               fail("gnutls_x509_privkey_init: %d\n", ret);
+
+       gnutls_x509_privkey_set_pin_function(pkey, good_pwd_cb, NULL);
+       key.data = (void *) key1;
+       key.size = sizeof(key1);
+       ret = gnutls_x509_privkey_import2(pkey, &key, GNUTLS_X509_FMT_PEM,
+                                         NULL, 0);
+       if (ret < 0) {
+               fail("gnutls_x509_privkey_import2 (good pin): %s\n",
+                    gnutls_strerror(ret));
+       }
+       gnutls_x509_privkey_deinit(pkey);
+
+       /* import_openssl NULL / callback bad => success */
+       ret = gnutls_x509_privkey_init(&pkey);
+       if (ret < 0)
+               fail("gnutls_x509_privkey_init: %d\n", ret);
+
+       gnutls_x509_privkey_set_pin_function(pkey, bad_pwd_cb, NULL);
+       key.data = (void *) key1;
+       key.size = sizeof(key1);
+       ret = gnutls_x509_privkey_import2(pkey, &key, GNUTLS_X509_FMT_PEM,
+                                         NULL, 0);
+       if (ret != GNUTLS_E_DECRYPTION_FAILED) {
+               fail("gnutls_x509_privkey_import2 (bad pin): %s\n",
+                    gnutls_strerror(ret));
+       }
+       gnutls_x509_privkey_deinit(pkey);
+
        gnutls_global_deinit();
 }