Disallow use of invalid contexts #58
No reviewers
Labels
No labels
api-spec
bug
CLA requested
CLA valid
compliance
DO NOT MERGE
duplicate
enhancement
feature branch
good first issue
HEADER FORMATTING ISSUE
help wanted
Information
invalid
Jira status: AWAITING REVIEW
Jira status: CLOSED
Jira status: DONE
Jira status: IN PROGRESS
Jira status: IN REVIEW
Jira status: OPEN
Jira status: REOPENED
Jira status: RESOLVED
mirrored
mirror internally
needs: backports
needs: ci
needs: design review
needs: preceding PR
needs: review
needs: work
notabug
open for community contribution
Product Backlog
question
ready for merge
security
stale
type: bug
type: enhancement
type: question
web pages
wontfix
writing
No milestone
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
gh-ARMmbed/mbed-crypto!58
Loading…
Reference in a new issue
No description provided.
Delete branch "disallow-invalid-context"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Disallow use of MAC, hash, and cipher contexts that haven't been set up (i.e. has a
*_setup()function called on them).I'm not sure if it's a good idea to call
aborton aBAD_STATEerror. What is likely to happen?If the operation object was uninitialized or corrupted,
aborthas undefined behavior and this could be a way for an attacker to leverage a memory corruption error into remote code execution.If the object was in a well-formed state, but not ready for an update, then for a hash that means that the object is already in a non-setup state and
abortwill do nothing.Please avoid mixing input validation tests with operation correctness tests. That makes it harder to understand what is tested, and makes it harder to run just the input validation tests without also running the more costly operation correctness tests. This function is for operation correctness.
This also goes for
mac_verify.Also, why test
sign_finishfollowed bysign_finish, but not other invalid combinations such assign_finishfollowed byupdate,sign_setupfollowed byverify_finish, etc.?Looks ok to me besides the comments already made by Gilles. Are there any additional dependencies that need to be updated (e.g. example repo , usage by tls, etc..)?
The same reasoning seems to apply to
psa_hash_finish()as well. I'll update there, too.If implementation functions like
mbedtls_sha1_finish_ret()and can ever return an error equivalent toPSA_ERROR_BAD_STATE, then we may have a pre-existing bug inpsa_hash_finish()as we will callpsa_hash_abort()in such a case.Rebasing to address review feedback, extend tests, and fix #10.
Rebased. Previous branch at https://github.com/Patater/mbed-crypto/tree/disallow-invalid-context-1
I'm looking into some memory leaks.
In general, if you start a cipher operation, and some internal memory is allocated on your behalf (e.g. AES context created), and then you call finish twice and get a
PSA_ERROR_BAD_STATEerror, there is no way to free that lost memory anymore, is there? You can't call abort, since after you get anPSA_ERROR_BAD_STATE, all bets are off.wouldn't the first call to finish de-allocate the resources?
That's not true. All bets are off if you have a bad state because the object was corrupted or never initialized. But if you've correctly initialized the object and subsequently only ever modified it through API functions, then abort is guaranteed to succeed.
@NirSonnenschein Yes, it likely would. Good point.
I'll change my example. How about if you call cipher finish without first setting an IV? Finish would fail with
PSA_ERROR_BAD_STATE, but memory would have been allocated during cipher setup.Thanks for the clarification, Gilles. I'll switch from using memset to all 0 between bad order tests and use abort instead.
Also note that one isn't guaranteed to get BAD_STATE if the context is corrupt or never initialized, so I'm not sure why we should be concerned, as per your comment: https://github.com/ARMmbed/mbed-crypto/pull/58#discussion_r257349820, about calling abort if BAD_STATE is encountered in these sorts of "well-formed" situations.
Can we conclude that it is OK to call abort on BAD_STATE? Are there cases we shouldn't call abort given we've gotten a BAD_STATE?
https://github.com/ARMmbed/mbed-crypto/pull/58#discussion_r257349820 was about calling abort internally, not about calling it from the application. I distinguished two cases: well-formed situations, where it's debatable whether the right behavior is to abort or to not modify the object, and non-well-formed situations, where abort could make things worse.
In application code, you should always initialize your memory, and you should always call abort unless you have a guarantee that the object is in its initial state (e.g. because you never set it up or the last function that you applied to it was a finish function).
Rebase incoming to switch from memset to abort between bad order tests.
Rebased. Previous branch at https://github.com/Patater/mbed-crypto/tree/disallow-invalid-context-3
Forgot to apply a fixup commit. Rebasing again.
Rebased to apply fixup commit. Previous branch at https://github.com/Patater/mbed-crypto/tree/disallow-invalid-context-4
All done rebasing. Ready to review.
Added commits to address https://github.com/ARMmbed/mbed-crypto/pull/58#discussion_r257349820
Will apply as fixup with a rebase if review goes well
This is getting a bit too messy. I'm going to have to rebase before review.
Rebased to apply fixups and make some style improvements. Previous branch at https://github.com/Patater/mbed-crypto/tree/disallow-invalid-context-5
Rebasing done.
Will rebase to apply fixup commit now
Rebased to apply fixup and fix CI issues with
depend_hashes.pl.Rebasing and rework done for now.
This has CI failures. I'll be doing some rework to address this.
@ -1373,7 +1379,13 @@ psa_status_t psa_hash_setup( psa_hash_operation_t *operation,psa_algorithm_t alg )Style (here and in a few other places):
I've given the PR a first glance and it looks like it's going in the right direction. I'll hold doing a detailed code review until you've finished the rework.
We've uncovered pre-existing bugs where we didn't initialize the operation context before calling setup. Rebasing to add commits to fix these issues.
Rebased to add commits to fix uninitialized context bugs and edit commits with bad style. Previous branch at https://github.com/Patater/mbed-crypto/tree/disallow-invalid-context-8
CI passed. Ready for review.
psa_mac_updateis not consistent with the other update/finish functions wrt an argument in initial state: it calls abort. This is not an absolute blocker because we still haven't decided what behavior the specification will mandate, but I'd prefer the implementation to be consistent.@ -1238,3 +1238,3 @@psa_status_t status;psa_cipher_operation_t cipher_op;psa_cipher_operation_t cipher_op = PSA_CIPHER_OPERATION_INIT;size_t part_len;Why wasn't this caught by CI? Are we missing a test case or a test configuration?
@ -2232,6 +2247,11 @@ psa_status_t psa_mac_sign_finish( psa_mac_operation_t *operation,{psa_status_t status;Style: missing space before
)(here and elsewhere)@ -1960,6 +1961,14 @@ void hash_operation_init( )What does “default hash operation” mean? I understand from context, but this is the code explaining the comment whereas it should be the other way round. Suggestion: “freshly-initialized”
@ -2016,0 +2038,4 @@PSA_ASSERT( psa_hash_abort( &operation ) );/* Call verify after finish. */PSA_ASSERT( psa_hash_setup( &operation, alg ) );This is getting to be a long series of ad hoc tests. Have we reached the point where they would be easier to write and easier to read if we made the code data-driven? That would make it easier to add other sequences.
@ -2016,0 +2044,4 @@TEST_EQUAL( psa_hash_verify( &operation,valid_hash, sizeof( valid_hash ) ),PSA_ERROR_BAD_STATE );PSA_ASSERT( psa_hash_abort( &operation ) );Technically, you're calling update after abort. This is equivalent to update without setup only if abort behaves correctly.
Leftover from a previous iteration.
@ -1238,3 +1238,3 @@psa_status_t status;psa_cipher_operation_t cipher_op;psa_cipher_operation_t cipher_op = PSA_CIPHER_OPERATION_INIT;size_t part_len;This was caught by CI, but it wasn't a failure until we started checking that the context is initialized before allowing setup() (by fixing #10). Same with the X.509 issues. all.sh catches this when it runs "make test" when using the
MBEDTLS_USE_PSA_CRYPTOoption.@ -2232,6 +2247,11 @@ psa_status_t psa_mac_sign_finish( psa_mac_operation_t *operation,{psa_status_t status;Gah, I thought I fixed all of these...
@ -2016,0 +2044,4 @@TEST_EQUAL( psa_hash_verify( &operation,valid_hash, sizeof( valid_hash ) ),PSA_ERROR_BAD_STATE );PSA_ASSERT( psa_hash_abort( &operation ) );Would you recommend we call both abort and memset the context to 0? I'm depending on abort setting the context to 0, and if it doesn't, the test will fail.
@ -1960,6 +1961,14 @@ void hash_operation_init( )I've also seen us use "blank". I'll change to freshly-initialized.
Removed
@ -2016,0 +2044,4 @@TEST_EQUAL( psa_hash_verify( &operation,valid_hash, sizeof( valid_hash ) ),PSA_ERROR_BAD_STATE );PSA_ASSERT( psa_hash_abort( &operation ) );If abort works properly, it doesn't matter. It's only a matter of how hard it will be to investigate a test failure that is ultimately due to abort returning the expected status but not having done its job properly.
I would prefer to make each unit test independent. But it's also good to have a stress test where a single object is reused.
@ -2016,0 +2038,4 @@PSA_ASSERT( psa_hash_abort( &operation ) );/* Call verify after finish. */PSA_ASSERT( psa_hash_setup( &operation, alg ) );I did have this thought as well, but decided it wasn't worth the time yet.
Rebasing to address review feedback.
@ -2016,0 +2044,4 @@TEST_EQUAL( psa_hash_verify( &operation,valid_hash, sizeof( valid_hash ) ),PSA_ERROR_BAD_STATE );PSA_ASSERT( psa_hash_abort( &operation ) );I've raised #66 to add targeted abort tests.
Rebased. Previous branch at https://github.com/Patater/mbed-crypto/tree/disallow-invalid-context-9
Rebased to add a commit that returns bad state without aborting in more cases. Previous branch at https://github.com/Patater/mbed-crypto/tree/disallow-invalid-context-12
@ -6531,3 +6531,3 @@size_t hash_size;psa_hash_operation_t sha256_psa;psa_hash_operation_t sha256_psa = PSA_HASH_OPERATION_INIT;psa_status_t status;Using
PSA_HASH_OPERATION_INIT,psa_hash_operation_init();or simply= 0are all valid ways to do initialisation, right?What are the advantages of different methods? In particular, why are we using on line 1449 and 1492
psa_hash_operation_init();andPSA_HASH_OPERATION_INIThere?@ -6531,3 +6531,3 @@size_t hash_size;psa_hash_operation_t sha256_psa;psa_hash_operation_t sha256_psa = PSA_HASH_OPERATION_INIT;psa_status_t status;{0}andINIT(macro) can be used to initialize global variables, butinit()(function) can't.{0}is generic but some compilers warn that this implicitly initializes other fields to 0.init()is the only one that's typed, so you'll get an error if you use it in the wrong context.memsetto 0 is also defined as equivalent because it allows applications to use e.g.calloc, and in practice it produces the same value as{0}on virtually all platforms.In most cases, the choice is indifferent.
@ -6531,3 +6531,3 @@size_t hash_size;psa_hash_operation_t sha256_psa;psa_hash_operation_t sha256_psa = PSA_HASH_OPERATION_INIT;psa_status_t status;PSA_HASH_OPERATION_INITis all static, so you can use it for static globals. The inline function can be used where functions can be used, which is a few less places, but it uses the static initializer under-the-hood.= {0}is usually ok, but some compilers will complain about missing field initializers.I personally prefer using the macro everywhere, but previous authors inside library/ssl_tls.c liked the function. There is no functional difference in this case.
Looks good to me!
CI failure is only FreeBSD timing test, a known-flaky test.