/*
*******************************************************************************
* Java Card Bitcoin Hardware Wallet
* (c) 2015 Ledger
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*******************************************************************************
*/
package com.ledger.wallet.test;
import java.math.BigInteger;
import java.util.Arrays;
import junit.framework.TestCase;
import com.licel.jcardsim.base.Simulator;
import com.licel.jcardsim.utils.AIDUtil;
import com.licel.jcardsim.utils.ByteUtil;
import com.licel.jcardsim.bouncycastle.asn1.ASN1Sequence;
import com.licel.jcardsim.bouncycastle.asn1.ASN1EncodableVector;
import com.licel.jcardsim.bouncycastle.asn1.ASN1Primitive;
import com.licel.jcardsim.bouncycastle.asn1.DERInteger;
import com.licel.jcardsim.bouncycastle.asn1.DERSequence;
import javacard.framework.AID;
import javacard.framework.ISO7816;
import com.ledger.wallet.LedgerWalletApplet;
import com.btchip.BTChipDongle;
import com.btchip.BTChipConstants;
import com.btchip.BTChipException;
public abstract class AbstractTest extends TestCase {
private static final BigInteger HALF_ORDER = new BigInteger(ByteUtil.byteArray("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0"));
private static final BigInteger ORDER = new BigInteger(1, ByteUtil.byteArray("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"));
public static final AID LOAD_FILE_AID = AIDUtil.create("FF4C4547522E57414C543031");
public static final byte[] INSTANCE_AID_DATA = ByteUtil.byteArray("FF4C4547522E57414C5430312E493031");
public static final AID INSTANCE_AID = AIDUtil.create(INSTANCE_AID_DATA);
public static final int TESTNET_VERSION = 111;
public static final int TESTNET_P2SH_VERSION = 196;
public static final byte[] DEFAULT_PIN = "1234".getBytes();
// release afford clump fury license speak hungry remain crouch exile basic choose bar client own clip like armor forum fossil energy eight seven sausage
public static final byte[] DEFAULT_SEED = ByteUtil.byteArray("d3c9b5146da60ebb8216ced62ecfc3a7dd3c7dc98f41a35e841cd5a659f0991bb7562be0d1138b2a5df2512004c8374162a2970d2a1277001f6614172e44f033");
public static final byte DEFAULT_KEYCARD_ADDRESS_SIZE = (byte)4;
public static final byte[] DEFAULT_KEYCARD = ByteUtil.byteArray("f27c395759a14d3aec2135188d670d8e");
protected Simulator simulator;
protected Simulator prepareSimulator() {
byte[] parameters = new byte[INSTANCE_AID_DATA.length + 3];
parameters[0] = (byte)INSTANCE_AID_DATA.length;
System.arraycopy(INSTANCE_AID_DATA, 0, parameters, 1, INSTANCE_AID_DATA.length);
Simulator tmpSimulator = new Simulator();
tmpSimulator.installApplet(LOAD_FILE_AID, LedgerWalletApplet.class, parameters, (short)0, (byte)parameters.length);
return tmpSimulator;
}
protected BTChipDongle getDongle(boolean debug) throws BTChipException {
this.simulator = prepareSimulator();
assertTrue(simulator.selectApplet(INSTANCE_AID));
JCardSIMTransport transport = new JCardSIMTransport(simulator, debug);
BTChipDongle dongle = new BTChipDongle(transport);
dongle.setKeycardSeed(DEFAULT_KEYCARD_ADDRESS_SIZE, DEFAULT_KEYCARD);
return dongle;
}
protected BTChipDongle getDongle() throws BTChipException {
return getDongle(false);
}
protected BTChipDongle prepareDongleRestoreTestnet(boolean debug) throws BTChipException {
BTChipDongle dongle = getDongle(debug);
dongle.setup(
new BTChipDongle.OperationMode[] { BTChipDongle.OperationMode.WALLET },
new BTChipDongle.Feature[] { BTChipDongle.Feature.RFC6979, BTChipDongle.Feature.NO_2FA_P2SH},
TESTNET_VERSION,
TESTNET_P2SH_VERSION,
DEFAULT_PIN,
null,
BTChipConstants.QWERTY_KEYMAP,
DEFAULT_SEED,
null);
return dongle;
}
protected void reset() throws BTChipException {
simulator.reset();
assertTrue(simulator.selectApplet(INSTANCE_AID));
}
protected byte[] canonicalizeSignature(byte[] signature) throws BTChipException {
try {
ASN1Sequence seq = (ASN1Sequence)ASN1Primitive.fromByteArray(signature);
BigInteger r = ((DERInteger)seq.getObjectAt(0)).getValue();
BigInteger s = ((DERInteger)seq.getObjectAt(1)).getValue();
if (s.compareTo(HALF_ORDER) > 0) {
s = ORDER.subtract(s);
}
else {
return signature;
}
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(new DERInteger(r));
v.add(new DERInteger(s));
return new DERSequence(v).getEncoded("DER");
}
catch(Exception e) {
throw new BTChipException("Error canonicalizing signature", e);
}
}
}