-
-
Notifications
You must be signed in to change notification settings - Fork 216
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* #153: Add initial functionality of including DM token calculation for INSTALL [for load]. Minor refactoring for more clarity. * #153: Extract DM token addition to separate universal handler, use in all commands that require DM token. Replace private key loading implementation. * #153: Simple tests for DelegatedManagementHandler * #153: Refactor DAP properties assignment to separate class. Handle DAP in --install. Extract duplicated CAP loading to separate method. Declare DM token in GlobalPlatform and load it in transitDM. Refactoring. * #153: Sign APDU data for token with crypto.Cipher (RSA/ECB/PKCS1Padding) instead of security.Signature * #153: Fix introduced LGTM alert. Remove DAPProperties setters. Cipher back to Signature. Swap -token to -token-key. * #153: Fix another LGTM error * #153: Fix false assumption that INS_DELETE does not require zero-length of DM token to be transmitted * #153: Include required LFDB hash calculation for load if token-key exists (as per specification). Respect SHA256 option for load if DAP not required. * #153: Add tag '9E' before Delete Token
- Loading branch information
1 parent
5fd2424
commit c8dad37
Showing
8 changed files
with
361 additions
and
164 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package pro.javacard.gp; | ||
|
||
import joptsimple.OptionSet; | ||
import pro.javacard.AID; | ||
|
||
import javax.smartcardio.CardException; | ||
|
||
import static pro.javacard.gp.GPCommandLineInterface.OPT_DAP_DOMAIN; | ||
import static pro.javacard.gp.GPCommandLineInterface.OPT_TO; | ||
|
||
public class DAPProperties { | ||
private AID targetDomain = null; | ||
private AID dapDomain = null; | ||
private boolean required = false; | ||
|
||
public DAPProperties(OptionSet args, GlobalPlatform gp) throws CardException, GPException { | ||
// Override target and check for DAP | ||
if (args.has(OPT_TO)) { | ||
targetDomain = AID.fromString(args.valueOf(OPT_TO)); | ||
if (gp.getRegistry().getDomain(targetDomain) == null) { | ||
throw new GPException("Specified target domain is invalid: " + targetDomain); | ||
} | ||
if (gp.getRegistry().getDomain(targetDomain).getPrivileges().has(GPRegistryEntry.Privilege.DAPVerification)) | ||
required = true; | ||
} | ||
|
||
// Check if DAP block is required | ||
for (GPRegistryEntryApp e : gp.getRegistry().allDomains()) { | ||
if (e.getPrivileges().has(GPRegistryEntry.Privilege.MandatedDAPVerification)) | ||
required = true; | ||
} | ||
|
||
// Check if DAP is overriden | ||
if (args.has(OPT_DAP_DOMAIN)) { | ||
dapDomain = AID.fromString(args.valueOf(OPT_DAP_DOMAIN)); | ||
GPRegistryEntry.Privileges p = gp.getRegistry().getDomain(dapDomain).getPrivileges(); | ||
if (!(p.has(GPRegistryEntry.Privilege.DAPVerification) || p.has(GPRegistryEntry.Privilege.MandatedDAPVerification))) { | ||
throw new GPException("Specified DAP domain does not have (Mandated)DAPVerification privilege: " + p.toString()); | ||
} | ||
} | ||
} | ||
|
||
public AID getTargetDomain() { | ||
return targetDomain; | ||
} | ||
|
||
public AID getDapDomain() { | ||
return dapDomain; | ||
} | ||
|
||
public boolean isRequired() { | ||
return required; | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package pro.javacard.gp; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import javax.smartcardio.CommandAPDU; | ||
import java.io.ByteArrayOutputStream; | ||
import java.security.PrivateKey; | ||
import java.security.Signature; | ||
|
||
import static pro.javacard.gp.GlobalPlatform.INS_DELETE; | ||
|
||
public class DMTokenGenerator { | ||
private static final Logger logger = LoggerFactory.getLogger(DMTokenGenerator.class); | ||
private static final String acceptedSignatureAlgorithm = "SHA1withRSA"; | ||
|
||
private PrivateKey key; | ||
|
||
public DMTokenGenerator(PrivateKey key) { | ||
this.key = key; | ||
} | ||
|
||
public CommandAPDU applyToken(CommandAPDU apdu) { | ||
ByteArrayOutputStream newData = new ByteArrayOutputStream(); | ||
|
||
try { | ||
newData.write(apdu.getData()); | ||
if (apdu.getINS() == INS_DELETE || apdu.getINS() == (INS_DELETE & 255)) { | ||
// See GP 2.3.1 Table 11-23 | ||
logger.debug("Adding tag 0x9E before Delete Token"); | ||
newData.write(0x9E); | ||
} | ||
if (key == null) { | ||
logger.debug("No private key for token generation provided"); | ||
newData.write(0); //Token length | ||
} else { | ||
logger.debug("Using private key for token generation (" + acceptedSignatureAlgorithm + ")"); | ||
byte[] token = calculateToken(apdu, key); | ||
newData.write(token.length); | ||
newData.write(token); | ||
} | ||
return new CommandAPDU(apdu.getCLA(), apdu.getINS(), apdu.getP1(), apdu.getP2(), newData.toByteArray()); | ||
} catch (Exception e) { | ||
throw new RuntimeException("Could not add DM token to constructed APDU", e); | ||
} | ||
} | ||
|
||
private static byte[] calculateToken(CommandAPDU apdu, PrivateKey key) { | ||
return signData(key, getTokenData(apdu)); | ||
} | ||
|
||
private static byte[] getTokenData(CommandAPDU apdu) { | ||
try { | ||
ByteArrayOutputStream bo = new ByteArrayOutputStream(); | ||
bo.write(apdu.getP1()); | ||
bo.write(apdu.getP2()); | ||
bo.write(apdu.getData().length); | ||
bo.write(apdu.getData()); | ||
return bo.toByteArray(); | ||
} catch (Exception e) { | ||
throw new RuntimeException("Could not get P1/P2 or data for token calculation", e); | ||
} | ||
} | ||
|
||
private static byte[] signData(PrivateKey privateKey, byte[] apduData) { | ||
try { | ||
Signature signature = Signature.getInstance(acceptedSignatureAlgorithm); | ||
signature.initSign(privateKey); | ||
signature.update(apduData); | ||
return signature.sign(); | ||
} catch (Exception e) { | ||
throw new RuntimeException("Could not create signature with instance " + acceptedSignatureAlgorithm, e); | ||
} | ||
} | ||
|
||
public boolean hasKey() { | ||
return key != null; | ||
} | ||
|
||
} |
This file contains 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
This file contains 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
Oops, something went wrong.