]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Added ability to request PIN from a TPM URL. It uses the PKCS11 PIN function.
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Fri, 13 Jul 2012 15:09:55 +0000 (17:09 +0200)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Fri, 13 Jul 2012 15:09:55 +0000 (17:09 +0200)
lib/gnutls_privkey.c
lib/gnutls_x509.c
lib/includes/gnutls/abstract.h
lib/libgnutls.map
lib/tpm.c
src/certtool-common.c
src/tpmtool.c

index de8061f5ab9eef03c1e152cad22c46eedcf235c5..2246cabe9d3d8609b6122949fab8c862a6a8f47a 100644 (file)
@@ -400,27 +400,8 @@ gnutls_privkey_import_ext (gnutls_privkey_t pkey,
                            gnutls_privkey_decrypt_func decrypt_func,
                            unsigned int flags)
 {
-int ret;
-
-  ret = check_if_clean(pkey);
-  if (ret < 0)
-    {
-      gnutls_assert();
-      return ret;
-    }
-  
-  if (sign_func == NULL && decrypt_func == NULL)
-    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
-
-  pkey->key.ext.sign_func = sign_func;
-  pkey->key.ext.decrypt_func = decrypt_func;
-  pkey->key.ext.deinit_func = NULL;
-  pkey->key.ext.userdata = userdata;
-  pkey->type = GNUTLS_PRIVKEY_EXT;
-  pkey->pk_algorithm = pk;
-  pkey->flags = flags;
-
-  return 0;
+  return gnutls_privkey_import_ext2( pkey, pk, userdata, sign_func, decrypt_func,
+                                     NULL, flags);
 }
 
 /**
index daa4b262677dfeae668415a457ef841c0648fd96..413fc34289a0ab40a270cfdb6b2a073dea76103f 100644 (file)
@@ -566,7 +566,7 @@ read_key_mem (gnutls_certificate_credentials_t res,
   return 0;
 }
 
-#ifdef ENABLE_TROUSERS
+#ifdef HAVE_TROUSERS
 /* Reads a private key from a token.
  */
 static int
@@ -586,7 +586,7 @@ read_key_tpmurl (gnutls_certificate_credentials_t res, const char *url)
     }
 
   ret =
