Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor AES context to be shallow-copyable #5896

Merged
merged 5 commits into from
Jul 20, 2022

Conversation

wernerlewis
Copy link
Contributor

@wernerlewis wernerlewis commented Jun 7, 2022

Description

Replaces use of a round key pointer in mbedtls_aes_context with a buffer offset, so that the structure is shallow-copyable. This retains support for alignment requirements with PadLock, removal of rk results in an ABI change. A test is added to confirm a shallow-copy of the structure is valid. Fixes #2147.

Status

READY

Requires Backporting

NO

Todos

  • Tests
  • Changelog updated

Steps to test or reproduce

Initialise an mbedtls_aes_context structure, set encryption keys and then encrypt plaintext. Shallow-copy and then zero the original context, and then repeat encryption of the same plaintext using the copied context. The two ciphertexts should match, but will not prior to this change.
A similar test has been added in this PR.

@wernerlewis wernerlewis added bug needs-review Every commit must be reviewed by at least two team members, component-crypto Crypto primitives and low-level interfaces labels Jun 8, 2022
@daverodgman daverodgman added the priority-medium Medium priority - this can be reviewed as time permits label Jun 8, 2022
@paul-elliott-arm paul-elliott-arm self-requested a review June 9, 2022 10:14
Copy link
Contributor

@gilles-peskine-arm gilles-peskine-arm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks mostly good, just a couple of minor points.

library/aes.c Outdated
else
#endif
ctx->rk = RK = ctx->buf;
ctx->rk_offset = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is not indented correctly. The indentation should reflect the fact that ctx->rk_offset = 0; is not executed if aes_padlock_ace is nonzero (whereas the assignment to RK is unconditional).

When we have an interaction between preprocessor nesting and instruction nesting, I prefer to arrange for the indentation to be correct if you hide the disabled preprocessor directives. For if/else, with our brace style, this can be done by putting the “either else or sole code path” line in braces:

#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_PADLOCK_ALIGN16)
    if( aes_padlock_ace == -1 )
        aes_padlock_ace = mbedtls_padlock_has_support( MBEDTLS_PADLOCK_ACE );

    if( aes_padlock_ace )
        ctx->rk_offset = MBEDTLS_PADLOCK_ALIGN16( ctx->buf ) - ctx->buf;
    else
#endif
    {
        ctx->rk_offset = 0;
    }
    RK = ctx->buf + ctx->rk_offset;

But in fact I would find this code more readable as

    ctx->rk_offset = 0;
#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_PADLOCK_ALIGN16)
    if( aes_padlock_ace == -1 )
        aes_padlock_ace = mbedtls_padlock_has_support( MBEDTLS_PADLOCK_ACE );

    if( aes_padlock_ace )
        ctx->rk_offset = MBEDTLS_PADLOCK_ALIGN16( ctx->buf ) - ctx->buf;
#endif
    RK = ctx->buf + ctx->rk_offset;

Same thing in setkey_dec.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the information on indentation in this case, I've updated to use the latter formatting.

@@ -80,7 +80,7 @@ extern "C" {
typedef struct mbedtls_aes_context
{
int MBEDTLS_PRIVATE(nr); /*!< The number of rounds. */
uint32_t *MBEDTLS_PRIVATE(rk); /*!< AES round keys. */
size_t MBEDTLS_PRIVATE(rk_offset); /*!< Buffer offset for AES round keys. */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please document the unit. Both bytes and array elements (which is uint32_t) are plausible. Turns out the offset is a number of array elements.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if I follow the logic here - isn't this just a 16-byte alignment offset kept along an unaligned buffer, so bytes?

Copy link
Contributor

@tom-cosgrove-arm tom-cosgrove-arm Jul 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, rk_offset is the difference between two uint32_t *s. I agree the name MBEDTLS_PADLOCK_ALIGN16 doesn't make it clear, but it includes a cast to uint32_t *.

See

library/padlock.h:#define MBEDTLS_PADLOCK_ALIGN16(x) (uint32_t *) (16 + ((int32_t) (x) & ~15))

library/aes.c:ctx->rk_offset = MBEDTLS_PADLOCK_ALIGN16( ctx->buf ) - ctx->buf;

and

library/aes.c:RK = ctx->buf + ctx->rk_offset;

Copy link
Contributor

@AndrzejKurek AndrzejKurek Jul 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, but even though this is a difference between two uint32_t's, this contains an address offset aligned to 16 bytes, and the result of MBEDTLS_PADLOCK_ALIGN16( buf ) - buf can be at most 16.
For uint32_t elements, this means that it's at most an offset of half of an element, not the number of elements. ctx->rk_offset is not used when accesing a specific index of RK, where I would interpret it as an offset of given array elements.
Again - what am I missing here?
Edit: Sorry, mixed up the sizes here. It can be up to 16 bytes, while the elements have 4 bytes, so if it was to be used as a number of array elements, it should rather be divided by 4.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Err, yes, (char *)MBEDTLS_PADLOCK_ALIGN16( buf ) - (char *)buf will be 0, 4, 8 or 12 bytes, but MBEDTLS_PADLOCK_ALIGN16( buf ) - buf will be 0, 1, 2 or 3.

this is a difference between two uint32_t's

It's actually the difference between two uint32_t *s.

If buf (i.e. &buf[0]) is at (vaddr_t)1000 (decimal), &buf[1] is at 1004, &buf[2] is at 1008 and &buf[3] is at 1012, MBEDTLS_PADLOCK_ALIGN16(buf) will give us (uint32_t *)1008, which will give us 2 - the third one in the list) when we subtract buf from it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All clear, I failed at pointer-land arithmetics :) Sorry for taking so long to realize!

