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

The pkcs7_get_signed_data function should be made global #1

Open
xNickChildx opened this issue Jul 22, 2020 · 0 comments
Open

The pkcs7_get_signed_data function should be made global #1

xNickChildx opened this issue Jul 22, 2020 · 0 comments

Comments

@xNickChildx
Copy link

Description

  • Type: Enhancement
  • Priority: Minor

Enhancement

Due to some signed files being in mbedtls_pkcs7_signed_data format (rather than pkcs7), it would be nice to be able to call the pkcs7_get_signed_data function directly (right now it is static). This would allow for outside programs to use the function to parse the new file format.

Suggested enhancement
Add pkcs7_get_signed_data to pkcs7.h

naynajain pushed a commit that referenced this issue Nov 17, 2020
The previous code used comparison operators >= and == that are quite likely to
be compiled to branches by some compilers on some architectures (with some
optimisation levels).

For example, take the following function:

void old_update( size_t data_len, size_t *padlen )
{
    *padlen  *= ( data_len >= *padlen + 1 );
}

With Clang 3.8, let's compile it for the Arm v6-M architecture:

% clang --target=arm-none-eabi -march=armv6-m -Os foo.c -S -o - |
    sed -n '/^old_update:$/,/\.size/p'

old_update:
        .fnstart
@ BB#0:
        .save   {r4, lr}
        push    {r4, lr}
        ldr     r2, [r1]
        adds    r4, r2, #1
        movs    r3, #0
        cmp     r4, r0
        bls     .LBB0_2
@ BB#1:
        mov     r2, r3
.LBB0_2:
        str     r2, [r1]
        pop     {r4, pc}
.Lfunc_end0:
        .size   old_update, .Lfunc_end0-old_update

We can see an unbalanced secret-dependant branch, resulting in a total
execution time depends on the value of the secret (here padlen) in a
straightforward way.

The new version, based on bit operations, doesn't have this issue:

new_update:
        .fnstart
@ BB#0:
        ldr     r2, [r1]
        subs    r0, r0, #1
        subs    r0, r0, r2
        asrs    r0, r0, Mbed-TLS#31
        bics    r2, r0
        str     r2, [r1]
        bx      lr
.Lfunc_end1:
        .size   new_update, .Lfunc_end1-new_update

(As a bonus, it's smaller and uses less stack.)

While there's no formal guarantee that the version based on bit operations in
C won't be translated using branches by the compiler, experiments tend to show
that's the case [1], and it is commonly accepted knowledge in the practical
crypto community that if we want to sick to C, bit operations are the safest
bet [2].

[1] https://github.com/mpg/ct/blob/master/results
[2] https://github.com/veorq/cryptocoding

Signed-off-by: Manuel Pégourié-Gonnard <[email protected]>
nick-child-ibm pushed a commit to nick-child-ibm/mbedtls-1 that referenced this issue May 25, 2021
nick-child-ibm pushed a commit that referenced this issue May 12, 2022
The PSA Crypto API uses 0 as the initial counter value, but the test vector
in RFC 7539 uses 1. So the unit tests here include an extra leading block.
The expected data for this leading block was calculated with Cryptodome.

    #!/usr/bin/env python3
    import re
    from Cryptodome.Cipher import ChaCha20

    key = bytes.fromhex('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f')
    nonce = bytes.fromhex('000000000000004a00000000')
    encrypt = lambda pt: ChaCha20.new(key=key, nonce=nonce).encrypt(pt)
    # Cryptodome uses counter=0, like PSA Crypto. Prepend a 64-byte input block #0
    # so that the plaintext from RFC 7539 starts exactly at block #1.
    header = b'The RFC 7539 test vector uses counter=1, but PSA uses counter=0.'
    assert(len(header) == 64)
    sunscreen = b"Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it."
    plaintext = header + sunscreen
    zeros = b'\x00' * len(plaintext)
    keystream = encrypt(zeros)
    ciphertext = encrypt(plaintext)

    print('RFC 7539 §2.4.2')
    print('Keystream:')
    print(re.sub(r'(..)', r'\1:', keystream[64:].hex()))
    print('Ciphertext Subscreen:')
    print(re.sub(r'(..)', r'\1 ', ciphertext[64:].hex()))
    print('')

    print(f"""\
    PSA symmetric decrypt: ChaCha20, RFC7539 keystream
    depends_on:PSA_WANT_ALG_STREAM_CIPHER:PSA_WANT_KEY_TYPE_CHACHA20
    # Keystream from RFC 7539 §2.4.2, with an extra 64-byte output block prepended
    # because the test vector starts at counter=1 but our API starts at counter=0.
    cipher_decrypt:PSA_ALG_STREAM_CIPHER:PSA_KEY_TYPE_CHACHA20:"{key.hex()}":"{nonce.hex()}":"{zeros.hex()}":"{keystream.hex()}"

    PSA symmetric decrypt: ChaCha20, RFC7539 sunscreen
    depends_on:PSA_WANT_ALG_STREAM_CIPHER:PSA_WANT_KEY_TYPE_CHACHA20
    # Test vector from RFC 7539 §2.4.2, with an extra 64-byte block prepended
    # because the test vector starts at counter=1 but our API starts at counter=0.
    cipher_decrypt:PSA_ALG_STREAM_CIPHER:PSA_KEY_TYPE_CHACHA20:"{key.hex()}":"{nonce.hex()}":"{ciphertext.hex()}":"{plaintext.hex()}"
    """)

Signed-off-by: Gilles Peskine <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant