PK: inline & simplify check_pair functions #521
Closed
opened 2025-10-14 08:15:02 -05:00 by mpg
·
12 comments
No Branch/Tag specified
development
tf-psa-crypto-1.1
archive/20261005T153337Z-force/pull/927
archive/20261001T141055Z-force/pull/927
archive/20261005T153337Z-force/pull/931
archive/20261001T083616Z-force/pull/927
archive/20260930T232327Z-force/pull/927
archive/20260930T154618Z-force/pull/927
archive/20260929T231919Z-rescue/rohankl-arm/mldsa-pubkey-899
archive/20260929T231919Z-rescue/sigvartmh/pr/spake2p-9342-public-key-import-export
archive/20260929T231919Z-rescue/ManoharPaturi/fix-pem-ct-padding
archive/20260929T231919Z-rescue/ManoharPaturi/fix-asn1write-null-guard
archive/20260929T231919Z-rescue/ManoharPaturi/fix-pbes2-params-validation
archive/20260929T231919Z-rescue/valeriosetti/blake2
archive/20260929T231919Z-rescue/jfdev001/v1.1.1_bump-cmake-minimum-version
archive/20260929T231919Z-rescue/jfdev001/bump-cmake-minimum-version
archive/20260929T231919Z-rescue/ronald-cron-arm/sm3-base
archive/20260929T231919Z-rescue/valeriosetti/blake2-hmac
archive/20260929T231919Z-rescue/v1rtu3x/enforce-hash-length-sign-verify
archive/20260929T231919Z-rescue/bjwtaylor/file-backed-keystore-doc
archive/20260929T231919Z-rescue/sigvartmh/pr/spake2p-9344-set-context
archive/20260929T231919Z-rescue/sigvartmh/pr/spake2p-9343-key-pair-import-export-depends-on-9342
archive/20260929T231919Z-rescue/romart/development
archive/20260929T231919Z-rescue/sweetlilmre/constant-time-embedded-perf
archive/20260929T231919Z-rescue/JulioLoayzaM/add-wycheproof-rsa-pss
archive/20260929T231919Z-rescue/JulioLoayzaM/add-wycheproof-ecdsa
archive/20260929T231919Z-rescue/JulioLoayzaM/add-wycheproof-tests
archive/20260929T231919Z-rescue/oubaid-a/dev_psa_driver_wrapper
archive/20260929T231919Z-rescue/gilles-peskine-arm/keystoreless-prototype-1
archive/20260929T231919Z-rescue/valeriosetti/issue9580
archive/20260929T231919Z-rescue/LeonieReichertABB/hpke-functionality
archive/20260929T231919Z-rescue/gilles-peskine-arm/psa-hash-no-buffer-copy-1.1
archive/20260929T231919Z-rescue/vanhauser-thc/development
archive/20260929T231919Z-rescue/tpambor/key-wrap
archive/20260929T231919Z-rescue/ruiliio/psa_xts
archive/20261011T063515Z-force/pull/538
archive/20260929T231919Z-rescue/gilles-peskine-arm/fix-broken-links-1.1
archive/20260929T231919Z-rescue/valeriosetti/issue669
archive/20260929T231919Z-rescue/gilles-peskine-arm/prepare-release-test
archive/20260929T231919Z-rescue/krish2718/wpa3-sae-design-note
archive/20260929T231919Z-rescue/nzzlinh/fix_iar_endianness_1.1
archive/20260929T231919Z-rescue/nzzlinh/fix-iar-endianness
archive/20260929T231919Z-rescue/abtom87/fix-pbkdf2-iter-count
archive/20260929T231919Z-rescue/minosgalanakis/tools/prepare_release_lite
archive/20260929T231919Z-rescue/Harshal5/fix/aes-xts-in-place-cts
archive/20260929T231919Z-rescue/sigvartmh/pr/spake2p-9347-prover-depends-on-9342-9343-9344
archive/20260929T231919Z-rescue/crabel99/async-hardware-support-c35df962
tf-psa-crypto-1.2.0_mergeback
tf-psa-crypto-1.1.1_mergeback
archive/20260929T231919Z-rescue/asmellby/feature/dispatch-library
tf-psa-crypto-release-sync
archive/20260929T231919Z-rescue/ChakshuGupta13/fix/ecdsa-zeroize-stack-key
archive/20260929T231919Z-rescue/gilles-peskine-arm/security-md-option-names
archive/20260929T231919Z-rescue/parmi93/patch-2
archive/20260929T231919Z-rescue/bjwtaylor/remove-mldsa-sign-from-build
archive/20260929T231919Z-rescue/bjwtaylor/tf-m-build-issues
archive/20260929T231919Z-rescue/bjwtaylor/test-context-population
archive/20260929T231919Z-rescue/gilles-peskine-arm/iar-1.1.0
archive/20260929T231919Z-rescue/gilles-peskine-arm/fork-helper-unit-tests-create-crypto
archive/20260929T231919Z-rescue/bjwtaylor/redundant-declarations
archive/20260929T231919Z-rescue/hasheddan/docs/fix-broken-links
main
archive/20260929T231919Z-rescue/bjwtaylor/reintroduce-dh
archive/20260929T231919Z-rescue/bjwtaylor/cipher-update-incorrect-error
archive/20260929T231919Z-rescue/Marandil/fix/mbedtls-4314-parse-explicit-curve
archive/20260929T231919Z-rescue/schneider-electric/dev/plaj-se/parse-rsassa-pss
archive/20260929T231919Z-rescue/minosgalanakis/bugfix/program-fuzz-mscv
archive/20260929T231919Z-rescue/daverodgman/aesgcm
archive/20260929T231919Z-rescue/gilles-peskine-arm/sha3-coverity-20260224
archive/20260929T231919Z-rescue/bensze01/undef
archive/20260929T231919Z-rescue/valeriosetti/issue523
archive/20260929T231919Z-rescue/dannytsen/ppc-dev
archive/20260929T231919Z-rescue/daverodgman/aes12
archive/20260929T231919Z-rescue/gilles-peskine-arm/ascon-prototype
archive/20260929T231919Z-rescue/daverodgman/chacha10
archive/20260929T231919Z-rescue/kusumitg/implement_psa_pake_set_context_for_spake2p
archive/20260929T231919Z-rescue/davidhorstmann-arm/add-code-size-target
archive/20260929T231919Z-rescue/bjwtaylor/simplify-sign_func
archive/20260929T231919Z-rescue/mfil/feature/aes_ni_parallel
archive/20260929T231919Z-rescue/ivv19041994/patch-1
archive/20260929T231919Z-rescue/gilles-peskine-arm/psa-verify-policy-relax
public_2/main
archive/20260929T231919Z-rescue/mpg/pk-sign-proto
release/tf-psa-crypto1.0.0-documentation
archive/20260929T231919Z-rescue/gilles-peskine-arm/0e-plans-july-updates
archive/20260929T231919Z-rescue/davidhorstmann-arm/guard-context-types-in-client-only
archive/20260929T231919Z-rescue/gilles-peskine-arm/psa-driver-interface-spec-remove
archive/20260929T231919Z-rescue/gilles-peskine-arm/ecp-self-test-race-crypto
archive/20260929T231919Z-rescue/KiruthikPrakash/feature/9342_add-support-for-spake2p-public-key-import-export
archive/20260929T231919Z-rescue/ruiliio/chacha20_16
archive/20260929T231919Z-rescue/irwir/winsock2
archive/20260929T231919Z-rescue/aphroteus/development
archive/20260929T231919Z-rescue/amjoul01/amjoul01/psa-mac-out-of-bound-fix
archive/20260929T231919Z-rescue/gilles-peskine-arm/everest-submodule-crypto
archive/20260929T231919Z-rescue/yamt/xtensa-ccount
archive/20260929T231919Z-rescue/gilles-peskine-arm/all.sh-generate-only-before-checks-crypto
archive/20260929T231919Z-rescue/Harshal5/feat/builtin_cmac_driver_use_psa_crypto_interface
archive/20260929T231919Z-rescue/gilles-peskine-arm/test-data_t-empty_is_empty-crypto
archive/20260929T231919Z-rescue/jean-baptisteboric-eaton/oids-pkcs7-authenticated-attributes
dev/bensze01/public-only-commit
archive/20260929T231919Z-rescue/waleed-elmelegy-arm/psa-key-wrap-aes-kw
archive/20260929T231919Z-rescue/tfloch/psa_add_xts_algorithm
archive/20260929T231919Z-rescue/gilles-peskine-arm/msancf-clang16-crypto
archive/20260929T231919Z-rescue/DemiMarie/document-unexpected-tags
archive/20260929T231919Z-rescue/DemiMarie/strict-len
archive/20260929T231919Z-rescue/valeriosetti/issue9255-tfpsacrypto
archive/20260929T231919Z-rescue/daantimmer/use-compiler-frontend
archive/20260929T231919Z-rescue/benmcollins/enable-rsassa-pss-pkparse
dev/paul-elliott-arm/add_iop_key_agreement_negative_tests
add-iop-export-pub-key-get-num-ops
dev/rc/new-2-d635ea1
dev/bensze01/jenkins
v1.2.0
tf-psa-crypto-1.2.0
v1.1.1
tf-psa-crypto-1.1.1
v1.1.0
tf-psa-crypto-1.1.0
v1.0.0
tf-psa-crypto-1.0.0
v1.0.0-beta
tf-psa-crypto-1.0.0-beta
Labels
Clear labels
api-break
This issue/PR breaks the API and must wait for a new major version
approved
Design and code approved - may be waiting for CI or backports
bug
Something isn't working
component-docs
Docs / website issues filed here for tracking
component-platform
Portability layer and build scripts
component-test
Test framework and CI scripts
dependencies
Pull requests that update a dependency file
deprecation
needs deprecation announcement
DO-NOT-MERGE
enhancement
New feature or request
good first issue
Good for newcomers
help wanted
This issue is not being actively worked on, but PRs welcome.
needs-adoption
stalled PR that someone should pick up and complete
needs-backports
Backports are missing or are pending review and approval.
needs-ci
Needs to pass CI tests
needs-design-approval
Needs design discussion / approval
needs-info
An issue or PR which needs further info from the reporter / author
needs-preceding-pr
Requires another PR to be merged first
needs-review
Every commit must be reviewed by at least two team members
needs-reviewer
This PR needs someone to pick it up for review
needs-work
priority-high
High priority - will be reviewed soon
priority-low
Low priority - this may not receive review soon
priority-medium
Medium priority - this can be reviewed as time permits
priority-scheduled
This PR is big - it will require time to be scheduled for review
priority-very-high
Highest priority - prioritise this over other review work
resolved-after-1.1
The issue is resolved in development, but still present in 1.1 LTS.
single-reviewer
This PR qualifies for having only one reviewer
size-l
Estimated task size: large (2w+)
size-m
Estimated task size: medium (~1w)
size-optimisation
size-s
Estimated task size: small (~2d)
size-xs
Estimated task size: extra small (a few hours at most)
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
Milestone
Clear milestone
No items
No milestone
Assignees
Clear assignees
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set
Reference
gh-Mbed-TLS/TF-PSA-Crypto#521
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
Similar to #515 and #519 but with
check_pair_func. Reminder of the steps:Step 1:
Step 2: the usual.
Step 3: currently wrapping (formerly "opaque") RSA keys are not supported, consider adding support for them as it would probably use the same code path as ECC (just with different sizes).
For
check_pair, I think it's easiest to write the implementation from scratch than do do progressive refactoring:That's already how it's done when the private key is wrapped.
I agree with Gille's proposal for a direct rewrite. I'll note that
get_psa_key_type(prv)was pseudo-code at the time this issue was created, and can now be written asprv->psa_type.Also
get_psa_key_bits()is actuallymbedtls_pk_get_bitlen()of course.I think considering this function quite simple, we don't need a full test matrix (all 5 ways of creating each input context + each type for each input context, etc) and it's enough to ensure full branch coverage in the proposed implementation.
I'll review the existing tests and make a proposal if they need to be extended.
@gilles-peskine-arm Regarding your proposed implementation
I'm really not sure we need to check
get_psa_key_bits(pub) == get_psa_key_bits(prv)in addition to the following two lines (compare raw buffers including their lengths).I think the most important check here is comparing the buffers content (including lengths). I agree we should also check key types in order to enforce proper usage and protect against possible polyglot keys (sequences of bytes that could be parsed either as a valid ECC key or as a valid RSA key - not sure if that's possible or not, but I don't want to have to think about it, so just check the types).
So I'd like to suggest just:
My reasoning is that this matches the (non-policy) mandatory inputs to
psa_import_public_key(): in addition to buffer length and content, key type is a mandatory input (via the attributes), but key size is determined from the buffer (can be set in the attributes too but that's optional).Wdyt? Am I missing something or were you just overly cautious here?
(Where I'm coming from is that I have a hard time coming up with a test case where only the bitlen check would fail, but not the buffer length+content comparison.)
Test design
Review of the existing
Documentation
Currently it says:
I'm not sure that's correct: I think the function already works when prv is a wrapping
ECC key (but not when it's a wrapping RSA key).
Anyway, this limitation is a historical accident and it makes no sense
preserving it. So, let's remove this note from
mbedtls_pk_check_pair()'sdocumentation, and remove the corresponding point from
mbedtls_pk_wrap_psa()'sdocumentation too.
The documentation promises specific error codes on specific conditions. We
should try to preserve them when applicable:
#MBEDTLS_ERR_PK_FEATURE_UNAVAILABLEif the keys could not be checked - wellthat should no longer happen, after lifting the restriction mentioned above.
#PSA_ERROR_INVALID_ARGUMENTif a context is invalid - OK, we should keepreturning that if a context has not been populated, or if we're passed a
public key as the private key argument.
freedom. We can try preserving existing return codes when it's free, but we're
free to change them if that's more convenient.
Existing test functions
pk_psa_utils(): check that it fails with "opaque" (wrapping) contexts (RSA,ECC) -> no longer relevant, remove that.
mbedtls_pk_check_pair(): inputs are two files + expected return code, allowsboth positive and some negative testing.
check_pair()with with both contexts created by parsingcurrently expecting failure for RSA keys, but we're changing that).
pk_copy_from_psa_success(): callscheck_pair()with contexts created bycopy_from_psa()(both public and private). Also has a 2 other contexts:pk_priv_copy_publicandpk_pub_copy_public, created withcopy_public_from_psa()but those are not tested withcheck_pair.Existing test cases
pk_psa_utils:: no longer relevant, we're removingcheck_pair()from here,see above.
mbedtls_pk_check_pair:test cases:pk_copy_from_psa_success:(positive only):Proposed test plan
We keep all existing test functions and cases except for the
check_pair-specific par ofpk_psa_utils()as mentioned above. We also extend the existing test functions and add new test cases for them.Missing test cases to be added
Positive:
mbedtls_pk_check_pair()so that RSA keys are tested the same as ECC keys(actually a simplification, no longer need to distinguish ECC vs RSA).
copy_public_from_psa-> extendpk_copy_from_psa_success()to also callcheck_pairon the existingcontexts
pk_priv_copy_publicandpk_pub_copy_publicin addition to theexisting call.
Negative:
emptycontext inthe existing test function
mbedtls_pk_check_pair(), add calls with (pub,empty) and (empty, prv) and always expect failure (in addition to normal
testing that can either succeed or fail depending on the data).
(prv, prv)? -> as above, we can just add calls with the wrong argument in
the existing test function
mbedtls_pk_check_pair()always expecting failure.(All other items below assume arguments in the correct order and populated.)
should test with both pub larger than prv and prv larger than prv (we want to
make sure our internal
memcmp()never overreads). Can be done by adding newnegative test cases for
mbedtls_pk_check_pair:with varying key sizes. Sincethe function accepts two file names as arguments, it should be a simple matter
of locating existing files with keys of different sizes, and adjusting the
test case dependencies.
again can be done by adding a new case for
mbedtls_pk_check_pair:as above.Missing test cases that we accept
Negative testing is only done with contexts populater by parsing or wrapping,
contexts populated with
copy_from_psa()orcopy_public_from_psa()are onlyused in positive testing. I think that's acceptable considering how simple the
function is, and that positive testing of
copycontexts is enough to establishthat their
pub_rawandpub_raw_lenare correctly populated.Wdty @bjwtaylor @valeriosetti ?
It's definitely possible for two key pairs of different types to have the same public key representation. A simple example would be two different elliptic curves of the same size. Actually finding one would involve solving a discrete log, though. Generally speaking, finding a key pair from a public key is supposed to be hard!
Maybe it's actually feasible between Curve25519 and Ed25519, because of the mathematical relationship between the two curves?
With the same type but different bit-sizes, I don't think it's currently possible to have the same public key representation. As you note,
psa_import_keycan deduce the bit-size from the type and public key representation. However, this isn't an absolute guarantee that we make in the API design. We just tried to make import more convenient, and we've succeeded for all currently defined key types, but we can't promise that we'll always succeed.Conceptually the bit-size is almost part of the key type. I had considered making it part of the key type, but I ended up treating them as separate attributes because I thought it would be too inconvenient sometimes, especially with RSA, key derivation fodder and HMAC, for which there's a wide range of sensible key sizes.
Comparing the bit-sizes is extremely cheap. Not comparing the bit-sizes is probably safe but it's tricky to justify. So I think that omitting the bit-size comparison is a useless risk.
Makes sense. Let's keep the bitlength check then.
Minor update to my proposed test plan then: negative test with two RSA keys of the same bitlength (ie, same modulus size) but public exponents of different byte sizes (eg, one with the usual e = 65537, another with e = 3). This is to ensure branch coverage of the case where the bitlengths are identical but the
pub_raw_lendiffer.It might be the case that all our existing RSA keys have e = 65537, so we may need to generate a test keypair with a different e just for this.
Well it seems to be the case indeed:
However generating a key with a different exponent should be easy:
(Just requires a preliminary PR to the framework to add these two files (and corresponding Makefile entries) before we can use them in tests.)
@mpg, just got round to reviewing this. Mostly makes sense, however just one thing to confirm on wrapped keys. In the current implementation, I've done the first part of inlining the functions and we currently only support wrapped ECC keys. We do not currently support wrapped RSA keys. I've not dug into why this is, though from the above it sounds like it's something we want to investigate further and resolve as there is no architectural reason why this should be the case is this correct?
Indeed, currently we only support
check_pair()for wrapped ECC keys, but not RSA keys. The reason is entirely "we never came around to implementing it for RSA keys", and as you say there is no architectural reason, just historical happenstance.My reasoning is at this point, where we are unifying the implementation for all key types (wrapped or not, RSA or ECC), maintaining the restriction what wrapped RSA keys are not supported would actually make the code (and documentation and tests) more complicated than removing this historical restriction, so I'm suggesting we just remove the restriction. Clearer code, more features, less to document, just slightly different set of things to test.
OK, thanks for the confirmation. I'll get on with working out how to remove this restriction.
Note that the reason I'm suggesting we remove this restriction is I believe there is nothing to work out: just using the simple implementation suggested by Gilles should to the trick. Well, for the implementation part - for the testing part, I've outlined above but basically it's remove the negative test for this case and add a positive one.
Basically the restriction exists because each key type had a different implementation, in particular "wrapped ECC" and "wrapped RSA" had a different one - and we never wrote that for "wrapped RSA". Here, there will be code path to implement them all, and it should "just work" for wrapped RSA as it does for all the others.
So, initially I had a implementation with the check on wrapped RSA removed and the system generated a MBEDTLS_ERR_ASN1_BUF_TOO_SMALL error which David pointed out in this thread nhttps://github.com/Mbed-TLS/TF-PSA-Crypto/pull/580#discussion_r2606315448 eeded to be restored to the original error. So in the current implementation we have a check implemented here
github.com/bjwtaylor/TF-PSA-Crypto@d0b3565e85/drivers/builtin/src/pk.c (L1358)to return, I agree though I can't think of an architectural reason why this should be needed. So I'll look into removing it.