// Encrypt with copied context and decrypt
TEST_ASSERT( mbedtls_aes_crypt_ecb( &ctx2, MBEDTLS_AES_ENCRYPT,
src_str->x, output2 ) == 0 );
TEST_ASSERT( mbedtls_aes_setkey_dec( &ctx2, key_str->x,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're testing the sequence {setkey_enc; move; crypt}, and the sequence {init; move; setkey_enc}, but not the sequence {setkey_dec; move; crypt}. Since the problematic code is present in both setkey_enc and setkey_dec, we should test both, i.e. move the context after setkey_dec.

The sequence {init; move; setkey} is not particularly risky since setkey is unlikely to have a flaw where it would depend on previous content: that bug would be likely to hit on a freshly initialized context too. We can test it just in case, but I don't think it's required.

@gilles-peskine-arm
Copy link
Contributor

On code inspection, I believe that VIA padlock support (which was the reason for the offset due to its alignment constraint) is preserved. However we do not have the hardware to test it. I sent a message to the mailing list to let people know and ask for someone to test it if they can.

@gilles-peskine-arm
Copy link
Contributor

Please address review comments with subsequent commits (one commit for each unrelated change), not by rewriting old commits.

@gilles-peskine-arm gilles-peskine-arm added needs-work and removed needs-review Every commit must be reviewed by at least two team members, labels Jun 9, 2022
@gilles-peskine-arm
Copy link
Contributor

The latest commits are missing a signoff line.

git rebase --signoff -i HEAD~3

wernerlewis and others added 4 commits June 29, 2022 16:17
Replace RK pointer in AES context with a buffer offset, to allow
shallow copying. Fixes Mbed-TLS#2147.

Signed-off-by: Werner Lewis <werner.lewis@arm.com>
Signed-off-by: Werner Lewis <werner.lewis@arm.com>
Signed-off-by: Werner Lewis <werner.lewis@arm.com>
Signed-off-by: Werner Lewis <werner.lewis@arm.com>
Copy link
Member

@paul-elliott-arm paul-elliott-arm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

Re-iterating previous comment about adding new commits to address review comments, rather than re-writing and force pushing.

@AndrzejKurek AndrzejKurek self-requested a review July 1, 2022 12:48
AndrzejKurek
AndrzejKurek previously approved these changes Jul 4, 2022
Copy link
Contributor

@AndrzejKurek AndrzejKurek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good apart from the one minor comment that I'm not sure about.

@tom-cosgrove-arm tom-cosgrove-arm added approved Design and code approved - may be waiting for CI or backports needs-backports Backports are missing or are pending review and approval. and removed needs-work labels Jul 4, 2022
@tom-cosgrove-arm
Copy link
Contributor

tom-cosgrove-arm commented Jul 4, 2022

Since we normally backport bug fixes, should we backport this one?

@tom-cosgrove-arm
Copy link
Contributor

Answer: no backport, as it would break the ABI on LTS, which we try hard not to break (except for security fixes)

@tom-cosgrove-arm tom-cosgrove-arm removed the needs-backports Backports are missing or are pending review and approval. label Jul 4, 2022
@tom-cosgrove-arm
Copy link
Contributor

Hmm, a thought about this PR: the whole point is to make the structure shallow-copyable, so instead of having an embedded pointer into buf, it becomes rk_offset. Of course, if the buffer is copied, the offset needed for alignment might need to be changed, so: is what we have done right?

@tom-cosgrove-arm tom-cosgrove-arm added the needs-info An issue or PR which needs further info from the reporter / author label Jul 5, 2022
@AndrzejKurek
Copy link
Contributor

Hmm, a thought about this PR: the whole point is to make the structure shallow-copyable, so instead of having an embedded pointer into buf, it becomes rk_offset. Of course, if the buffer is copied, the offset needed for alignment might need to be changed, so: is what we have done right?

Looking at the use case and steps to reproduce - mbedtls_aes_setkey_enc/mbedtls_aes_setkey_dec is not called after the shallow copy is done, so the alignment might as well be wrong, if I understand correctly. Good catch!

@wernerlewis
Copy link
Contributor Author

Yes, this could lead to a change in alignment, which would cause failures with MBEDTLS_PADLOCK_C, good spot. If we want to support shallow copying in this case, then it would require a different implementation, or a way to realign RK after copying.

@tom-cosgrove-arm
Copy link
Contributor

tom-cosgrove-arm commented Jul 5, 2022

Actually, all you need to do is check that ctx->buf + ctx->rk_offset is 16-byte aligned in mbedtls_padlock_xcryptecb() and mbedtls_padlock_xcryptcbc() (which already do this for input and output) returning MBEDTLS_ERR_PADLOCK_DATA_MISALIGNED if not aligned, at which point the calling code will fall back to the slow (but working) path.

This means that a non-shallow-copied (OG) ctx will still use Padlock acceleration, and a (lucky) aligned shallow-copied ctx will use Padlock, but an unlucky not-aligned shallow-copied ctx will at least work.

That seems reasonable - you can copy the context, but it might be slow on the (rare, these days) VIA Padlock system.

@tom-cosgrove-arm tom-cosgrove-arm added needs-work and removed needs-info An issue or PR which needs further info from the reporter / author labels Jul 5, 2022
Signed-off-by: Werner Lewis <werner.lewis@arm.com>
Copy link
Contributor

@tom-cosgrove-arm tom-cosgrove-arm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - thanks for fixing so quickly

@daverodgman daverodgman added needs-ci Needs to pass CI tests and removed needs-ci Needs to pass CI tests labels Jul 20, 2022
@daverodgman
Copy link
Contributor

CI failures are all ABI, as expected

@daverodgman daverodgman merged commit 7085aa4 into Mbed-TLS:development Jul 20, 2022
@wernerlewis wernerlewis deleted the aes_shallow_copy branch July 20, 2022 14:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Design and code approved - may be waiting for CI or backports bug component-crypto Crypto primitives and low-level interfaces priority-medium Medium priority - this can be reviewed as time permits
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Make mbedtls_aes_context be shallow-copyable
6 participants