Repository navigation
Skip the redundant signature verification for normal CAs. - #11892
yosuke-wolfssl wants to merge 1 commit into
Conversation
|
b64333d to
b147ee5
Compare
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #11892
Scan targets checked: wolfcrypt-src, wolfcrypt-bugs
Coverage: 1 of 1 in-scope changed file(s) opened by the reviewer
Findings: 1
1 finding(s) posted as inline comments (see file-level comments below)
This review was generated automatically by Fenrir. Reported findings require changes before merge.
Review tier: Lite
b147ee5 to
b23f009
Compare
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #11892
Scan targets checked: wolfcrypt-src, wolfcrypt-bugs, wolfssl-src, wolfssl-bugs
Coverage: 1 of 3 in-scope changed file(s) opened by the reviewer; not opened: tests/api.c, wolfssl/wolfcrypt/asn.h
Findings: 1
1 finding(s) posted as inline comments (see file-level comments below)
This review was generated automatically by Fenrir. Reported findings require changes before merge.
Review tier: Lite
b23f009 to
ef7749a
Compare
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #11892
Scan targets checked: wolfssl-src, wolfssl-bugs
Unchanged since last review (not re-run): wolfcrypt-src, wolfcrypt-bugs
Coverage: 1 of 2 in-scope changed file(s) opened by the reviewer; not opened: tests/api.c
Findings: 1
1 finding(s) posted as inline comments (see file-level comments below)
This review was generated automatically by Fenrir. Reported findings require changes before merge.
Review tier: Lite
ef7749a to
15797c4
Compare
Frauschi
left a comment
There was a problem hiding this comment.
Thanks for chasing down the memory cost from #11334. Skipping the self-signature check for AKID == SKID roots looks sound for the common case. A few comments: the VERIFY_NAME change sets selfSigned from a key that isn't guaranteed to be the one that verified the signature, the skip is a bit broader than the root case it targets, and the new tests don't exercise the changed path yet.
| } | ||
| #endif /* WOLFSSL_DUAL_ALG_CERTS */ | ||
| } | ||
| else if (verify == VERIFY_NAME) { |
There was a problem hiding this comment.
This assumes cert->ca holds the key that verified the signature, which isn't guaranteed here. Under WOLFSSL_SMALL_CERT_VERIFY the check was done by wc_CheckCertSignature(), which looks up its own CA in the cert manager only, while ParseCertRelative() can take cert->ca from the CSR v2 pending list first. Also, if sigRet failed and the verify callback overrides it, selfSigned still gets set from a plain key compare.
selfSigned exempts a chain CA from CheckChainCAExtKeyUsage(), so it should only come from a verified signature. --enable-lowresource turns on WOLFSSL_SMALL_CERT_VERIFY, so this branch is probably part of your numbers and just dropping it isn't free. Could the small-cert path pass down the key it actually verified with (and nothing when sigRet != 0), and compare against that?
There was a problem hiding this comment.
Done as suggested. The small-cert path now calls the new wc_CheckCertSignature_ex(), which reports the key of the CA that verified the signature. selfSigned is set from that key only when sigRet == 0, and ParseCertRelative() no longer derives it under VERIFY_NAME. Peak heap is unchanged.
| XMEMCMP(sigKey, cert->publicKey, cert->pubKeySize) == 0; | ||
| } | ||
| else if (cert->selfIssued) { | ||
| else if (cert->selfIssued && (type != CA_TYPE || !cert->extAuthKeyIdSet || |
There was a problem hiding this comment.
A genuinely self-signed root whose AKID doesn't match its SKID now ends up with selfSigned = 0: this skips ConfirmSelfSignature(), and UserRootEndsNcWalk() doesn't mark it either. Think of a renewed root whose AKID still names the old key, or one whose AKID was computed with a different key-ID method than ours. The name-constraint walk then continues past it and can pick up another same-DN CA's constraints, or fall back to a name lookup under NO_SKID, which is the case test_NameConstraints_SameDnRoots is about. Worst case is a spurious ASN_NAME_INVALID_E, not a bypass.
Could the skip be limited to AKID == SKID? That's the case the memory saving targets, and anything else keeps the full check.
There was a problem hiding this comment.
Done: the skip now needs AKID == SKID; anything else gets the full check. test_NameConstraints_RootAkid covers a renewed root with a stale AKID.
|
|
||
| /* Returns 1 when a user-trusted CA is a root that ends the name-constraint | ||
| * walk without its self-signature being verified. */ | ||
| static int UserRootEndsNcWalk(const DecodedCert* cert) |
There was a problem hiding this comment.
I don't think this is needed. When the root has an AKID, FindSignerByAkidOrName() treats it as authoritative, and AlreadySigner() dedups by SKID (by subject name under NO_SKID), so for an AKID == SKID root the walk finds the root itself and stops on ncParent == ncSigner. I forced this to return 0 in an --enable-all build and the whole API suite still passed.
Dropping it keeps Signer::selfSigned meaning what it says (the asn.h comment change can go too), and there's no second copy of the KU/AKID condition from ParseCertRelative() to keep in sync.
There was a problem hiding this comment.
Agreed, removed along with the asn.h comment change.
| /* Two trusted roots share a DN and carry no AKID, so a name lookup from one | ||
| * root can return the other. Each root's leaf must be checked against its own | ||
| * root's nameConstraints only, whichever root the lookup returns. */ | ||
| static int test_NameConstraints_SameDnRoots(void) |
There was a problem hiding this comment.
Both new tests pass without the library change: I reverted ssl_certman.c, asn.c and asn.h to the base commit and they still pass. SameDnRoots builds roots without an AKID, so they still go through ConfirmSelfSignature(), and in RolloverCa K already got selfSigned = 0 from the old check.
Could you add a case for the path this PR changes? A trusted root with AKID == SKID and nameConstraints, plus a self-signed root whose AKID doesn't match its SKID, would cover it.
There was a problem hiding this comment.
Added test_NameConstraints_RootAkid. Its renewed-root case fails without the AKID == SKID condition.
|
|
||
| /* R's nameConstraints must reach leaves of K, a trusted key-rollover CA under | ||
| * R, with or without an AKID in K. */ | ||
| static int test_NameConstraints_RolloverCa(void) |
There was a problem hiding this comment.
These two tests load two CAs with the same DN, so the guard needs !defined(NO_SKID). Under NO_SKID, AlreadySigner() and HashSigner() key on the subject name, so the second CA isn't added and both tests would fail. I haven't built that config, so please double-check.
There was a problem hiding this comment.
Doen as suggested
15797c4 to
300fce8
Compare
- a CA_TYPE cert now skips ConfirmSelfSignature() only when its AKID is set and equals its SKID, and Key Usage allows keyCertSign - wc_CheckCertSignature_ex() reports the key of the CA that verified the signature; wc_CheckCertSignature() calls it without one. - CheckCertSignature_ex() in asn.c and asn_orig.c fills that key. - ProcessPeerCertParse() sets selfSigned on the small-cert path when the signature verified with the certificate's own key.
300fce8 to
89a2464
Compare
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #11892
Scan targets checked: wolfcrypt-src, wolfcrypt-bugs, wolfssl-src, wolfssl-bugs
Not reviewed (no scan target covers them): doc/dox_comments/header_files/asn.h
Coverage: 5 of 5 in-scope changed file(s) opened by the reviewer
Fenrir result: Approved ✅
No new issues found in the changed files.
Advisory only — this automated result does not count as a GitHub approval.
Review tier: Lite
Fenrir's latest completed scan found no issues; clearing the prior automated change request.
|
Hi @Frauschi , |
Problem
PR #11334 introduced selfSigned and its verifier ConfirmSelfSignature.
It increased the memory usage for CA loads unconditionally.
The PR recognized the runtime cost only.
Fix
a CA_TYPE cert now skips ConfirmSelfSignature() only when its AKID is set and equals its SKID, and Key Usage allows keyCertSign.
Also, ProcessPeerCertParse() sets selfSigned on the small-cert path when the signature verified with the certificate's own key. wc_CheckCertSignature_ex() is added for the purpose.
Test
make check with --enable-all: pass.
Verification (peak heap)
Built the
low_eccandlow_rsa2048configs from nightly-memusage-v2, plus--enable-trackmemory, and ran one mutual-auth TLS 1.2 handshake betweenexamples/server/serverandexamples/client/client. Numbers are thepeak Bytesline each process prints on exit (whole process, CA loadincluded); repeated runs gave identical numbers.
-c certs/server-ecc.pem -k certs/ecc-key.pem -A certs/client-ecc-cert.pem,client
-A certs/ca-ecc-cert.pem -c certs/client-ecc-cert.pem -k certs/ecc-client-key.pem