Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import static org.tron.common.utils.StringUtil.encode58Check;
import static org.tron.common.utils.WalletUtil.checkPermissionOperations;
import static org.tron.core.Constant.MAX_CONTRACT_RESULT_SIZE;
import static org.tron.core.Constant.MAX_PER_SIGN_LENGTH;
import static org.tron.core.exception.P2pException.TypeEnum.PROTOBUF_ERROR;

import com.google.common.primitives.Bytes;
Expand Down Expand Up @@ -505,6 +506,30 @@ public boolean sanitize() {
return true;
}

public boolean sanitizeSignatures() {
List<ByteString> sigs = this.transaction.getSignatureList();
boolean changed = false;
for (ByteString sig : sigs) {
if (sig.size() > MAX_PER_SIGN_LENGTH) {
changed = true;
break;
}
}
if (!changed) {
return false;
}
Transaction.Builder builder = this.transaction.toBuilder().clearSignature();
for (ByteString sig : sigs) {
if (sig.size() > MAX_PER_SIGN_LENGTH) {
builder.addSignature(sig.substring(0, MAX_PER_SIGN_LENGTH));
} else {
builder.addSignature(sig);
}
}
this.transaction = builder.build();
return true;
}

public void resetResult() {
if (this.getInstance().getRetCount() > 0) {
this.transaction = this.getInstance().toBuilder().clearRet().build();
Expand Down Expand Up @@ -631,7 +656,7 @@ public void addSign(byte[] privateKey, AccountStore accountStore)
.signHash(getTransactionId().getBytes())));
this.transaction = this.transaction.toBuilder().addSignature(sig).build();
}

private static void checkPermission(int permissionId, Permission permission, Transaction.Contract contract) throws PermissionException {
if (permissionId != 0) {
if (permission.getType() != PermissionType.Active) {
Expand Down Expand Up @@ -714,7 +739,7 @@ public boolean validateSignature(AccountStore accountStore,
}
}
isVerified = true;
}
}
return true;
}

Expand Down
18 changes: 0 additions & 18 deletions crypto/src/main/java/org/tron/common/crypto/SignUtils.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
package org.tron.common.crypto;

import static org.tron.core.Constant.MAX_PER_SIGN_LENGTH;
import static org.tron.core.Constant.PER_SIGN_LENGTH;

import java.security.SecureRandom;
import java.security.SignatureException;
import org.tron.common.crypto.ECKey.ECDSASignature;
Expand All @@ -11,21 +8,6 @@

