Skip to content

Commit

Permalink
Sanitize RSA signatures; add 2k test keys
Browse files Browse the repository at this point in the history
  • Loading branch information
martinpaljak committed Oct 9, 2024
1 parent 14770e8 commit af7b0f3
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 41 deletions.
23 changes: 2 additions & 21 deletions library/src/main/java/pro/javacard/gp/DAPSigner.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,36 +15,17 @@

public class DAPSigner {


private static final Logger log = LoggerFactory.getLogger(DAPSigner.class);

private DAPSigner() {
}

public static byte[] sign(CAPFile cap, PrivateKey key, GPData.LFDBH hash) throws GeneralSecurityException {
byte[] dtbs = cap.getLoadFileDataHash(hash.algo);
if (key instanceof RSAPrivateKey) {
RSAPrivateKey rkey = (RSAPrivateKey) key;
log.info("Signing DAP with {} RSA and {}", rkey.getModulus().bitLength(), hash);
if ((rkey.getModulus().bitLength() + 7) / 8 == 128) {
// B.3.1 Scheme1 of RSA keys up to 1k
if (!Arrays.asList(GPData.LFDBH.SHA1, GPData.LFDBH.SHA256).contains(hash))
throw new IllegalArgumentException("Unsupported hash for DAP: " + hash);
final Signature signer = Signature.getInstance(String.format("%swithRSA", hash.algo.replace("-", "")));
signer.initSign(key);
signer.update(cap.getLoadFileDataHash(hash.algo));
byte[] dap = signer.sign();
return dap;
} else {
// B.3.2 Scheme2 of RSA keys above 1k
MGF1ParameterSpec mgf = MGF1ParameterSpec.SHA256;
PSSParameterSpec spec = new PSSParameterSpec(mgf.getDigestAlgorithm(), "MGF1", mgf, 32, PSSParameterSpec.TRAILER_FIELD_BC);
Signature signer = Signature.getInstance("RSASSA-PSS");
signer.setParameter(spec);
signer.initSign(key);
signer.update(cap.getLoadFileDataHash(hash.algo));
byte[] dap = signer.sign();
return dap;
}
return GPCrypto.rsa_sign(rkey, dtbs);
} else if (key instanceof ECPrivateKey) {
// B.4.3 ECDSA of GPC 2.3.1
Signature signer = Signature.getInstance("SHA256withECDSA");
Expand Down
19 changes: 1 addition & 18 deletions library/src/main/java/pro/javacard/gp/DMTokenizer.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,27 +109,10 @@ protected boolean canTokenize(CommandAPDU apdu) {

@Override
protected byte[] getToken(CommandAPDU apdu) {
int keylen = (privateKey.getModulus().bitLength() + 7) / 8;
byte[] dtbs = dtbs(apdu);

try {
final byte[] token;
if (keylen == 128) {
// B.3.1 Scheme1 of RSA keys up to 1k
final Signature signer = Signature.getInstance("SHA1withRSA");
signer.initSign(privateKey);
signer.update(dtbs);
token = signer.sign();
} else {
// B.3.2 Scheme2 of RSA keys above 1k
MGF1ParameterSpec mgf = MGF1ParameterSpec.SHA256;
PSSParameterSpec spec = new PSSParameterSpec(mgf.getDigestAlgorithm(), "MGF1", mgf, 32, PSSParameterSpec.TRAILER_FIELD_BC);
Signature signer = Signature.getInstance("RSASSA-PSS");
signer.setParameter(spec);
signer.initSign(privateKey);
signer.update(dtbs);
token = signer.sign();
}
final byte[] token = GPCrypto.rsa_sign(privateKey, dtbs);
log.trace("DM token: {}", HexUtils.bin2hex(token));
return token;
} catch (GeneralSecurityException e) {
Expand Down
31 changes: 31 additions & 0 deletions library/src/main/java/pro/javacard/gp/GPCrypto.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.PSSParameterSpec;
import java.util.Arrays;

// Various cryptographic primitives used for secure channel or plaintext keys
Expand Down Expand Up @@ -264,6 +267,34 @@ public static Key aeskey(byte[] v) {
return new SecretKeySpec(v, "AES");
}

public static byte[] rsa_sign(RSAPrivateKey key, byte[] dtbs) throws GeneralSecurityException {
int keylen = (key.getModulus().bitLength() + 7) / 8;
if (keylen == 128) {
return rsa_scheme1(key, dtbs);
} else {
return rsa_scheme2(key, dtbs);
}
}

public static byte[] rsa_scheme2(RSAPrivateKey key, byte[] dtbs) throws GeneralSecurityException {
// B.3.2 Scheme2 of RSA keys above 1k
MGF1ParameterSpec mgf = MGF1ParameterSpec.SHA256;
PSSParameterSpec spec = new PSSParameterSpec(mgf.getDigestAlgorithm(), "MGF1", mgf, 32, PSSParameterSpec.TRAILER_FIELD_BC);
Signature signer = Signature.getInstance("RSASSA-PSS");
signer.setParameter(spec);
signer.initSign(key);
signer.update(dtbs);
return signer.sign();
}

public static byte[] rsa_scheme1(RSAPrivateKey key, byte[] dtbs) throws GeneralSecurityException {
// B.3.1 Scheme1 of RSA keys up to 1k
final Signature signer = Signature.getInstance("SHA1withRSA");
signer.initSign(key);
signer.update(dtbs);
return signer.sign();
}

// Get a public key from a PEM file, either public key or keypair
public static PublicKey pem2PublicKey(InputStream in) throws IOException {
try (PEMParser pem = new PEMParser(new InputStreamReader(in, StandardCharsets.US_ASCII))) {
Expand Down
7 changes: 5 additions & 2 deletions library/src/main/java/pro/javacard/gp/ReceiptVerifier.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ public AESReceiptVerifier(byte[] aesKey, boolean log_only) {
// XXX: the use of "log only" arguments, boolean function and exceptions is not nice. Refactor
@Override
boolean check(ResponseAPDU response, byte[] context) throws ReceiptVerificationException {
// Context is the concatenation of command parameters sent to the card before receiving the receipt.
byte[] data = response.getData();
if (data[0] == 0x00) {
log.debug("No receipt");
Expand All @@ -77,17 +78,18 @@ boolean check(ResponseAPDU response, byte[] context) throws ReceiptVerificationE
byte[] my = GPCrypto.aes_cmac(aes_key, GPUtils.concatenate(confdata, context), 128);
boolean verified = Arrays.equals(my, card);
if (!verified) {
log.error("Receipt verification: {}", verified);
log.error("Receipt verification failed");
if (!log_only) {
throw new ReceiptVerificationException("Receipt verification failed");
}
} else {
log.info("Receipt verification: {}", verified);
log.info("Receipt verified successfully");
}
return verified;
}
}

// Verifier that never complains.
static public class NullVerifier extends ReceiptVerifier {

public NullVerifier() {
Expand All @@ -99,6 +101,7 @@ boolean check(ResponseAPDU response, byte[] context) {
}
}

// Context data generators for different operatings and receipt types.
public static byte[] load(AID pkg, AID sd) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Expand Down
28 changes: 28 additions & 0 deletions library/src/test/resources/test-dap-rsa-2k.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC4e8Ohwxo6TSUC
bna7+Y7m+SL+tEVauWxMc+2Jt9Fa17PsElVuo5SDXQbiC7V8s+Lt+dcg8m4SVtRw
F7AUmXQPthodFTtesotIV7yp4JA6QZUT2M9BBaSpE7g1rVQo52EffOp5Z+o7uhLS
+9VtaJLsDUV0BUM9hZngaIkE2Gz4vWjuzOdVJBFAI5plBJEwqOdLfUJQFls7KQ0D
c2vKxwlRuDJ78Pdx3japHH3zVueUE3sv8H3ynyafZtjKbcOuzT/NSSDc7OgcCgsO
gTLOkDbMfkmphYCEQzY8khTty8r4SACp78C/IOPmDL+eQ5IkIADaLVTEChwIw+2T
yVKr9PufAgMBAAECggEAVwhcZMYsa3DVku4WKdw0JJdIgSz+wyxTAUZ3u87yf47f
nPGRSF73w3lxs9aeSjR7TJXfffWhJBm+oxspwK4caQUaELphhe1pdDmgEeyVXkZu
VCymqiBFbFaXQwuAdsOhuD8wRxJVGNRR6SNRrwn0tlQUfgW1kSKkU5A9hAGudzHm
GD4bflVAfAX50WnHCg+kUjttKQMOrjtAkLdiaWi1/XYb46SeGd0RBarTMc/+tYVB
03F9c+egGE87A0dR//BZhW0ypb/28ScR5WGYhxy3Sr6SDmjIoTX7Zo6uhIL+cX1K
uRxjVojbtoua4k91JRhIlGG8u9lvGpaP0GMJXQNMMQKBgQDzqxtiEu4zkY/wjgz0
COesiiCqyYIpeYA4UsoNgDwz9/aDmgmkv1uKcbXFVrp6yW9qUqEr3Q+CrDbYGe8u
g1C2ZUiBN2sQUAY0GU8y4V3gOvq7TtfvBct1GWgYNB+1W2mJ4Sd5istFLvRAcHiM
06IxAH9C1j+8DKQFn5T7o9RC8wKBgQDB0eAW2ZQeScoMLXrMRQbxk/kWml2/cvvb
EOAOcv0rC/2FASGmNH8J7Eli6Kk0dWx6xqlZfdR/I0Q+mlFliHe0qaPasP6mQcXH
6upx61TlOFs523llXKF6/CopFFeFgRVoeSLsak041+xR0mmaalzgfM8qAqvUncTW
9KDCidYXpQKBgFh4cMnMG8aHfF6YBOX58bv4ruGzplnOrppEnO4H+FPaHRwtKoEx
pVf/70KGOdDpIFXXSIN3kPEd/A+8YtZdgUmoPooECBB1Lbtu0Q2lPAN1BqJJfyde
0D9lCSF4k2aymQAhysZbeXBWGwLmky52jLYD+zDWP2/Umx0bkulG04O3AoGAekAf
4SnB1EzkpUO2dcuAMrYL4ebiBNTI6Qc+275J03IPqWnqSIRKMP8Z1so7l7wM/W/6
91h3xO2AqR/7AVjPcGOj11fWdxV7Y7rXv50ZAi/G0rqNWpLPw9vz189d2PZvg2MM
1SPDq3v+MinOtDgsdugiXzQqH8SXmKHaGHqKUIUCgYAzMTUuF1Swc3YhVE335r5L
kvWb/prGoqb4bdBDh5V5/lX0Of+1FhJNzY3TAVMWPsX8EhA5aE3YaKBfHVHJgBG0
lpDd3d6rHnEOqsOgoDlfV5eIvFTSctBY+W0DjKhp3oPE5GNqxCeVMsR7pC9NSxmo
ntocMznfHFPv3uG1PXavag==
-----END PRIVATE KEY-----
28 changes: 28 additions & 0 deletions library/src/test/resources/test-dm-rsa-2k.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCyx7TBkPq7lQpE
pKiTPg3XlPeJ10dwYPhPG8db8ON88ZfJtHf/ecXH4nPcjic6rrarQFsX3vOZiqRj
kv/wW6wYMmj1D6XYPELjV4Jd8vA+HTwgy2KrgGvqtL8yfY5UsiiDogk5ilLWFyEh
+PCOgJkbC3kJ9vRcSCTUFo7tZby9wdY22AWkaKWm/Rul3XFeS7oAHONxrDnqUtPa
dgR5lSQIQ0HO0lKi93+uA/tzZceI2i4xm+/jd1zaLyUb3KT6fX6F+C25Lm27KRG2
O0XPNSqDoi4XAUA2J9oE3OTbAPGYq6+sd9Mi1tf3QLxnQ/ctGhkQS9JMELJvWO7w
uHVCAbxfAgMBAAECggEADR0Uof187sUmvNSTyu0f0yLe/2eLmsTPd0SzMbLF36nR
okl7DdcZo1Ogf6/rqmRwtgy2lysoP33Jw3C1Fk/bG+aYB/W5tVaXlMPGpmvbTxW8
4y5CqBAiRP6KEcLfmFB9zp3+7Y9ltm95jjDg5aBYMAF+Q4qvmj9DzaIeoho20cz7
lbW6ciFfxFoUjY4Y4oFJRtXxbG8tJ04kNEKITreGeCa++3+t8mvkzlOT195wGo/G
KY8fOy+KRGOiFvkv6UWGIbwhYlPSy8V3VpLHVrQlThjJaBnycdLm4hAfoIcYz9CE
iTqzBnDrSHIVB3aUagppMF86DzDIld+cw7VEkBV35QKBgQDzcKj2jZE6PooCxzof
k92X65UAs4Qzp3gJJ3JCldERBY2sQlVFAPJfDjiYRtSt3A9SJlmIDzz3tatgQ2LS
HqElWoYKu1yype8p5Af6OSTnC3IySL3btYmcM4YH06bXcVq3SIloLFH7+xE4P1Dz
FKTmscJE7Ey4TCxDTN3v0cIpswKBgQC8AQWA+J7jINleB8J55zay2mR+Xan6E2zg
GouWJ7DyO3ms5XwY+r2RnfjpDpr9PMnTsSgS6IVn1fGrDmO2M5vWIj7foK0YLuzJ
xmO5tQgNmWUqj0WS0+N+9Tkg9rK+KY2bktOXSg838+ltOlV0DidT0wIGYUqouMEC
sWesf8m0pQKBgQDI/I7DYIYyrEeNm6blQ1OEhj/y4EOZ0f5MsICpcL+3afpZ6jo0
Sl/RExCuyGv3TuRnUrpAlzQi356qT3hbOmaZTG+2lJIn/M/Eqjvb3yoUh2K1GVGH
AA6pI/DYrWnmHfRjtkOb+luFyveglMXkq3qp7MET3nRJBLrWpbPmuCux+QKBgBRF
H+zJ4YenkQgcWhF+pl0eQtuFCcCWu5RmCErGOMPFOdc0Xu7qienbWGz4UCmhljkm
zqVLQKbzYD0LLiEE63Zo9tJxpngHByyyISpypE2jDk9KZzvvcIXNtr0hHCB4pnXx
nLKhH4bu22oVcgUzSXY2N++sKbqLQPQjYIQuuvapAoGAMZP+Dp/wvRq2G5FzTiis
aJzmTA9UEyznzhAT4iVpbzuZilcA89Pz8VRQ0L+/dQcX3QKBX3kzRRnMz2B6B++z
6+2A3vojSy2TyMEJ1cPsAcxfZES4ClV9puQjnghdoLMsJ111FDDDeBsSDGfWQ+mh
JXg3n4R7gdD9w/d4fA0CeWY=
-----END PRIVATE KEY-----

0 comments on commit af7b0f3

Please sign in to comment.