Skip to content
Merged
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
97 changes: 79 additions & 18 deletions Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -396,6 +396,9 @@ public void process(APDU apdu) {
case INS_GENERATE_KEY_CMD:
processGenerateKey(apdu);
break;
case INS_ATTEST_KEY_CMD:
processAttestKeyCmd(apdu);
break;
case INS_IMPORT_KEY_CMD:
processImportKeyCmd(apdu);
break;
Expand DownExpand Up@@ -1283,16 +1286,17 @@ private KMAttestationCert makeAttestationCert(short attKeyBlob, short attKeyPara

// Add Tags
addTags(hwParameters, true, cert);
addTags(swParameters, false, cert);
short swParams = KMKeyParameters.makeKeystoreEnforced(data[KEY_PARAMETERS], scratchPad);
addTags(swParams, false, cert);
// Add Device Boot locked status
cert.deviceLocked(kmDataStore.isDeviceBootLocked());
// VB data
cert.verifiedBootHash(getVerifiedBootHash(scratchPad));
cert.verifiedBootKey(getBootKey(scratchPad));
cert.verifiedBootState((byte) kmDataStore.getBootState());

// TODO remove the following line
makeKeyCharacteristics(scratchPad);
data[SECRET] = privKey;
data[KEY_BLOB] = origBlob;
return cert;
}

Expand DownExpand Up@@ -3294,13 +3298,9 @@ protected void setVendorPatchLevel(short patch){

private short generateKeyCmd(APDU apdu){
short params = KMKeyParameters.expAny();
short blob = KMByteBlob.exp();
// Array of expected arguments
short cmd = KMArray.instance((short) 4);
short cmd = KMArray.instance((short) 1);
KMArray.cast(cmd).add((short) 0, params); //key params
KMArray.cast(cmd).add((short) 1, blob); //attest key
KMArray.cast(cmd).add((short) 2, params); //attest key params
KMArray.cast(cmd).add((short) 3, blob); //issuer
return receiveIncoming(apdu, cmd);
}

Expand All@@ -3310,10 +3310,6 @@ private void processGenerateKey(APDU apdu) {
// Re-purpose the apdu buffer as scratch pad.
byte[] scratchPad = apdu.getBuffer();
data[KEY_PARAMETERS] = KMArray.cast(cmd).get((short) 0);
data[ATTEST_KEY_BLOB] = KMArray.cast(cmd).get((short) 1);
data[ATTEST_KEY_PARAMS] = KMArray.cast(cmd).get((short) 2);
data[ATTEST_KEY_ISSUER] = KMArray.cast(cmd).get((short) 3);
data[CERTIFICATE] = KMArray.instance((short)0); //by default the cert is empty.
// ROLLBACK_RESISTANCE not supported.
KMTag.assertAbsence(data[KEY_PARAMETERS], KMType.BOOL_TAG,KMType.ROLLBACK_RESISTANCE, KMError.ROLLBACK_RESISTANCE_UNAVAILABLE);

Expand DownExpand Up@@ -3359,22 +3355,84 @@ private void processGenerateKey(APDU apdu) {
// create key blob and associated attestation.
data[ORIGIN] = KMType.GENERATED;
makeKeyCharacteristics(scratchPad);
generateAttestation(data[ATTEST_KEY_BLOB], data[ATTEST_KEY_PARAMS],scratchPad);
createEncryptedKeyBlob(scratchPad);
// Remove custom tags from key characteristics
short teeParams = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getTeeEnforced();
if(teeParams != KMType.INVALID_VALUE) {
KMKeyParameters.cast(teeParams).deleteCustomTags();
}
// prepare the response
short resp = KMArray.instance((short) 4);
short resp = KMArray.instance((short) 3);
KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK));
KMArray.cast(resp).add((short) 1, data[KEY_BLOB]);
KMArray.cast(resp).add((short) 2, data[KEY_CHARACTERISTICS]);
KMArray.cast(resp).add((short) 3, data[CERTIFICATE]);
sendOutgoing(apdu, resp);
}

private short generateAttestKeyCmd(APDU apdu) {
short params = KMKeyParameters.expAny();
short blob = KMByteBlob.exp();
// Array of expected arguments
short cmd = KMArray.instance((short) 5);
KMArray.cast(cmd).add((short) 0, blob); // key blob
KMArray.cast(cmd).add((short) 1, params); // keyparamters to be attested.
KMArray.cast(cmd).add((short) 2, blob); // attest key blob
KMArray.cast(cmd).add((short) 3, params); // attest key params
KMArray.cast(cmd).add((short) 4, blob); // attest issuer

return receiveIncoming(apdu, cmd);
}

public void getAttestKeyInputParameters(short arrPtr, short[] data, byte keyBlobOff,
byte keyParametersOff,
byte attestKeyBlobOff, byte attestKeyParamsOff, byte attestKeyIssuerOff) {
data[keyBlobOff] = KMArray.cast(arrPtr).get((short) 0);
data[keyParametersOff] = KMArray.cast(arrPtr).get((short) 1);
data[attestKeyBlobOff] = KMType.INVALID_VALUE;
data[attestKeyParamsOff] = KMType.INVALID_VALUE;
data[attestKeyIssuerOff] = KMType.INVALID_VALUE;
}

private void processAttestKeyCmd(APDU apdu) {
// Receive the incoming request fully from the master into buffer.
short cmd = generateAttestKeyCmd(apdu);
// Re-purpose the apdu buffer as scratch pad.
byte[] scratchPad = apdu.getBuffer();
data[KEY_BLOB] = KMArray.cast(cmd).get((short) 0);
data[KEY_PARAMETERS] = KMArray.cast(cmd).get((short) 1);
data[ATTEST_KEY_BLOB] = KMArray.cast(cmd).get((short) 2);
data[ATTEST_KEY_PARAMS] = KMArray.cast(cmd).get((short) 3);
data[ATTEST_KEY_ISSUER] = KMArray.cast(cmd).get((short) 4);

data[CERTIFICATE] = KMArray.instance((short) 0); //by default the cert is empty.

// Check for app id and app data.
data[APP_ID] =
KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_ID, data[KEY_PARAMETERS]);
data[APP_DATA] =
KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_DATA, data[KEY_PARAMETERS]);
if (data[APP_ID] != KMTag.INVALID_VALUE) {
data[APP_ID] = KMByteTag.cast(data[APP_ID]).getValue();
}
if (data[APP_DATA] != KMTag.INVALID_VALUE) {
data[APP_DATA] = KMByteTag.cast(data[APP_DATA]).getValue();
}
// parse key blob
parseEncryptedKeyBlob(data[KEY_BLOB], data[APP_ID], data[APP_DATA], scratchPad);
// The key which is being attested should be asymmetric i.e. RSA or EC
short alg = KMEnumTag.getValue(KMType.ALGORITHM, data[HW_PARAMETERS]);
if (alg != KMType.RSA && alg != KMType.EC) {
KMException.throwIt(KMError.INCOMPATIBLE_ALGORITHM);
}
// Build certificate
generateAttestation(data[ATTEST_KEY_BLOB], data[ATTEST_KEY_PARAMS], scratchPad);

