-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
Move RSA basic key parsing/writing to rsa.c #8740
Conversation
Signed-off-by: Valerio Setti <[email protected]>
…paque RSA key Signed-off-by: Valerio Setti <[email protected]>
These functions are meant to be used internally, so their prototype declaration is kept into rsa_internal.h. Signed-off-by: Valerio Setti <[email protected]>
Signed-off-by: Valerio Setti <[email protected]>
…ormat This feature was an unofficial extension which was never documented. Now that we are removing the PK dependency in order to use only functions from RSA module, PEM support is unavailable. Therefore we explicitly remove it. Signed-off-by: Valerio Setti <[email protected]>
Use new functions from the RSA module to parse and write private and public keys in PKCS#1 format. Signed-off-by: Valerio Setti <[email protected]>
1c49e30
to
9895b38
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking pretty good to me. My only points are about documentation and testing.
The goal is to remove usage of PK return values in order to completely eliminate that dependency. This commit also updates pkparse and test_suite_x509parse to align with this change in return values. Signed-off-by: Valerio Setti <[email protected]>
Signed-off-by: Valerio Setti <[email protected]>
Do not disable RSA_C and related modules because now it does not automatically re-enable PK module. Signed-off-by: Valerio Setti <[email protected]>
Signed-off-by: Valerio Setti <[email protected]>
…pub keys Signed-off-by: Valerio Setti <[email protected]>
9895b38
to
1dc1501
Compare
Signed-off-by: Valerio Setti <[email protected]>
Signed-off-by: Valerio Setti <[email protected]>
Signed-off-by: Valerio Setti <[email protected]>
Signed-off-by: Valerio Setti <[email protected]>
1dc1501
to
ea98647
Compare
…cies() Since we officially disabled support for importing of PEM formatted keys into PSA we removed dedicated tests from test_suite_psa_crypto. As a consequence MBEDTLS_PEM_PARSE_C is no more an exception for component_check_test_dependencies(). Signed-off-by: Valerio Setti <[email protected]>
Er, right, fe329ce did pass the CI. Sorry for the confusion. I don't know what happened here: maybe I posted on the wrong tab (I was looking at several PR on my review queue)? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM apart from a check that isn't doing what it's supposed to do.
@@ -725,7 +725,7 @@ RSA parse public key - correct values, extra integer inside the SEQUENCE | |||
rsa_parse_pkcs1_key:1:"30818c028181009f091e6968b474f76f0e9c237c1d895996ae704b4f6d706acec8d2daac6209bf524aa3f658d0283adba1077f6cbe92e425dcde52290b239cade91be86c88425434986806e85734e159768f3dfea932baaa9409d25bace8ee9dce0cdde0903207299de575ae60feccf0daf82334ab83638539b0da74072f253acea8afc8e66bb70203010001020100":MBEDTLS_ERR_ASN1_LENGTH_MISMATCH | |||
|
|||
RSA parse public key - correct values, extra integer outside the SEQUENCE | |||
rsa_parse_pkcs1_key:1:"308189028181009f091e6968b474f76f0e9c237c1d895996ae704b4f6d706acec8d2daac6209bf524aa3f658d0283adba1077f6cbe92e425dcde52290b239cade91be86c88425434986806e85734e159768f3dfea932baaa9409d25bace8ee9dce0cdde0903207299de575ae60feccf0daf82334ab83638539b0da74072f253acea8afc8e66bb70203010001":0 | |||
rsa_parse_pkcs1_key:1:"308189028181009f091e6968b474f76f0e9c237c1d895996ae704b4f6d706acec8d2daac6209bf524aa3f658d0283adba1077f6cbe92e425dcde52290b239cade91be86c88425434986806e85734e159768f3dfea932baaa9409d25bace8ee9dce0cdde0903207299de575ae60feccf0daf82334ab83638539b0da74072f253acea8afc8e66bb70203010001020100":0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hold on: since there's extra data, the function should return an error.
And it looks like we're missing a similar test case for key pairs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And it looks like we're missing a similar test case for key pairs.
It's on line 664:
RSA parse private key - correct values, extra integer outside the SEQUENCE
Hold on: since there's extra data, the function should return an error.
This is basically the feedback I was waiting for after my last comment:
It makes more sense to me to do it this way because the user can provide a larger buffer which contains a valid key (priv or pub, it does not matter) and we are able to parse only the relevant data from there.
In my opinion, since the extra data is after the sequence it could make sense to have a success here because we're not corrupting the main SEQUENCE (it's just some extra data after it). However if you think that this must still be an error I will update the code accordingly ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't think of a direct security risk in accepting a key followed by arbitrary garbage, but I'm always uneasy accepting invalid inputs: it can often be a step in an attack in some weird circumstances that are hard to anticipate. So I would prefer to reject all invalid data unless there's a compelling reason.
library/rsa.c
Outdated
@@ -109,6 +109,10 @@ int mbedtls_rsa_parse_key(mbedtls_rsa_context *rsa, const unsigned char *key, si | |||
|
|||
end = p + len; | |||
|
|||
if (end > (key + keylen)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This check never fires: at this point, the comparison is between the end of the SEQUENCE content and the end of the overall buffer, and a success from mbedtls_asn1_get_tag
guarantees that they're in the desired order. I think the fix is to put this exact check just above end = p + len
.
Same with parse_pubkey
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
success from mbedtls_asn1_get_tag guarantees that they're in the desired order
Ops, that's a detail that I missed before. Thanks for the hint!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the fix is to put this exact check just above end = p + len.
Mmmm, but (if I'm not wrong) doing so would result in a never-firing-check again. end
is set few lines above as end = p + keylen;
(where p = (unsigned char *) key;
at that point) and then mbedtls_asn1_get_tag()
does not update it, so checking if (end > (key + keylen))
never fires. Am I wrong?
On the other hand if I replace if (end > (key + keylen))
with if (end != (key + keylen))
there are other test suites that start failing. For example test_suite_pkparse
fails at:
Parse RSA Key #2 (Correct password) ............................... FAILED
Parse RSA Key #4 (DES Encrypted) .................................. FAILED
Parse RSA Key #5 (3DES Encrypted) ................................. FAILED
Parse RSA Key #6 (AES-128 Encrypted) .............................. FAILED
Parse RSA Key #7 (AES-192 Encrypted) .............................. FAILED
Parse RSA Key #8 (AES-256 Encrypted) .............................. FAILED
Parse RSA Key #9 (2048-bit, DES Encrypted) ........................ FAILED
Parse RSA Key #10 (2048-bit, 3DES Encrypted) ...................... FAILED
Parse RSA Key #11 (2048-bit, AES-128 Encrypted) ................... FAILED
Parse RSA Key #12 (2048-bit, AES-192 Encrypted) ................... FAILED
Parse RSA Key #13 (2048-bit, AES-256 Encrypted) ................... FAILED
Parse RSA Key #14 (4096-bit, DES Encrypted) ....................... FAILED
Parse RSA Key #15 (4096-bit, 3DES Encrypted) ...................... FAILED
Parse RSA Key #16 (4096-bit, AES-128 Encrypted) ................... FAILED
Parse RSA Key #17 (4096-bit, AES-192 Encrypted) ................... FAILED
Parse RSA Key #18 (4096-bit, AES-256 Encrypted) ................... FAILED
I will have a look at this of course, but I'm not sure that having the extra data is a real bad thing (see my previous comment). Wdyt?
Edit: I just checked the first failure above (Parse RSA Key #2 (Correct password)
) and the problem in this case is that the key is encrypted (AES-128-CBC) so PEM allocates a buffer whose length is the one of the encrypted key content, not the decrypted one. As a consequence the following call to mbedtls_rsa_parse_key
fails.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There might be some history of sloppiness in pk parsing of encrypted keys, because the decryption code (mbedtls_pkcs5_pbes2
and mbedtls_pkcs12_pbe
) used to not report the length of the plaintext. But nowadays pkparse calls mbedtls_pkcs5_pbes2_ext
and mbedtls_pkcs12_pbe_ext
, which do report the length of the plaintext. So I'd expect this to be easy to fix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The failing cases I reported above are not related to pkcs5/12. For example in
Parse RSA Key #2 (Correct password)
the flow is:
mbedtls_pk_parse_key -> mbedtls_pem_read_buffer -> pem_aes_decrypt
Here len
is not updated at the end of mbedtls_pem_read_buffer
compared to what it was allocated from the first call to mbedtls_base64_decode()
on the encrypted buffer. As a consequence the following call to mbedtls_rsa_parse_key
fails.
The only way to prevent this would be to analyze the decrypted buffer to determine how long it is based on the SEQUENCE data, but that's part of the RSA parser in my opinion. Wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I'd forgotten we also had a decryption method in pem.c
. It's a similar construction as PKCS5 and PKCS12: CBC where the old decryption code doesn't strip away the padding. For PKCS5 and PKCS12, we added _ext
functions that do strip the padding. So I guess we should do the same thing in pem.c
: remove PKCS7 padding after CBC decryption.
Since pem.c
can be built without MBEDTLS_CIPHER_C
, we can't use the cipher.c
code (get_pkcs_padding
) to strip the padding. On the other hand, since we're parsing the content, we don't have to worry about a padding oracle: there's a decryption oracle via the content anyway. So the padding check doesn't need to be constant-time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To move on with this pull request which is already pretty long, I propose to merge it as is, and fix this in a follow-up.
Signed-off-by: Valerio Setti <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved on the condition that we fix #8799 before the next release.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thanks Gilles for splitting #8799 out of this and to Valerio for identifying that the problem was with PEM decryption.
This is possible because after Mbed-TLS#8740 RSA_C no longer depends on PK to parse and write private/public keys. This commit also solves related issues that arose after this change in "pk.c" and "test_suite_pk". In particular now we can use rsa's module functions for parsing and writing keys without need to rely on pk_parse and pk_write functions. Signed-off-by: Valerio Setti <[email protected]>
This is possible because after Mbed-TLS#8740 RSA_C no longer depends on PK to parse and write private/public keys. This commit also solves related issues that arose after this change in "pk.c" and "test_suite_pk". In particular now we can use rsa's module functions for parsing and writing keys without need to rely on pk_parse and pk_write functions. Signed-off-by: Valerio Setti <[email protected]>
This is possible because after Mbed-TLS#8740 RSA_C no longer depends on PK to parse and write private/public keys. This commit also solves related issues that arose after this change in "pk.c" and "test_suite_pk". In particular now we can use rsa's module functions for parsing and writing keys without need to rely on pk_parse and pk_write functions. Signed-off-by: Valerio Setti <[email protected]>
This is possible because after Mbed-TLS#8740 RSA_C no longer depends on PK to parse and write private/public keys. This commit also solves related issues that arose after this change in "pk.c" and "test_suite_pk". In particular now we can use rsa's module functions for parsing and writing keys without need to rely on pk_parse and pk_write functions. Signed-off-by: Valerio Setti <[email protected]>
This is possible because after Mbed-TLS#8740 RSA_C no longer depends on PK to parse and write private/public keys. This commit also solves related issues that arose after this change in "pk.c" and "test_suite_pk". In particular now we can use rsa's module functions for parsing and writing keys without need to rely on pk_parse and pk_write functions. Signed-off-by: Valerio Setti <[email protected]>
This is possible because after Mbed-TLS#8740 RSA_C no longer depends on PK to parse and write private/public keys. This commit also solves related issues that arose after this change in "pk.c" and "test_suite_pk". In particular now we can use rsa's module functions for parsing and writing keys without need to rely on pk_parse and pk_write functions. Signed-off-by: Valerio Setti <[email protected]>
This is possible because after Mbed-TLS#8740 RSA_C no longer depends on PK to parse and write private/public keys. This commit also solves related issues that arose after this change in "pk.c" and "test_suite_pk". In particular now we can use rsa's module functions for parsing and writing keys without need to rely on pk_parse and pk_write functions. Signed-off-by: Valerio Setti <[email protected]>
Description
This PR moves RSA private/public parsing functions from PK module to the RSA one. In this way the PK dependency of PSA crypto is removed even when building with RSA enabled.
Resolves #8647 (primary goal).
Resolves #5145 (in passing).
PR checklist