PK: add mbedtls_pk_write_pubkey_psa() #577
Labels
No labels
api-break
approved
bug
component-docs
component-platform
component-test
dependencies
deprecation
DO-NOT-MERGE
enhancement
good first issue
help wanted
needs-adoption
needs-backports
needs-ci
needs-design-approval
needs-info
needs-preceding-pr
needs-review
needs-reviewer
needs-work
priority-high
priority-low
priority-medium
priority-scheduled
priority-very-high
resolved-after-1.1
single-reviewer
size-l
size-m
size-optimisation
size-s
size-xs
No milestone
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
gh-Mbed-TLS/TF-PSA-Crypto!577
Loading…
Reference in a new issue
No description provided.
Delete branch "issue529"
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?
Description
Resolves #529
PR checklist
Looks pretty good to me, thanks for the nice documentation, but I want more tests :)
Typo: pubBlic
I don't think we need to check for that or promise that we do in the documentation. Generally speaking when passed NULL pointers that shouldn't be NULL, we're OK with getting whatever behaviour we get from the platform (like segfault on Linux etc).
Some of the old code in PK has more checks than our current policy, but I don't think we should copy that in new code.
(Though thanks for documenting every error condition here!)
@ -880,2 +880,4 @@int mbedtls_pk_write_key_pem(const mbedtls_pk_context *ctx, unsigned char *buf, size_t size);#endif /* MBEDTLS_PEM_WRITE_C *//**Thanks! This is an example of how we should always write documentation about buffer sizes :)
@ -158,0 +230,4 @@} else if (key_bits == 521) {priv_key = test_ec_secp521r1_priv;priv_key_len = sizeof(test_ec_secp521r1_priv);}It has now been merged, so this can be updated :)
Post 1.0, we can (and should) just call
PSA_INIT(). (Same withPSA_DONE().)Ok, that's one was to populate a context. As discussed elsewhere, we need to test other ways of populating the context. Also as discussed, that might either be done with more test functions, or my handling multiple methods in a single function.
Off the top of my head, I'd say:
wrap_psa(),copy_from_psa()andcopy_public_from_psa(), as they all start with a PSA key?While addressing comments I realized that the implementation I provided completely misses the support for opaque keys! This is not a regression compared to what there before since opaque contexts (EC and RSA) do not have the debug support. So the question: is this something we foresee that might be useful in the future? Or are we OK with the current implementation?
I think that extending the test coverage as you suggested will tell if at least we're fine with non-opaque keys, I guess
On a second thought I have a proposal/question as follow-up. How bad is it for opaque keys in PK to have their public part in the PK context (like non-opaque EC/RSA)? I cannot think of any drawback to this, but you know for sure better than me.
Rationale.
I found that
mbedtls_pk_ecc_set_pubkey_from_prvandmbedtls_pk_rsa_set_pubkey_from_prvare basically the same, so instead of duplicating the code I can move them inpk.cwith their prototype being inpk_internal.h. Then inmbedtls_pk_write_pubkey_psaI can check ifpk->pub_raw_len != 0andmemcpyfrom that; however in case it's empty BUTpk->priv_idis not empty, I can try to export the public key from the private one (using the merge ofmbedtls_pk_ecc_set_pubkey_from_prv&mbedtls_pk_rsa_set_pubkey_from_prv) as last resort.To me this makes
mbedtls_pk_write_pubkey_psaable to work in all scenarios without end user intervention and being able to support opaque keys as well!Wdyt?
It's just a memory-vs-performance compromise. Given that the current trend in pk is to reduce the number of cases when manipulating key representations, I think it would make sense to always store the public key in the context.
I just added a couple of commits ([1] and [2]) to show what I had in mind.
I haven't extended testing though, so please wait a bit before reviewing the PR again.
As Gilles said, and as I was trying to say on the bitlen PR, I think we want to avoid as much as possible having fields in the
pk_contextthat are sometimes set, sometimes not, and as maintainers we have to remember about them and what condition to check to know if the field is set or not, and that adds a lot of cognitive load when working with the code.So, yes, every time we can reduce the number of cases we have to consider and move to a situation where the same information is always present in the same way not matter how the key was populated, I'll be in favour of doing so!
Sorry I had to rebase on
developmentbecause I neededmbedtls_pk_get_key_type()in test code, but this has only been added recently in tf-psa-cryto.Thanks for adding the bunch of tests I requested, I like how your structured them too :)
However in addition to small suggestions I have two blocker comments:
Also, a few other comments/suggestions that are optional.
@ -137,6 +143,23 @@ int mbedtls_pk_setup(mbedtls_pk_context *ctx, const mbedtls_pk_info_t *info)return 0;Minor: since the function returns
int, I'd findreturn 0more natural here.@ -475,6 +475,26 @@ int mbedtls_pk_write_key_der(const mbedtls_pk_context *key, unsigned char *buf,return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;}/******************************************************************************This feels a bit hacky: having to remove the
constis a bad smell. I'd rather make sure all functions that populate a context always set the public key field (presumably by callingmbedtls_pk_set_pubkey_from_prv().This goes with my general wish that once a context is populated, all the fields from
pk_contextare set and usable (except forpriv_idwhen the context is only holding public key material).Unless you think there's a reason this can't be done?
@ -153,3 +153,86 @@ pk_write_public_from_private:"../framework/data_files/ec_x25519_prv.der":"../fraDerive public key EC X448depends_on:PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY:PSA_WANT_ECC_MONTGOMERY_448Minor: can we have symbolic names, like
MBEDTLS_PK_TEST_{PUBLIC,PRIVATE}(either using#defines or an enum)? We already have too many test with 0/1 parameters, and as long as there's only one we can often guess, but when there's more than one it's uncomfortable to read.In the spirit that you suggested of raising the bar for readability in newly added tests :)
Note: this is likely to be also useful for other test functions, so it would make sense turning that into its own helper function. (Can be done either in this PR, or in the next PR that needs something similar - I think perhaps #575 could use something similar.)
Shouldn't we call
test_pk_write_pubkey_psa()? Am I missing something obvious or did you?@ -153,3 +153,86 @@ pk_write_public_from_private:"../framework/data_files/ec_x25519_prv.der":"../fraDerive public key EC X448I thought I left a comment here but it seems github lost it: I'd like a symbolic name instead of 0/1 for the new argument, like you did for
pk_write_pubkey_psa_from_psa().@ -475,6 +475,26 @@ int mbedtls_pk_write_key_der(const mbedtls_pk_context *key, unsigned char *buf,return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;}/******************************************************************************TBH I was skeptical as well about this change. I checked current calls to
mbedtls_pk_debugin TLS code and in all the cases aconstpointer is being passed. It makes sense of course, because we're only supposed to get some data out of the PK context, not to modify it.Also I knew that this change was "requesting" a bit too many weird castings in the TLS code and that this was not nice as well.
I'll look into improving this.
@ -153,3 +153,86 @@ pk_write_public_from_private:"../framework/data_files/ec_x25519_prv.der":"../fraDerive public key EC X448depends_on:PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY:PSA_WANT_ECC_MONTGOMERY_448Sure, that makes completely sense. I usually hate when I have to switch back and forth between
.dataand.functionfiles because there are sequences of1and0in the test data and my bad short term memory cannot remember the order of parameters in test functions :)@ -153,3 +153,86 @@ pk_write_public_from_private:"../framework/data_files/ec_x25519_prv.der":"../fraDerive public key EC X448depends_on:PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY:PSA_WANT_ECC_MONTGOMERY_448That calls for IDE support! Emacs users can use mbedtls-test-data-mode. Contributions for other editors are welcome.
@ -153,3 +153,86 @@ pk_write_public_from_private:"../framework/data_files/ec_x25519_prv.der":"../fraDerive public key EC X448depends_on:PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY:PSA_WANT_ECC_MONTGOMERY_448I thought @davidhorstmann-arm has something from vim using a small special-purpose LSP, but I can't seem to find it again.
Still, I think we can all agree that symbolic names have value regardless of the level of editor/IDE support :)
Oops, bad mistake, sorry
Since we also collaborated on previous PRs about PK I guess you saw that this was a duplication of the test helper function that's already used in test_suite_pk.function, so I agree that creating a common helper makes sense.
The only thing I'm not sure about is if it's better to do this in this PR or in a quick follow-up one. This one is going to be in the range of 20 commits already, so perhaps a quick follow-up one is better.
https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/598
Thanks for addressing my comments. Looks almost all good to me, but I think we're missing a test for calling the new function on an unpopulated context:
(or similar, without the silly mistake I probably made).
I'd suggest adding a small dedicated test function for that. That way, looking at the
.datafile it's very apparent that we're testing all the cases for this function: unpopulated context (negative), then all 5 methods of populating the context (4 positive cases each).@mpg @bjwtaylor I had to rebase to resolve a conflict on the
framework. Can you please re-check?LGTM, thanks!