short resp = KMArray.instance((short) 2);
KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK));
KMArray.cast(resp).add((short) 1, data[CERTIFICATE]);
sendOutgoing(apdu, resp);
}

private short getAttestationMode(short attKeyBlob, short attChallenge){
short alg = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, data[KEY_PARAMETERS]);
short mode = KMType.NO_CERT;
Expand DownExpand Up@@ -3419,7 +3477,7 @@ private void generateAttestation(short attKeyBlob, short attKeyParam, byte[] sc

switch (mode){
case KMType.ATTESTATION_CERT:
cert = makeAttestationCert(attKeyBlob,attKeyParam, attChallenge, data[ATTEST_KEY_ISSUER],data[HW_PARAMETERS],
cert = makeAttestationCert(attKeyBlob,attKeyParam, attChallenge, data[ATTEST_KEY_ISSUER],data[HW_PARAMETERS],
data[SW_PARAMETERS], scratchPad);
break;
case KMType.SELF_SIGNED_CERT:
Expand DownExpand Up@@ -3838,7 +3896,7 @@ private static void makeAuthData(byte[] scratchPad) {
KMArray.cast(params).add((short) 2, data[PUB_KEY]);
}

short authIndex = repository.alloc(MAX_AUTH_DATA_SIZE);
short authIndex = repository.allocReclaimableMemory(MAX_AUTH_DATA_SIZE);
short index = 0;
short len = 0;
short paramsLen = KMArray.cast(params).length();
Expand All@@ -3855,7 +3913,10 @@ private static void makeAuthData(byte[] scratchPad) {
}
index++;
}
data[AUTH_DATA] = authIndex;
short authDataIndex = repository.alloc(len);
Util.arrayCopyNonAtomic(repository.getHeap(), authIndex, repository.getHeap(), authDataIndex, len);
repository.reclaimMemory(MAX_AUTH_DATA_SIZE);
data[AUTH_DATA] = authDataIndex;
data[AUTH_DATA_LENGTH] = len;
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,7 +32,7 @@
*/
public class KMRepository {

public static final short HEAP_SIZE = 15000;
public static final short HEAP_SIZE = 10000;

// Class Attributes
private byte[] heap;
Expand Down
27 changes: 23 additions & 4 deletions HAL/JavacardKeyMintDevice.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -33,6 +33,7 @@
#include <vector>

namespace aidl::android::hardware::security::keymint {
using km_utils::KmParamSet;
using namespace ::keymaster;
using namespace ::keymint::javacard;

Expand DownExpand Up@@ -81,19 +82,37 @@ ScopedAStatus JavacardKeyMintDevice::generateKey(const vector<KeyParameter>& key
cppbor::Array array;
// add key params
cbor_.addKeyparameters(array, keyParams);
// add attestation key if any
cbor_.addAttestationKey(array, attestationKey);
auto [item, err] = card_->sendRequest(Instruction::INS_GENERATE_KEY_CMD, array);
if (err != KM_ERROR_OK) {
LOG(ERROR) << "Error in sending generateKey.";
return km_utils::kmError2ScopedAStatus(err);
}
if (!cbor_.getBinaryArray(item, 1, creationResult->keyBlob) ||
!cbor_.getKeyCharacteristics(item, 2, creationResult->keyCharacteristics) ||
!cbor_.getCertificateChain(item, 3, creationResult->certificateChain)) {
!cbor_.getKeyCharacteristics(item, 2, creationResult->keyCharacteristics)) {
LOG(ERROR) << "Error in decoding og response in generateKey.";
return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR);
}

AuthorizationSet paramSet;
paramSet.Reinitialize(KmParamSet(keyParams));
// Call attestKey only Asymmetric algorithms.
keymaster_algorithm_t algorithm;
paramSet.GetTagValue(TAG_ALGORITHM, &algorithm);
if (algorithm == KM_ALGORITHM_RSA || algorithm == KM_ALGORITHM_EC) {
cppbor::Array attestKeyArray;
attestKeyArray.add(creationResult->keyBlob);
cbor_.addKeyparameters(attestKeyArray, keyParams);
cbor_.addAttestationKey(attestKeyArray, attestationKey);
auto [item, err] = card_->sendRequest(Instruction::INS_ATTEST_KEY_CMD, attestKeyArray);
if (err != KM_ERROR_OK) {
LOG(ERROR) << "Failed in attestKey err: ";
return km_utils::kmError2ScopedAStatus(err);
}
if (!cbor_.getCertificateChain(item, 1, creationResult->certificateChain)) {
LOG(ERROR) << "Error in decoding og response in generateKey.";
return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR);
}
}
return ScopedAStatus::ok();
}

Expand Down