fix(crypto): strengthen signature length validation#6776
Closed
Federico2014 wants to merge 10 commits into
Closed
Conversation
Sunny6889
reviewed
May 18, 2026
3for
reviewed
May 18, 2026
3for
reviewed
May 18, 2026
6185c26 to
3fa9b53
Compare
Sunny6889
reviewed
May 18, 2026
Sunny6889
reviewed
May 18, 2026
Sunny6889
reviewed
May 18, 2026
Sunny6889
reviewed
May 18, 2026
Sunny6889
reviewed
May 18, 2026
Sunny6889
reviewed
May 18, 2026
Sunny6889
reviewed
May 18, 2026
Sunny6889
reviewed
May 18, 2026
Sunny6889
reviewed
May 19, 2026
bladehan1
reviewed
May 19, 2026
2a687f2 to
ac7889a
Compare
Sunny6889
approved these changes
May 20, 2026
5897571 to
15bc00f
Compare
3for
reviewed
May 21, 2026
…ength_limit # Conflicts: # framework/src/test/java/org/tron/core/capsule/BlockCapsuleTest.java
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
ChainConstant.MIN_SIGNATURE_SIZE(65) andChainConstant.MAX_SIGNATURE_SIZE(68), and centralize the predicate inSignUtils.isValidLength(int size, boolean checkMaxSignatureSize).ForkController.signatureMaxSizeChecked(), which passes only afterVERSION_4_8_2fork stats meet the required threshold.Wallet.broadcastTransaction,TransactionsMsgHandler.check,RelayService.checkHelloMessage).Wallet.getTransactionApprovedListon a lower-bound-only check, so historical transactions with padded signatures remain inspectable.Design Notes
Why use
[65, 68]instead of strict65?After the fork gate is active, the accepted signature-length window is
[65, 68]bytes rather than strict== 65.This is a deliberate compatibility trade-off:
r || s || v).MAX_SIGNATURE_SIZE = 68closes the previously unbounded encoding window while remaining compatible with historical data already on chain.== 65once the compatibility window is no longer needed.Because the bounds are centralized in
ChainConstantand the predicate is centralized inSignUtils.isValidLength, tightening the rule later will be straightforward.Why gate consensus paths with
ForkController.signatureMaxSizeChecked()?Consensus and block-validation paths must be able to replay history. The upper bound on these paths is enforced only after
VERSION_4_8_2passes through the existing fork-stats mechanism:SignUtils.isValidLength(size, false)enforces only the lower bound.SignUtils.isValidLength(size, true)enforces both the lower and upper bounds.ForkController.signatureMaxSizeChecked().ForkController.signatureMaxSizeChecked()delegates toForkController.instance().pass(ForkBlockVersionEnum.VERSION_4_8_2).Wallet.getTransactionApprovedListintentionally passesfalseso historical padded signatures remain readable even after the fork is active.Why enforce both bounds unconditionally on admission paths?
Admission paths see freshly created signatures, not historical chain state, so there is no need to keep a permissive window for replay:
Wallet.broadcastTransaction- local RPC entry; clients producing oversized signatures are misbehaving regardless of fork state.TransactionsMsgHandler.check- P2P transaction ingress; an oversized signature here cannot come from already-on-chain data.RelayService.checkHelloMessage- peer handshake signature, generated on demand from a fresh timestamp.Enforcing
[65, 68]unconditionally on these paths blocks malformed traffic at the edge without affecting historical chain replay.Compatibility
This PR tightens validation behavior, but it does not apply the new upper bound uniformly to every path:
VERSION_4_8_2passes, consensus/block/PBFT validation paths enforce only the lower bound (>= 65).VERSION_4_8_2passes, consensus/block/PBFT validation paths enforce both bounds ([65, 68]).Wallet.broadcastTransaction,TransactionsMsgHandler.check,RelayService.checkHelloMessage) enforce both bounds ([65, 68]) unconditionally.Wallet.getTransactionApprovedListremains intentionally more permissive and continues to skip the upper bound so historical transactions can still be inspected.This means admission policy can be stricter than pre-fork consensus replay. That is intentional because admission only handles fresh inbound data, while consensus replay must preserve historical compatibility.
Breaking Changes
The following public method signatures changed:
TransactionCapsule.checkWeight(Permission, List<ByteString>, byte[], List<ByteString>)(Permission, List<ByteString>, byte[], List<ByteString>, boolean)All in-tree callers were updated.
External JVM consumers of the
chainbaseartifact, such as SDKs, signing services, and third-party tools, must update these call sites. Existing callers will fail at compile time rather than silently misbehave at runtime.Main Code Changes
common/.../config/Parameter.javaMIN_SIGNATURE_SIZE,MAX_SIGNATURE_SIZE, andVERSION_4_8_2/BLOCK_VERSION = 35crypto/.../SignUtils.javaisValidLength(int, boolean)chainbase/.../ForkController.javasignatureMaxSizeChecked()as theVERSION_4_8_2fork gatechainbase/.../DynamicPropertiesStore.javaALLOW_TVM_OSAKA-basedsignatureMaxSizeChecked()helperchainbase/.../TransactionCapsule.javacheckWeight;validateSignatureuses the fork gate, whileaddSignvalidates existing signatures with an unconditional max-size checkchainbase/.../BlockCapsule.javavalidateSignatureframework/.../Wallet.javabroadcastTransaction; keep the read-only approved-list path lower-bound-onlyframework/.../TransactionsMsgHandler.javacheck()for the P2P transaction ingress pathframework/.../RelayService.javacheckHelloMessageframework/.../PbftDataSyncHandler.javaValidPbftSignTaskframework/.../PbftMsgHandler.javaconsensus/.../PbftBaseMessage.javaanalyzeSignatureconsensus/.../PbftMessageHandle.javaactuator/.../TransactionUtil.javacheckWeightusage lower-bound-onlyTest Coverage Added or Updated
ForkControllerTestForkController.signatureMaxSizeChecked()uses realVERSION_4_8_2fork stats: false below threshold, true once 80% stats pass.TransactionCapsuleTestBlockCapsuleTestTransactionExpireTestgetTransactionApprovedListafter Osaka.TransactionUtilTestgetTransactionSignWeight.WalletMockTestbroadcastTransactionadmission path; accept[65, 68].TransactionsMsgHandlerTest[65, 68].RelayServiceTestPbftDataSyncHandlerTestPbftMsgHandlerTestVerification
./gradlew framework:test --tests org.tron.core.ForkControllerTest./gradlew framework:test --tests org.tron.core.capsule.BlockCapsuleTest --tests org.tron.core.capsule.TransactionCapsuleTest --tests org.tron.core.net.messagehandler.PbftDataSyncHandlerTest --tests org.tron.core.net.messagehandler.PbftMsgHandlerTest./gradlew framework:checkstyleMain framework:checkstyleTestgit diff --check