diff options
author | Denis Kenzior <denkenz@gmail.com> | 2018-10-09 17:49:28 +0100 |
---|---|---|
committer | James Morris <james.morris@microsoft.com> | 2018-10-26 09:30:47 +0100 |
commit | e73d170f6c77e7006b48c5e9c325fe520f6012ca (patch) | |
tree | cbff5f6905bdcb06e4dc497975736633fc91c507 /crypto/asymmetric_keys/asym_tpm.c | |
parent | e08e6891231f5fae82a6ffb4affdfa2ced8c1a77 (diff) | |
download | linux-e73d170f6c77e7006b48c5e9c325fe520f6012ca.tar.bz2 |
KEYS: asym_tpm: Implement tpm_sign [ver #2]
Signed-off-by: Denis Kenzior <denkenz@gmail.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Tested-by: Marcel Holtmann <marcel@holtmann.org>
Reviewed-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: James Morris <james.morris@microsoft.com>
Diffstat (limited to 'crypto/asymmetric_keys/asym_tpm.c')
-rw-r--r-- | crypto/asymmetric_keys/asym_tpm.c | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/crypto/asymmetric_keys/asym_tpm.c b/crypto/asymmetric_keys/asym_tpm.c index a38ba375675e..a5a5f913a74f 100644 --- a/crypto/asymmetric_keys/asym_tpm.c +++ b/crypto/asymmetric_keys/asym_tpm.c @@ -20,9 +20,11 @@ #define TPM_ORD_FLUSHSPECIFIC 186 #define TPM_ORD_LOADKEY2 65 #define TPM_ORD_UNBIND 30 +#define TPM_ORD_SIGN 60 #define TPM_LOADKEY2_SIZE 59 #define TPM_FLUSHSPECIFIC_SIZE 18 #define TPM_UNBIND_SIZE 63 +#define TPM_SIGN_SIZE 63 #define TPM_RT_KEY 0x00000001 @@ -190,6 +192,91 @@ static int tpm_unbind(struct tpm_buf *tb, } /* + * Sign a blob provided by userspace (that has had the hash function applied) + * using a specific key handle. The handle is assumed to have been previously + * loaded by e.g. LoadKey2. + * + * Note that the key signature scheme of the used key should be set to + * TPM_SS_RSASSAPKCS1v15_DER. This allows the hashed input to be of any size + * up to key_length_in_bytes - 11 and not be limited to size 20 like the + * TPM_SS_RSASSAPKCS1v15_SHA1 signature scheme. + */ +static int tpm_sign(struct tpm_buf *tb, + uint32_t keyhandle, unsigned char *keyauth, + const unsigned char *blob, uint32_t bloblen, + void *out, uint32_t outlen) +{ + unsigned char nonceodd[TPM_NONCE_SIZE]; + unsigned char enonce[TPM_NONCE_SIZE]; + unsigned char authdata[SHA1_DIGEST_SIZE]; + uint32_t authhandle = 0; + unsigned char cont = 0; + uint32_t ordinal; + uint32_t datalen; + int ret; + + ordinal = htonl(TPM_ORD_SIGN); + datalen = htonl(bloblen); + + /* session for loading the key */ + ret = oiap(tb, &authhandle, enonce); + if (ret < 0) { + pr_info("oiap failed (%d)\n", ret); + return ret; + } + + /* generate odd nonce */ + ret = tpm_get_random(NULL, nonceodd, TPM_NONCE_SIZE); + if (ret < 0) { + pr_info("tpm_get_random failed (%d)\n", ret); + return ret; + } + + /* calculate authorization HMAC value */ + ret = TSS_authhmac(authdata, keyauth, SHA1_DIGEST_SIZE, enonce, + nonceodd, cont, sizeof(uint32_t), &ordinal, + sizeof(uint32_t), &datalen, + bloblen, blob, 0, 0); + if (ret < 0) + return ret; + + /* build the request buffer */ + INIT_BUF(tb); + store16(tb, TPM_TAG_RQU_AUTH1_COMMAND); + store32(tb, TPM_SIGN_SIZE + bloblen); + store32(tb, TPM_ORD_SIGN); + store32(tb, keyhandle); + store32(tb, bloblen); + storebytes(tb, blob, bloblen); + store32(tb, authhandle); + storebytes(tb, nonceodd, TPM_NONCE_SIZE); + store8(tb, cont); + storebytes(tb, authdata, SHA1_DIGEST_SIZE); + + ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE); + if (ret < 0) { + pr_info("authhmac failed (%d)\n", ret); + return ret; + } + + datalen = LOAD32(tb->data, TPM_DATA_OFFSET); + + ret = TSS_checkhmac1(tb->data, ordinal, nonceodd, + keyauth, SHA1_DIGEST_SIZE, + sizeof(uint32_t), TPM_DATA_OFFSET, + datalen, TPM_DATA_OFFSET + sizeof(uint32_t), + 0, 0); + if (ret < 0) { + pr_info("TSS_checkhmac1 failed (%d)\n", ret); + return ret; + } + + memcpy(out, tb->data + TPM_DATA_OFFSET + sizeof(uint32_t), + min(datalen, outlen)); + + return datalen; +} +/* * Maximum buffer size for the BER/DER encoded public key. The public key * is of the form SEQUENCE { INTEGER n, INTEGER e } where n is a maximum 2048 * bit key and e is usually 65537 |