From: Nikos Mavrogiannopoulos Date: Fri, 13 Jul 2012 15:09:55 +0000 (+0200) Subject: Added ability to request PIN from a TPM URL. It uses the PKCS11 PIN function. X-Git-Tag: gnutls_3_1_0pre0~66 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=809678afeb247656c050b91afbe5f4c742df9514;p=thirdparty%2Fgnutls.git Added ability to request PIN from a TPM URL. It uses the PKCS11 PIN function. --- diff --git a/lib/gnutls_privkey.c b/lib/gnutls_privkey.c index de8061f5ab..2246cabe9d 100644 --- a/lib/gnutls_privkey.c +++ b/lib/gnutls_privkey.c @@ -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); } /** diff --git a/lib/gnutls_x509.c b/lib/gnutls_x509.c index daa4b26267..413fc34289 100644 --- a/lib/gnutls_x509.c +++ b/lib/gnutls_x509.c @@ -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); diff --git a/lib/includes/gnutls/abstract.h b/lib/includes/gnutls/abstract.h index 4c79e5aed8..754019993f 100644 --- a/lib/includes/gnutls/abstract.h +++ b/lib/includes/gnutls/abstract.h @@ -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); diff --git a/lib/libgnutls.map b/lib/libgnutls.map index 4192ae271c..f186b2531f 100644 --- a/lib/libgnutls.map +++ b/lib/libgnutls.map @@ -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 { diff --git a/lib/tpm.c b/lib/tpm.c index 0e9e3cc9f0..ecff8e4724 100644 --- 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(); diff --git a/src/certtool-common.c b/src/certtool-common.c index 4cd0452e42..f8c05bc839 100644 --- a/src/certtool-common.c +++ b/src/certtool-common.c @@ -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); } diff --git a/src/tpmtool.c b/src/tpmtool.c index be0d0bd91c..7f689b5208 100644 --- a/src/tpmtool.c +++ b/src/tpmtool.c @@ -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);