[PATCH v4 2/7] tpm2-sessions: Add full HMAC and encrypt/decrypt session handling

Ard Biesheuvel ard.biesheuvel at linaro.org
Tue Oct 23 10:08:24 UTC 2018


On 23 October 2018 at 04:01, James Bottomley
<James.Bottomley at hansenpartnership.com> wrote:
> On Mon, 2018-10-22 at 19:19 -0300, Ard Biesheuvel wrote:
> [...]
>> > +static void hmac_init(struct shash_desc *desc, u8 *key, int
>> > keylen)
>> > +{
>> > +       u8 pad[SHA256_BLOCK_SIZE];
>> > +       int i;
>> > +
>> > +       desc->tfm = sha256_hash;
>> > +       desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
>>
>> I don't think this actually does anything in the shash API
>> implementation, so you can drop this.
>
> OK, I find crypto somewhat hard to follow.  There were bits I had to
> understand, like when I wrote the CFB implementation or when I fixed
> the ECDH scatterlist handling, but I've got to confess, in time
> honoured tradition I simply copied this from EVM crypto without
> actually digging into the code to understand why.
>

Yeah, it is notoriously hard to use, and we should try to improve that.

>>  However, I take it this means that hmac_init() is never called in
>> contexts where sleeping is not allowed? For the relevance of that,
>> please see below.
>
> Right, these routines are always called as an adjunct to a TPM
> operation and TPM operations can sleep, so we must at least have kernel
> thread context.
>
> [...]
>> > +       /* encrypt before HMAC */
>> > +       if (auth->attrs & TPM2_SA_DECRYPT) {
>> > +               struct scatterlist sg[1];
>> > +               u16 len;
>> > +               SKCIPHER_REQUEST_ON_STACK(req, auth->aes);
>> > +
>> > +               skcipher_request_set_tfm(req, auth->aes);
>> > +               skcipher_request_set_callback(req,
>> > CRYPTO_TFM_REQ_MAY_SLEEP,
>> > +                                             NULL, NULL);
>> > +
>>
>> Your crypto_alloc_skcipher() call [further down] does not mask out
>> CRYPTO_ALG_ASYNC, and so it permits asynchronous implementations to
>> be selected. Your generic cfb template only permits synchronous
>> implementations, since it wraps the cipher directly (which is always
>> synchronous). However, we have support in the tree for some
>> accelerators that implement cfb(aes), and those will return
>> -EINPROGRESS when invoking crypto_skcipher_en/decrypt(req), which you
>> are not set up to handle.
>>
>> So the simple solution is to call 'crypto_alloc_skcipher("cfb(aes)",
>> 0, CRYPTO_ALG_ASYNC)' below instead.
>>
>> However, I would prefer it if we permit asynchronous skciphers here.
>> The reason is that, on a given platform, the accelerator may be the
>> only truly time invariant AES implementation that is available, and
>> since we are dealing with the TPM, a bit of paranoia does not hurt.
>> It also makes it easier to implement it as a [time invariant] SIMD
>> based asynchronous skcipher, which are simpler than synchronous ones
>> since they don't require a non-SIMD fallback path for calls from
>> contexts where the SIMD unit may not be used.
>>
>> I have already implemented cfb(aes) for arm64/NEON. I will post the
>> patch after the merge window closes.
>>
>> > +               /* need key and IV */
>> > +               KDFa(auth->session_key, SHA256_DIGEST_SIZE
>> > +                    + auth->passphraselen, "CFB", auth->our_nonce,
>> > +                    auth->tpm_nonce, AES_KEYBYTES +
>> > AES_BLOCK_SIZE,
>> > +                    auth->scratch);
>> > +               crypto_skcipher_setkey(auth->aes, auth->scratch,
>> > AES_KEYBYTES);
>> > +               len = tpm_get_inc_u16(&p);
>> > +               sg_init_one(sg, p, len);
>> > +               skcipher_request_set_crypt(req, sg, sg, len,
>> > +                                          auth->scratch +
>> > AES_KEYBYTES);
>> > +               crypto_skcipher_encrypt(req);
>>
>> So please consider replacing this with something like.
>>
>> DECLARE_CRYPTO_WAIT(wait); [further up]
>> skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP,
>>                               crypto_req_done, &wait);
>> crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
>
> Sure, I can do this ... the crypto skcipher handling was also cut and
> paste, but I forget where from this time.  So what I think you're
> asking for is below as the incremental diff?  I've tested this out and
> it all works fine in my session testing environment (and on my real
> laptop) ... although since I'm fully sync, I won't really have tested
> the -EINPROGRESS do the wait case.
>