-    gnutls_privkey_import_tpm_url (pkey, url, NULL, NULL);
+    gnutls_privkey_import_tpm_url (pkey, url, NULL, NULL, 0);
   if (ret < 0)
     {
       gnutls_assert ();
@@ -872,12 +872,12 @@ read_key_file (gnutls_certificate_credentials_t res,
     }
 #endif /* ENABLE_PKCS11 */
 
-#ifdef ENABLE_TROUSERS
+#ifdef HAVE_TROUSERS
   if (strncmp (keyfile, "tpmkey:", 7) == 0)
     {
       return read_key_tpmurl (res, keyfile);
     }
-#endif /* ENABLE_TROUSERS */
+#endif /* HAVE_TROUSERS */
 
   data = read_binary_file (keyfile, &size);
 
index 4c79e5aed86c3d3320b5f3d4fd73145b82be2647..754019993f56b3cae1256e8e0f7bf8af05e65b79 100644 (file)
@@ -71,7 +71,8 @@ gnutls_pubkey_import_privkey (gnutls_pubkey_t key, gnutls_privkey_t pkey,
 int
 gnutls_pubkey_import_tpm_url (gnutls_pubkey_t pkey,
                               const char* url,
-                              const char *srk_password);
+                              const char *srk_password,
+                              unsigned int flags);
 
 int
 gnutls_pubkey_import_tpm_raw (gnutls_pubkey_t pkey,
@@ -208,7 +209,8 @@ gnutls_privkey_import_tpm_raw (gnutls_privkey_t pkey,
 
 int
 gnutls_privkey_import_tpm_url (gnutls_privkey_t pkey,
-          const char* url, const char *srk_password, const char *key_password);
+          const char* url, const char *srk_password, const char *key_password,
+          unsigned int flags);
 
 int gnutls_privkey_import_pkcs11_url (gnutls_privkey_t key, const char *url);
 
index 4192ae271c1a843c9f9f12ef3312a5b3257622f6..f186b2531f7d276f1fc2860e37761277ac2f8210 100644 (file)
@@ -816,6 +816,7 @@ GNUTLS_3_1_0 {
        gnutls_tpm_get_registered;
        gnutls_tpm_privkey_delete;
        gnutls_pubkey_import_tpm_url;
+       gnutls_privkey_import_tpm_url;
 } GNUTLS_3_0_0;
 
 GNUTLS_PRIVATE {
index 0e9e3cc9f09d96df43f3e5ba67d8f5b090d346dc..ecff8e47241f2201cc9d3fc60e69e954484afb86 100644 (file)
--- a/lib/tpm.c
+++ b/lib/tpm.c
@@ -64,6 +64,7 @@ static int import_tpm_key (gnutls_privkey_t pkey,
                            TSS_UUID *uuid,
                            const char *srk_password,
                            const char *key_password);
+static int encode_tpmkey_url(char** url, const TSS_UUID* uuid, const TSS_UUID* parent);
 
 /* TPM URL format:
  *
@@ -161,7 +162,7 @@ tpm_sign_fn (gnutls_privkey_t key, void *_s,
        _gnutls_debug_log ("TPM hash signature failed: %s\n",
                           Trspi_Error_String (err));
       if (err == TPM_E_AUTHFAIL)
-       return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+       return GNUTLS_E_TPM_KEY_PASSWORD_ERROR;
       else
        return GNUTLS_E_PK_SIGN_FAILED;
     }
@@ -169,8 +170,69 @@ tpm_sign_fn (gnutls_privkey_t key, void *_s,
 }
 
 static const unsigned char nullpass[20];
+static const gnutls_datum_t nulldata = {(void*)nullpass, 20};
 const TSS_UUID srk_uuid = TSS_UUID_SRK;
 
+static int tpm_pin(const TSS_UUID* uuid, char* pin, unsigned int pin_size, 
+                   unsigned int attempts)
+{
+unsigned int flags = 0;
+const char* label;
+char* url = NULL;
+int ret;
+
+  if (attempts > 0) 
+    flags |= GNUTLS_PKCS11_PIN_WRONG;
+    
+  if (uuid)
+    {
+      if (memcmp(uuid, &srk_uuid, sizeof(TSS_UUID)) == 0)
+        label = "SRK";
+      else
+        {
+          ret = encode_tpmkey_url(&url, uuid, NULL);
+          if (ret < 0)
+            return gnutls_assert_val(ret);
+          
+          label = url;
+        }
+    }
+  else
+    label = "unknown";
+
+  ret = _gnutls_pin_func(_gnutls_pin_data, attempts, "TPM", label, flags, pin, pin_size);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      goto cleanup;
+    }
+  
+  ret = 0;
+cleanup:
+  gnutls_free(url);
+  return ret;
+}
+
+
+static TSS_RESULT myTspi_Policy_SetSecret(TSS_HPOLICY hPolicy, 
+                                          UINT32 ulSecretLength, BYTE* rgbSecret)
+{
+  if (rgbSecret == NULL)
+    {
+      /* Well known NULL key */
+      return Tspi_Policy_SetSecret (hPolicy,
+                                  TSS_SECRET_MODE_SHA1,
+                                   sizeof (nullpass), (BYTE *) nullpass);
+    }
+  else /* key is given */
+    {
+      return Tspi_Policy_SetSecret (hPolicy, TSS_SECRET_MODE_PLAIN,
+                                    ulSecretLength, rgbSecret);
+    }
+}
+
+#define SAFE_LEN(x) (x==NULL?0:strlen(x))
+
 static int tpm_open_session(struct tpm_ctx_st *s, const char* srk_password)
 {
 int err, ret;
@@ -208,14 +270,8 @@ int err, ret;
       goto out_srk;
     }
 
-  if (srk_password)
-    err = Tspi_Policy_SetSecret (s->srk_policy,
-                                TSS_SECRET_MODE_PLAIN,
-                                strlen (srk_password), (BYTE *) srk_password);
-  else                         /* Well-known NULL key */
-    err = Tspi_Policy_SetSecret (s->srk_policy,
-                                TSS_SECRET_MODE_SHA1,
-                                sizeof (nullpass), (BYTE *) nullpass);
+  err = myTspi_Policy_SetSecret (s->srk_policy,
+                                SAFE_LEN (srk_password), (BYTE *) srk_password);
   if (err)
     {
       gnutls_assert ();
@@ -250,6 +306,56 @@ static void tpm_close_session(struct tpm_ctx_st *s)
   s->tpm_ctx = 0;
 }
 
+static int
+import_tpm_key_cb (gnutls_privkey_t pkey,
+                const gnutls_datum_t * fdata,
+                gnutls_x509_crt_fmt_t format,
+                TSS_UUID *uuid,
+                const char *srk_password,
+                const char *key_password)
+{
+unsigned int attempts = 0;
+char pin1[GNUTLS_PKCS11_MAX_PIN_LEN];
+char pin2[GNUTLS_PKCS11_MAX_PIN_LEN];
+int ret, ret2;
+
+  do
+    {
+      ret = import_tpm_key(pkey, fdata, format, uuid, srk_password, key_password);
+
+      if (attempts > 3 || _gnutls_pin_func == NULL)
+        break;
+
+      if (ret == GNUTLS_E_TPM_SRK_PASSWORD_ERROR)
+        {
+          ret2 = tpm_pin(&srk_uuid, pin1, sizeof(pin1), attempts++);
+          if (ret2 < 0)
+            {
+              gnutls_assert();
+              return GNUTLS_E_TPM_SRK_PASSWORD_ERROR;
+            }
+          srk_password = pin1;
+        }
+
+      if (ret == GNUTLS_E_TPM_KEY_PASSWORD_ERROR)
+        {
+          ret2 = tpm_pin(uuid, pin2, sizeof(pin2), attempts++);
+          if (ret2 < 0)
+            {
+              gnutls_assert();
+              return GNUTLS_E_TPM_KEY_PASSWORD_ERROR;
+            }
+          key_password = pin2;
+        }
+    }
+  while(ret == GNUTLS_E_TPM_KEY_PASSWORD_ERROR || ret == GNUTLS_E_TPM_SRK_PASSWORD_ERROR);
+
+  if (ret < 0)
+    gnutls_assert();
+  return ret;
+}
+
+
 static int
 import_tpm_key (gnutls_privkey_t pkey,
                 const gnutls_datum_t * fdata,
@@ -303,20 +409,9 @@ import_tpm_key (gnutls_privkey_t pkey,
                                         asn1.size, asn1.data, &s->tpm_key);
       if (err != 0)
         {
-          if (srk_password)
-            {
-              gnutls_assert ();
-              _gnutls_debug_log
-                  ("Failed to load TPM key blob: %s\n",
-                   Trspi_Error_String (err));
-            }
-
-          if (err)
-            {
-              gnutls_assert ();
-              ret = tss_err(err);
-              goto out_blob;
-            }
+          gnutls_assert ();
+          ret = tss_err(err);
+          goto out_blob;
         }
     }
   else if (uuid)
@@ -348,8 +443,8 @@ import_tpm_key (gnutls_privkey_t pkey,
     }
 
   ret =
-      gnutls_privkey_sign_data (pkey, GNUTLS_DIG_SHA1, 0, fdata, &tmp_sig);
-  if (ret == GNUTLS_E_INSUFFICIENT_CREDENTIALS)
+      gnutls_privkey_sign_data (pkey, GNUTLS_DIG_SHA1, 0, &nulldata, &tmp_sig);
+  if (ret == GNUTLS_E_TPM_KEY_PASSWORD_ERROR)
     {
       if (!s->tpm_key_policy)
        {
@@ -378,9 +473,8 @@ import_tpm_key (gnutls_privkey_t pkey,
            }
        }
 
-      err = Tspi_Policy_SetSecret (s->tpm_key_policy,
-                                  TSS_SECRET_MODE_PLAIN,
-                                  strlen (key_password), (void *) key_password);
+      err = myTspi_Policy_SetSecret (s->tpm_key_policy,
+                                    SAFE_LEN(key_password), (void *) key_password);
 
       if (err)
        {
@@ -442,7 +536,7 @@ gnutls_privkey_import_tpm_raw (gnutls_privkey_t pkey,
                               const char *srk_password,
                               const char *key_password)
 {
-  return import_tpm_key(pkey, fdata, format, NULL, srk_password, key_password);
+  return import_tpm_key_cb(pkey, fdata, format, NULL, srk_password, key_password);
 }
 
 struct tpmkey_url_st
@@ -689,6 +783,7 @@ cleanup:
  * @url: The URL of the TPM key to be imported
  * @srk_password: The password for the SRK key (optional)
  * @key_password: A password for the key (optional)
+ * @flags: should be zero
  *
  * This function will import the given private key to the abstract
  * #gnutls_privkey_t structure. If a password is needed to access
@@ -707,7 +802,8 @@ int
 gnutls_privkey_import_tpm_url (gnutls_privkey_t pkey,
                                const char* url,
                                const char *srk_password,
-                               const char *key_password)
+                               const char *key_password,
+                               unsigned int flags)
 {
 struct tpmkey_url_st durl;
 gnutls_datum_t fdata = { NULL, 0 };
@@ -719,7 +815,6 @@ int ret;
 
   if (durl.filename)
     {
-
       ret = gnutls_load_file(durl.filename, &fdata);
       if (ret < 0)
         {
@@ -737,7 +832,7 @@ int ret;
     }
   else if (durl.uuid_set)
     {
-      ret = import_tpm_key (pkey, NULL, 0, &durl.uuid, srk_password, key_password);
+      ret = import_tpm_key_cb (pkey, NULL, 0, &durl.uuid, srk_password, key_password);
       if (ret < 0)
         {
           gnutls_assert();
@@ -804,6 +899,7 @@ int ret;
 }
 
 
+
 static int
 import_tpm_pubkey (gnutls_pubkey_t pkey,
                    const gnutls_datum_t * fdata,
@@ -894,6 +990,43 @@ out_session:
   return ret;
 }
 
+static int
+import_tpm_pubkey_cb (gnutls_pubkey_t pkey,
+                   const gnutls_datum_t * fdata,
+                   gnutls_x509_crt_fmt_t format,
+                   TSS_UUID *uuid,
+                   const char *srk_password)
+{
+unsigned int attempts = 0;
+char pin1[GNUTLS_PKCS11_MAX_PIN_LEN];
+int ret;
+
+  
+  do
+    {
+      ret = import_tpm_pubkey(pkey, fdata, format, uuid, srk_password);
+      
+      if (attempts > 3 || _gnutls_pin_func == NULL)
+        break;
+
+      if (ret == GNUTLS_E_TPM_SRK_PASSWORD_ERROR)
+        {
+          ret = tpm_pin(&srk_uuid, pin1, sizeof(pin1), attempts++);
+          if (ret < 0)
+            {
+              gnutls_assert();
+              return GNUTLS_E_TPM_SRK_PASSWORD_ERROR;
+            }
+          srk_password = pin1;
+        }
+    }
+  while(ret == GNUTLS_E_TPM_SRK_PASSWORD_ERROR);
+
+  if (ret < 0)
+    gnutls_assert();
+  return ret;
+}
+
 
 /**
  * gnutls_pubkey_import_tpm_raw:
@@ -920,7 +1053,7 @@ gnutls_pubkey_import_tpm_raw (gnutls_pubkey_t pkey,
                               gnutls_x509_crt_fmt_t format,
                               const char *srk_password)
 {
-  return import_tpm_pubkey(pkey, fdata, format, NULL, srk_password);
+  return import_tpm_pubkey_cb(pkey, fdata, format, NULL, srk_password);
 }
 
 /**
@@ -928,6 +1061,7 @@ gnutls_pubkey_import_tpm_raw (gnutls_pubkey_t pkey,
  * @pkey: The public key
  * @url: The URL of the TPM key to be imported
  * @srk_password: The password for the SRK key (optional)
+ * @flags: should be zero
  *
  * This function will import the given private key to the abstract
  * #gnutls_privkey_t structure. If a password is needed to access
@@ -943,7 +1077,8 @@ gnutls_pubkey_import_tpm_raw (gnutls_pubkey_t pkey,
 int
 gnutls_pubkey_import_tpm_url (gnutls_pubkey_t pkey,
                               const char* url,
-                              const char *srk_password)
+                              const char *srk_password,
+                              unsigned int flags)
 {
 struct tpmkey_url_st durl;
 gnutls_datum_t fdata = { NULL, 0 };
@@ -973,7 +1108,7 @@ int ret;
     }
   else if (durl.uuid_set)
     {
-      ret = import_tpm_pubkey (pkey, NULL, 0, &durl.uuid, srk_password);
+      ret = import_tpm_pubkey_cb (pkey, NULL, 0, &durl.uuid, srk_password);
       if (ret < 0)
         {
           gnutls_assert();
@@ -1091,8 +1226,8 @@ struct tpm_ctx_st s;
           goto err_sa;
         }
 
-      tssret = Tspi_Policy_SetSecret(key_policy, TSS_SECRET_MODE_PLAIN
-                                     strlen(key_password), (void*)key_password);
+      tssret = myTspi_Policy_SetSecret(key_policy
+                                       SAFE_LEN(key_password), (void*)key_password);
       if (tssret != 0)
         {
           gnutls_assert();
index 4cd0452e42c25f6002f9d46e9970b8e45e3eaa39..f8c05bc83901f2601f4cbfdb289441cb97b00a32 100644 (file)
@@ -144,6 +144,27 @@ gnutls_x509_privkey_t xkey;
   return key;
 }
 
+#ifdef HAVE_TROUSERS
+
+static gnutls_privkey_t _load_tpm_privkey(const char* url)
+{
+int ret;
+gnutls_privkey_t key;
+
+  ret = gnutls_privkey_init (&key);
+  if (ret < 0)
+    error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret));
+
+  ret = gnutls_privkey_import_tpm_url(key, url, NULL, NULL, 0);
+  if (ret < 0)
+    error (EXIT_FAILURE, 0, "importing TPM key: %s: %s",
+           url, gnutls_strerror (ret));
+
+  return key;
+}
+
+#endif
+
 #ifdef ENABLE_PKCS11
 
 static gnutls_privkey_t _load_pkcs11_privkey(const char* url)
@@ -280,6 +301,11 @@ load_private_key (int mand, common_info_st * info)
     return _load_pkcs11_privkey(info->privkey);
 #endif
 
+#ifdef HAVE_TROUSERS
+  if (strncmp(info->privkey, "tpmkey:", 7) == 0)
+    return _load_tpm_privkey(info->privkey);
+#endif
+
   dat.data = (void*)read_binary_file (info->privkey, &size);
   dat.size = size;
 
@@ -489,6 +515,11 @@ load_ca_private_key (common_info_st * info)
     return _load_pkcs11_privkey(info->ca_privkey);
 #endif
 
+#ifdef HAVE_TROUSERS
+  if (strncmp(info->privkey, "tpmkey:", 7) == 0)
+    return _load_tpm_privkey(info->privkey);
+#endif
+
   dat.data = (void*)read_binary_file (info->ca_privkey, &size);
   dat.size = size;
 
@@ -596,9 +627,8 @@ int ret;
     error (EXIT_FAILURE, 0, "gnutls_pubkey_init: %s",
            gnutls_strerror (ret));
 
-  ret = gnutls_pubkey_import_privkey(pubkey, privkey, 0, 0);
-  if (ret < 0) /* could not get (e.g. on PKCS #11 */
-    {
+  if (!privkey || (ret = gnutls_pubkey_import_privkey(pubkey, privkey, 0, 0)) < 0)
+    { /* could not get (e.g. on PKCS #11 */
       gnutls_pubkey_deinit(pubkey);
       return load_pubkey(mand, info);
     }
index be0d0bd91c76e665ffe3e39f8869a171e4501050..7f689b5208ede1d7c05db91af74624675e1f6867 100644 (file)
@@ -247,7 +247,7 @@ static void tpm_pubkey(const char* url, FILE* outfile)
 
   gnutls_pubkey_init(&pubkey);
 
-  ret = gnutls_pubkey_import_tpm_url(pubkey, url, srk_pass);
+  ret = gnutls_pubkey_import_tpm_url(pubkey, url, srk_pass, 0);
 
   free(srk_pass);