3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-02-11 17:55:53 +00:00

DefaultRiskAnalysis.isStandard checks for signatures to use canonical DER encoding. Adds a test.

This commit is contained in:
Andreas Schildbach 2014-12-20 01:15:47 +01:00
parent 121d2fcb63
commit 2fa5ba30e2
2 changed files with 38 additions and 2 deletions

View File

@ -18,12 +18,15 @@
package org.bitcoinj.wallet; package org.bitcoinj.wallet;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.ECKey.ECDSASignature;
import org.bitcoinj.core.NetworkParameters; import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.Transaction; import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionConfidence; import org.bitcoinj.core.TransactionConfidence;
import org.bitcoinj.core.TransactionInput; import org.bitcoinj.core.TransactionInput;
import org.bitcoinj.core.TransactionOutput; import org.bitcoinj.core.TransactionOutput;
import org.bitcoinj.core.Wallet; import org.bitcoinj.core.Wallet;
import org.bitcoinj.crypto.TransactionSignature;
import org.bitcoinj.script.ScriptChunk; import org.bitcoinj.script.ScriptChunk;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -111,7 +114,8 @@ public class DefaultRiskAnalysis implements RiskAnalysis {
VERSION, VERSION,
DUST, DUST,
SHORTEST_POSSIBLE_PUSHDATA, SHORTEST_POSSIBLE_PUSHDATA,
NONEMPTY_STACK // Not yet implemented (for post 0.12) NONEMPTY_STACK, // Not yet implemented (for post 0.12)
SIGNATURE_CANONICAL_ENCODING
} }
/** /**
@ -168,6 +172,19 @@ public class DefaultRiskAnalysis implements RiskAnalysis {
for (ScriptChunk chunk : input.getScriptSig().getChunks()) { for (ScriptChunk chunk : input.getScriptSig().getChunks()) {
if (chunk.data != null && !chunk.isShortestPossiblePushData()) if (chunk.data != null && !chunk.isShortestPossiblePushData())
return RuleViolation.SHORTEST_POSSIBLE_PUSHDATA; return RuleViolation.SHORTEST_POSSIBLE_PUSHDATA;
if (chunk.isPushData()) {
ECDSASignature signature;
try {
signature = ECKey.ECDSASignature.decodeFromDER(chunk.data);
} catch (RuntimeException x) {
// Doesn't look like a signature.
signature = null;
}
if (signature != null) {
if (!TransactionSignature.isEncodingCanonical(chunk.data))
return RuleViolation.SIGNATURE_CANONICAL_ENCODING;
}
}
} }
return RuleViolation.NONE; return RuleViolation.NONE;
} }

View File

@ -17,14 +17,17 @@
package org.bitcoinj.wallet; package org.bitcoinj.wallet;
import com.google.common.collect.Lists; import java.util.Arrays;
import org.bitcoinj.core.*; import org.bitcoinj.core.*;
import org.bitcoinj.crypto.TransactionSignature;
import org.bitcoinj.params.MainNetParams; import org.bitcoinj.params.MainNetParams;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.ScriptBuilder; import org.bitcoinj.script.ScriptBuilder;
import org.bitcoinj.script.ScriptChunk; import org.bitcoinj.script.ScriptChunk;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import org.bitcoinj.wallet.DefaultRiskAnalysis; import org.bitcoinj.wallet.DefaultRiskAnalysis;
import org.bitcoinj.wallet.RiskAnalysis; import org.bitcoinj.wallet.RiskAnalysis;
import org.bitcoinj.wallet.DefaultRiskAnalysis.RuleViolation;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -162,6 +165,22 @@ public class DefaultRiskAnalysisTest {
assertEquals(DefaultRiskAnalysis.RuleViolation.SHORTEST_POSSIBLE_PUSHDATA, DefaultRiskAnalysis.isStandard(tx)); assertEquals(DefaultRiskAnalysis.RuleViolation.SHORTEST_POSSIBLE_PUSHDATA, DefaultRiskAnalysis.isStandard(tx));
} }
@Test
public void canonicalSignature() {
TransactionSignature sig = TransactionSignature.dummy();
Script scriptOk = ScriptBuilder.createInputScript(sig);
assertEquals(RuleViolation.NONE,
DefaultRiskAnalysis.isInputStandard(new TransactionInput(params, null, scriptOk.getProgram())));
byte[] sigBytes = sig.encodeToBitcoin();
// Appending a zero byte makes the signature uncanonical without violating DER encoding.
Script scriptUncanonicalEncoding = new ScriptBuilder().data(Arrays.copyOf(sigBytes, sigBytes.length + 1))
.build();
assertEquals(RuleViolation.SIGNATURE_CANONICAL_ENCODING,
DefaultRiskAnalysis.isInputStandard(new TransactionInput(params, null, scriptUncanonicalEncoding
.getProgram())));
}
@Test @Test
public void standardOutputs() throws Exception { public void standardOutputs() throws Exception {
Transaction tx = new Transaction(params); Transaction tx = new Transaction(params);