Yes that looks fine. I will try to test this on one of my arm64
systems, but it may take me some time to get around to it.

In any case,

Reviewed-by: Ard Biesheuvel <ard.biesheuvel at linaro.org> # crypto API parts

>
> diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c
> index 422c3ec64f8c..bbd3e8580954 100644
> --- a/drivers/char/tpm/tpm2-sessions.c
> +++ b/drivers/char/tpm/tpm2-sessions.c
> @@ -165,7 +165,6 @@ static void hmac_init(struct shash_desc *desc, u8 *key, int keylen)
>         int i;
>
>         desc->tfm = sha256_hash;
> -       desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
>         crypto_shash_init(desc);
>         for (i = 0; i < sizeof(pad); i++) {
>                 if (i < keylen)
> @@ -244,7 +243,6 @@ static void KDFe(u8 z[EC_PT_SZ], const char *str, u8 *pt_u, u8 *pt_v,
>         __be32 c = cpu_to_be32(1);
>
>         desc->tfm = sha256_hash;
> -       desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
>
>         crypto_shash_init(desc);
>         /* counter (BE) */
> @@ -445,7 +443,6 @@ void tpm_buf_fill_hmac_session(struct tpm_buf *buf, struct tpm2_auth *auth)
>         auth->ordinal = head->ordinal;
>
>         desc->tfm = sha256_hash;
> -       desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
>
>         cc = be32_to_cpu(head->ordinal);
>
> @@ -514,10 +511,11 @@ void tpm_buf_fill_hmac_session(struct tpm_buf *buf, struct tpm2_auth *auth)
>                 struct scatterlist sg[1];
>                 u16 len;
>                 SKCIPHER_REQUEST_ON_STACK(req, auth->aes);
> +               DECLARE_CRYPTO_WAIT(wait);
>
>                 skcipher_request_set_tfm(req, auth->aes);
>                 skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP,
> -                                             NULL, NULL);
> +                                             crypto_req_done, &wait);
>
>                 /* need key and IV */
>                 KDFa(auth->session_key, SHA256_DIGEST_SIZE
> @@ -529,7 +527,7 @@ void tpm_buf_fill_hmac_session(struct tpm_buf *buf, struct tpm2_auth *auth)
>                 sg_init_one(sg, p, len);
>                 skcipher_request_set_crypt(req, sg, sg, len,
>                                            auth->scratch + AES_KEYBYTES);
> -               crypto_skcipher_encrypt(req);
> +               crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
>                 /* reset p to beginning of parameters for HMAC */
>                 p -= 2;
>         }
> @@ -755,7 +753,6 @@ int tpm_buf_check_hmac_response(struct tpm_buf *buf, struct tpm2_auth *auth,
>          * with rphash
>          */
>         desc->tfm = sha256_hash;
> -       desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
>         crypto_shash_init(desc);
>         /* yes, I know this is now zero, but it's what the standard says */
>         crypto_shash_update(desc, (u8 *)&head->return_code,
> @@ -786,10 +783,11 @@ int tpm_buf_check_hmac_response(struct tpm_buf *buf, struct tpm2_auth *auth,
>         if (auth->attrs & TPM2_SA_ENCRYPT) {
>                 struct scatterlist sg[1];
>                 SKCIPHER_REQUEST_ON_STACK(req, auth->aes);
> +               DECLARE_CRYPTO_WAIT(wait);
>
>                 skcipher_request_set_tfm(req, auth->aes);
>                 skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP,
> -                                             NULL, NULL);
> +                                             crypto_req_done, &wait);
>
>                 /* need key and IV */
>                 KDFa(auth->session_key, SHA256_DIGEST_SIZE
> @@ -801,7 +799,7 @@ int tpm_buf_check_hmac_response(struct tpm_buf *buf, struct tpm2_auth *auth,
>                 sg_init_one(sg, p, len);
>                 skcipher_request_set_crypt(req, sg, sg, len,
>                                            auth->scratch + AES_KEYBYTES);
> -               crypto_skcipher_decrypt(req);
> +               crypto_wait_req(crypto_skcipher_decrypt(req), &wait);
>         }
>
>   out:
> @@ -965,7 +963,6 @@ static int parse_create_primary(struct tpm_chip *chip, u8 *data)
>         tmp = resp;
>         /* now we have the public area, compute the name of the object */
>         desc->tfm = sha256_hash;
> -       desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
>         put_unaligned_be16(TPM2_ALG_SHA256, chip->tpmkeyname);
>         crypto_shash_init(desc);
>         crypto_shash_update(desc, resp, len);



More information about the Linux-security-module-archive mailing list