public class SignUtils {

/**
* Strict signature-length check for admission entry-points (RPC broadcast,
* P2P transaction ingress, peer hello handshake). Accepts only sizes in
* [{@link org.tron.core.Constant#PER_SIGN_LENGTH PER_SIGN_LENGTH},
* {@link org.tron.core.Constant#MAX_PER_SIGN_LENGTH MAX_PER_SIGN_LENGTH}].
*
* <p>Consensus paths (e.g. {@code TransactionCapsule.checkWeight}) intentionally
* keep the looser {@code size < 65} check to remain compatible with historical
* on-chain signatures that carry trailing padding bytes; do not call this
* helper from those paths.
*/
public static boolean isValidLength(int size) {
return size >= PER_SIGN_LENGTH && size <= MAX_PER_SIGN_LENGTH;
}

public static SignInterface getGeneratedRandomSign(
SecureRandom secureRandom, boolean isECKeyCryptoEngine) {
if (isECKeyCryptoEngine) {
Expand Down
10 changes: 1 addition & 9 deletions framework/src/main/java/org/tron/core/Wallet.java
Original file line number Diff line number Diff line change
Expand Up @@ -505,15 +505,7 @@ public GrpcAPI.Return broadcastTransaction(Transaction signedTransaction) {
trx.setTime(System.currentTimeMillis());
Sha256Hash txID = trx.getTransactionId();
try {
for (ByteString sig : signedTransaction.getSignatureList()) {
if (!SignUtils.isValidLength(sig.size())) {
String info = "Signature size is " + sig.size();
logger.warn("Broadcast transaction {} has failed, {}.", txID, info);
return builder.setResult(false).setCode(response_code.SIGERROR)
.setMessage(ByteString.copyFromUtf8("Validate signature error: " + info))
.build();
}
}
trx.sanitizeSignatures();

if (tronNetDelegate.isBlockUnsolidified()) {
logger.warn("Broadcast transaction {} has failed, block unsolidified.", txID);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.tron.core.net.message.adv;

import java.util.ArrayList;
import java.util.List;
import org.tron.core.capsule.TransactionCapsule;
import org.tron.core.net.message.MessageTypes;
Expand Down Expand Up @@ -33,6 +34,29 @@ public Protocol.Transactions getTransactions() {
return transactions;
}

public boolean sanitizeSignature() {
List<Transaction> list = transactions.getTransactionsList();
boolean changed = false;
List<Transaction> sanitized = new ArrayList<>(list.size());
for (Transaction trx : list) {
TransactionCapsule cap = new TransactionCapsule(trx);
if (cap.sanitizeSignatures()) {
changed = true;
sanitized.add(cap.getInstance());
} else {
sanitized.add(trx);
}
}
if (!changed) {
return false;
}
Protocol.Transactions.Builder builder = Protocol.Transactions.newBuilder();
sanitized.forEach(builder::addTransactions);
this.transactions = builder.build();
this.data = this.transactions.toByteArray();
return true;
}

@Override
public String toString() {
return new StringBuilder().append(super.toString()).append("trx size: ")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.tron.core.net.messagehandler;

import com.google.protobuf.ByteString;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
Expand All @@ -14,7 +13,6 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.tron.common.crypto.SignUtils;
import org.tron.common.es.ExecutorServiceManager;
import org.tron.common.utils.Sha256Hash;
import org.tron.core.ChainBaseManager;
Expand Down Expand Up @@ -127,6 +125,7 @@ public void processMessage(PeerConnection peer, TronMessage msg) throws P2pExcep
}

private void check(PeerConnection peer, TransactionsMessage msg) throws P2pException {
msg.sanitizeSignature();
List<Transaction> list = msg.getTransactions().getTransactionsList();
Set<Sha256Hash> seen = new HashSet<>(list.size() * 2);
for (Transaction trx : list) {
Expand All @@ -144,12 +143,6 @@ private void check(PeerConnection peer, TransactionsMessage msg) throws P2pExcep
throw new P2pException(TypeEnum.BAD_TRX,
"tx " + item.getHash() + " contract size should be greater than 0");
}
for (ByteString sig : trx.getSignatureList()) {
if (!SignUtils.isValidLength(sig.size())) {
throw new P2pException(TypeEnum.BAD_TRX,
"tx " + item.getHash() + " signature size is " + sig.size());
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.Sha256Hash;
import org.tron.core.ChainBaseManager;
import org.tron.core.Constant;
import org.tron.core.capsule.TransactionCapsule;
import org.tron.core.config.args.Args;
import org.tron.core.db.Manager;
Expand Down Expand Up @@ -150,9 +151,10 @@ public boolean checkHelloMessage(HelloMessage message, Channel channel) {
return false;
}

if (!SignUtils.isValidLength(msg.getSignature().size())) {
int sigSize = msg.getSignature().size();
if (sigSize < Constant.PER_SIGN_LENGTH || sigSize > Constant.MAX_PER_SIGN_LENGTH) {
logger.warn("HelloMessage from {}, signature size is {}.",
channel.getInetAddress(), msg.getSignature().size());
channel.getInetAddress(), sigSize);
return false;
}

Expand Down
49 changes: 11 additions & 38 deletions framework/src/test/java/org/tron/core/WalletMockTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -168,48 +168,21 @@ public void testCreateTransactionCapsuleWithoutValidateWithTimeout()
public void testBroadcastTxInvalidSigLength() throws Exception {
Wallet wallet = new Wallet();
TronNetDelegate tronNetDelegateMock = mock(TronNetDelegate.class);
when(tronNetDelegateMock.isBlockUnsolidified()).thenReturn(true);
Field field = wallet.getClass().getDeclaredField("tronNetDelegate");
field.setAccessible(true);
field.set(wallet, tronNetDelegateMock);

// signature shorter than 65 bytes → SIGERROR
Protocol.Transaction shortSig = Protocol.Transaction.newBuilder()
.addSignature(ByteString.copyFrom(new byte[64]))
.build();
GrpcAPI.Return ret = wallet.broadcastTransaction(shortSig);
assertEquals(GrpcAPI.Return.response_code.SIGERROR, ret.getCode());

// signature longer than 68 bytes → SIGERROR
Protocol.Transaction longSig = Protocol.Transaction.newBuilder()
.addSignature(ByteString.copyFrom(new byte[69]))
.build();
ret = wallet.broadcastTransaction(longSig);
assertEquals(GrpcAPI.Return.response_code.SIGERROR, ret.getCode());

// empty signature → SIGERROR
Protocol.Transaction emptySig = Protocol.Transaction.newBuilder()
.addSignature(ByteString.EMPTY)
.build();
ret = wallet.broadcastTransaction(emptySig);
assertEquals(GrpcAPI.Return.response_code.SIGERROR, ret.getCode());

// tronNetDelegate must not be consulted because the request is rejected up front
Mockito.verify(tronNetDelegateMock, Mockito.never()).isBlockUnsolidified();

// 65-byte signature passes the length check and proceeds to downstream logic
when(tronNetDelegateMock.isBlockUnsolidified()).thenReturn(true);
Protocol.Transaction validSig = Protocol.Transaction.newBuilder()
.addSignature(ByteString.copyFrom(new byte[65]))
.build();
ret = wallet.broadcastTransaction(validSig);
assertEquals(GrpcAPI.Return.response_code.BLOCK_UNSOLIDIFIED, ret.getCode());

// 68-byte signature (upper bound) also passes the length check
Protocol.Transaction paddedSig = Protocol.Transaction.newBuilder()
.addSignature(ByteString.copyFrom(new byte[68]))
.build();
ret = wallet.broadcastTransaction(paddedSig);
assertEquals(GrpcAPI.Return.response_code.BLOCK_UNSOLIDIFIED, ret.getCode());
// Signature length is no longer validated up front — any length proceeds past sanitize and
// reaches downstream logic (here: BLOCK_UNSOLIDIFIED stubbed for short-circuit).
for (int size : new int[] {0, 64, 65, 68, 69, 200}) {
Protocol.Transaction trx = Protocol.Transaction.newBuilder()
.addSignature(ByteString.copyFrom(new byte[size]))
.build();
GrpcAPI.Return ret = wallet.broadcastTransaction(trx);
assertEquals("sig size=" + size,
GrpcAPI.Return.response_code.BLOCK_UNSOLIDIFIED, ret.getCode());
}
}

@Test
Expand Down
Loading
Loading