Conversation
cvc_inherite_ec_group() resolves the curve by walking up to a self-signed CVC, even when the certificate in hand already carries explicit domain parameters (tag 0x81). When the CA named in the CAR has no certificate in the puk store, the walk sets ca_data = NULL, cvc_get_pub() returns NULL and the curve resolves to MBEDTLS_ECP_DP_NONE. That is the case for every key generated through OpenSC: pkcs15init stamps a fixed placeholder issuer into the key's CVC (src/pkcs15init/pkcs15-sc-hsm.c, car = "UTCA00001") for which no certificate exists anywhere. puk_verify() therefore fails and cmd_external_authenticate() rejects every signature with 6985, making n-of-m public key authentication unusable with OpenSC-generated keys. All three callers pass the certificate whose own public key they are about to interpret -- cmd_pso.c then reads tag 0x86 using the returned curve, and cvc.c:440/522 verify with the signer's key -- so reading the certificate's own 0x81 is also more correct than inheriting: a certificate whose explicit parameters differ from its CA's previously resolved to the wrong curve. The walk is retained unchanged for certificates that genuinely omit them. Measured on Pico 2 / RP2350 at fa3fd43, same device, same registered key, only this patch differing: 6.6 stock EXTERNAL AUTHENTICATE -> 6985 6.6 + patch EXTERNAL AUTHENTICATE -> 9000, card reports authenticated=1
Four cases against vectors taken from a live device: an EC key generated through OpenSC (CHR=ESPICOHSMTR00001, CAR=UTCA00001), the same certificate with its domain parameters removed, a self-signed variant, and a CA for the inherited case to resolve against. The regression case -- explicit parameters with an unresolvable CAR -- fails before a0e0a15 and passes after. The other three pass either way, which is what demonstrates that consulting a certificate's own parameters does not change inheritance behaviour. The puk store is stubbed so both branches are reachable deterministically; the remaining externals belong to certificate-writing paths this test does not exercise.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Bug fix.
EXTERNAL AUTHENTICATEalways fails with6985for any key generated throughOpenSC, which makes the M-of-N public key authentication already present in
this tree unusable with that toolchain.
cvc_inherite_ec_group()resolves EC domain parameters by walking up to aself-signed CVC even when the certificate in hand already carries explicit
parameters (tag
0x81). When the CA named in the CAR has no certificate inthe puk store, the walk sets
ca_data = NULL,cvc_get_pub()returns NULL,the curve resolves to
MBEDTLS_ECP_DP_NONE, andpuk_verify()rejects everysignature.
That is the case for every key generated through OpenSC:
pkcs15initstamps afixed placeholder issuer into the key's CVC (
pkcs15-sc-hsm.c,car = "UTCA00001") for which no certificate exists anywhere.The fix uses the certificate's own parameters when present, and walks only
when they are absent and genuinely have to be inherited.
Details / Impact
device on 6.4 as the custodian.
fa3fd433(6.6 tree).certificate whose own public key they are about to interpret —
cmd_pso.creads tag
0x86with the returned curve,cvc.c:440/522verify with thesigner's key — so consulting that certificate's own parameters is also more
correct than inheriting: a certificate whose explicit parameters differ from
its CA's previously resolved to the CA's curve. No change to PIN handling,
key storage, or attestation.
cvc_inherite_ec_group()returns a curve in cases where it previouslyreturned
DP_NONE; the inheritance path is unchanged.Testing
Same device, same commit, same registered key, same custodian; only the patch
differing:
EXTERNAL AUTHENTICATEfa3fd4336985fa3fd433+ patch9000, card reportsauthenticated=1Reversible in both directions (patched → stock → patched), so the result is
not an artefact of one flash.
Steps: generate an EC key on the custodian via
pkcs11-tool, export withsc-hsm-tool -e, register the request on a target initialised with-K 1 -n 1, then run MSE00 22 81 A4(tag83= CHR) →GET CHALLENGE→sign
SHA-256(dev_name || challenge)on the custodian →EXTERNAL AUTHENTICATEwith rawr||s.The second commit adds a unit test over
cvc_inherite_ec_group()with vectorstaken from a live device. The regression case fails without the patch and
passes with it; three further cases covering inheritance via the puk store,
inheritance with no CA available, and the self-signed path pass either way,
which is what shows inheritance behaviour is unchanged.
ctest4/4.Anything else?
Found while implementing the PKA challenge-response over PC/SC, which OpenSC
does not provide (OpenSC/OpenSC#594).
No overlap with #137 — that changes the
dev_namefallback inreset_puk_store(); this changes curve resolution incvc.c.