From e4484e9731e4e806bca3984fce219c8afa742ef2 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Mon, 5 Oct 2020 19:36:18 +0100 Subject: [PATCH 01/42] JCOP Provider Implementation --- .../keymaster/KMAttestationCertImpl.java | 973 ++++++++++++ .../javacard/keymaster/KMInstance.java | 7 + .../javacard/keymaster/KMJCOPSimProvider.java | 1371 +++++++++++++++++ .../javacard/keymaster/KMOperationImpl.java | 240 +++ .../keymaster/KMRsa2048NoDigestSignature.java | 135 ++ .../javacard/keymaster/KMSEProviderImpl.java | 8 + .../javacard/keymaster/KMOperationImpl.java | 6 + .../javacard/keymaster/KMKeymasterApplet.java | 5 +- .../javacard/keymaster/KMOperation.java | 2 + .../javacard/keymaster/KMOperationState.java | 7 +- 10 files changed, 2749 insertions(+), 5 deletions(-) create mode 100644 Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java create mode 100644 Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMInstance.java create mode 100644 Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMJCOPSimProvider.java create mode 100644 Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMOperationImpl.java create mode 100644 Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java create mode 100644 Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMSEProviderImpl.java diff --git a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java new file mode 100644 index 00000000..34a3b695 --- /dev/null +++ b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -0,0 +1,973 @@ +package com.android.javacard.keymaster; + +import javacard.framework.JCSystem; +import javacard.framework.Util; + +// The class encodes strongbox generated amd signed attestation certificate. This only encodes +// required fields of the certificates. It is not meant to be generic X509 cert encoder. +// Whatever fields that are fixed are added as byte arrays. The Extensions are encoded as per +// the values. +// The certificate is assembled with leafs first and then the sequences. + +public class KMAttestationCertImpl implements KMAttestationCert { + private static final byte MAX_PARAMS = 30; + // DER encoded object identifiers required by the cert. + // rsaEncryption - 1.2.840.113549.1.1.1 + private static final byte[] rsaEncryption = { + 0x06, 0x09, 0x2A, (byte) 0x86, 0x48, (byte) 0x86, (byte) 0xF7, 0x0D, 0x01, 0x01, 0x01 + }; + // ecPublicKey - 1.2.840.10045.2.1 + private static final byte[] eccPubKey = { + 0x06, 0x07, 0x2A, (byte) 0x86, 0x48, (byte) 0xCE, 0x3D, 0x02, 0x01 + }; + // prime256v1 curve - 1.2.840.10045.3.1.7 + private static final byte[] prime256v1 = { + 0x06, 0x08, 0x2A, (byte) 0x86, 0x48, (byte) 0xCE, 0x3D, 0x03, 0x01, 0x07 + }; + // Key Usage Extn - 2.5.29.15 + private static final byte[] keyUsageExtn = {0x06, 0x03, 0x55, 0x1D, 0x0F}; + // Android Extn - 1.3.6.1.4.1.11129.2.1.17 + private static final byte[] androidExtn = { + 0x06, 0x0A, 0X2B, 0X06, 0X01, 0X04, 0X01, (byte) 0XD6, 0X79, 0X02, 0X01, 0X11 + }; + // Authority Key Identifier Extn - 2.5.29.35 + private static final byte[] authKeyIdExtn = {0x06, 0x03, 0X55, 0X1D, 0X23}; + + // Signature algorithm identifier - always sha256WithRSAEncryption - 1.2.840.113549.1.1.11 + // SEQUENCE of alg OBJ ID and parameters = NULL. + private static final byte[] X509SignAlgIdentifier = { + 0x30, + 0x0D, + 0x06, + 0x09, + 0x2A, + (byte) 0x86, + 0x48, + (byte) 0x86, + (byte) 0xF7, + 0x0D, + 0x01, + 0x01, + 0x0B, + 0x05, + 0x00 + }; + // Validity is not fixed field + // Subject is a fixed field with only CN= Android Keystore Key - same for all the keys + private static final byte[] X509Subject = { + 0x30, 0x1F, 0x31, 0x1D, 0x30, 0x1B, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x14, 0x41, 0x6e, 0x64, + 0x72, 0x6f, 0x69, 0x64, 0x20, 0x4B, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x4B, 0x65, + 0x79 + }; + + private static final byte keyUsageSign = (byte) 0x80; // 0 bit + private static final byte keyUsageKeyEncipher = (byte) 0x20; // 2nd- bit + private static final byte keyUsageDataEncipher = (byte) 0x10; // 3rd- bit + + private static final byte KEYMASTER_VERSION = 4; + private static final byte ATTESTATION_VERSION = 3; + private static final byte[] pubExponent = {0x01, 0x00, 0x01}; + private static final byte SERIAL_NUM = (byte) 0x01; + private static final byte X509_VERSION = (byte) 0x02; + + private static short certStart; + private static short signatureOffset; + private static short tbsOffset; + private static short tbsLength; + + private static short stackPtr; + private static byte[] stack; + private static short start; + private static short length; + // private static KMRepository repo; + private static short uniqueId; + private static short attChallenge; + private static short notBefore; + private static short notAfter; + private static short pubKey; + private static short[] swParams; + private static short swParamsIndex; + private static short[] hwParams; + private static short hwParamsIndex; + private static byte keyUsage; + private static byte unusedBits; + private static KMAttestationCert inst; + private static boolean rsaCert; + private static byte deviceLocked; + private static short verifiedBootKey; + private static byte verifiedState; + private static short verifiedHash; + private static short authKey; + private static short issuer; + private static short signPriv; + private static short signMod; + + private KMAttestationCertImpl() {} + + public static KMAttestationCert instance(boolean rsaCert) { + if (inst == null) inst = new KMAttestationCertImpl(); + init(); + KMAttestationCertImpl.rsaCert = rsaCert; + return inst; + } + + private static void init() { + // if (repo == null) repo = KMRepository.instance(); + stack = null; + stackPtr = 0; + certStart = 0; + signatureOffset = 0; + start = 0; + length = 0; + tbsLength = 0; + if (swParams == null) { + swParams = JCSystem.makeTransientShortArray((short) MAX_PARAMS, JCSystem.CLEAR_ON_RESET); + } + if (hwParams == null) { + hwParams = JCSystem.makeTransientShortArray((short) MAX_PARAMS, JCSystem.CLEAR_ON_RESET); + } + + swParamsIndex = 0; + hwParamsIndex = 0; + keyUsage = 0; + unusedBits = 8; + attChallenge = 0; + notBefore = 0; + notAfter = 0; + pubKey = 0; + uniqueId = 0; + verifiedBootKey = 0; + verifiedHash = 0; + verifiedState = 0; + rsaCert = true; + deviceLocked = 0; + authKey = 0; + signPriv = 0; + signMod = 0; + } + + @Override + public KMAttestationCert verifiedBootHash(short obj) { + verifiedHash = obj; + return this; + } + + @Override + public KMAttestationCert authKey(short obj) { + authKey = obj; + return this; + } + + @Override + public KMAttestationCert verifiedBootKey(short obj) { + verifiedBootKey = obj; + return this; + } + + @Override + public KMAttestationCert verifiedBootState(byte val) { + verifiedState = val; + return this; + } + + @Override + public KMAttestationCert uniqueId(short obj) { + uniqueId = obj; + return this; + } + + @Override + public KMAttestationCert notBefore(short obj) { + notBefore = obj; + return this; + } + + @Override + public KMAttestationCert notAfter(short obj) { + notAfter = obj; + return this; + } + + @Override + public KMAttestationCert deviceLocked(boolean val) { + if (val) deviceLocked = (byte) 0xFF; + else deviceLocked = 0; + return this; + } + + @Override + public KMAttestationCert publicKey(short obj) { + pubKey = obj; + return this; + } + + @Override + public KMAttestationCert attestationChallenge(short obj) { + attChallenge = obj; + return this; + } + + @Override + public KMAttestationCert extensionTag(short tag, boolean hwEnforced) { + if (hwEnforced) { + hwParams[hwParamsIndex] = tag; + hwParamsIndex++; + } else { + swParams[swParamsIndex] = tag; + swParamsIndex++; + } + if (KMTag.getKey(tag) == KMType.PURPOSE) { + createKeyUsage(tag); + } + return this; + } + + @Override + public KMAttestationCert issuer(short obj) { + issuer = obj; + return this; + } + + private void createKeyUsage(short tag) { + short len = KMEnumArrayTag.cast(tag).length(); + byte index = 0; + while (index < len) { + if (KMEnumArrayTag.cast(tag).get(index) == KMType.SIGN) { + keyUsage = (byte) (keyUsage | keyUsageSign); + } else if (KMEnumArrayTag.cast(tag).get(index) == KMType.WRAP_KEY) { + keyUsage = (byte) (keyUsage | keyUsageKeyEncipher); + } else if (KMEnumArrayTag.cast(tag).get(index) == KMType.DECRYPT) { + keyUsage = (byte) (keyUsage | keyUsageDataEncipher); + } + index++; + } + index = keyUsage; + while (index != 0) { + index = (byte) (index << 1); + unusedBits--; + } + } + + private static void encodeCert( + short buf, + short keyChar, + short uniqueId, + short notBefore, + short notAfter, + short pubKey, + short attChallenge, + short attAppId, + boolean rsaCert) { + init(); + stack = KMByteBlob.cast(buf).getBuffer(); + start = KMByteBlob.cast(buf).getStartOff(); + length = KMByteBlob.cast(buf).length(); + stackPtr = (short) (start + length); + /* KMAttestationCertImpl.attChallenge = attChallenge; + KMAttestationCertImpl.attAppId = attAppId; + KMAttestationCertImpl.hwParams = KMKeyCharacteristics.cast(keyChar).getHardwareEnforced(); + KMAttestationCertImpl.swParams = KMKeyCharacteristics.cast(keyChar).getSoftwareEnforced(); + KMAttestationCertImpl.notBefore = notBefore; + KMAttestationCertImpl.notAfter = notAfter; + KMAttestationCertImpl.pubKey = pubKey; + KMAttestationCertImpl.uniqueId = uniqueId; + + */ + short last = stackPtr; + decrementStackPtr((short) 256); + signatureOffset = stackPtr; + pushBitStringHeader((byte) 0, (short) (last - stackPtr)); + // signatureOffset = pushSignature(null, (short) 0, (short) 256); + pushAlgorithmId(X509SignAlgIdentifier); + tbsLength = stackPtr; + pushTbsCert(rsaCert); + tbsOffset = stackPtr; + tbsLength = (short) (tbsLength - tbsOffset); + pushSequenceHeader((short) (last - stackPtr)); + // print(stack, stackPtr, (short)(last - stackPtr)); + certStart = stackPtr; + } + + private static void pushTbsCert(boolean rsaCert) { + short last = stackPtr; + pushExtensions(); + // subject public key info + if (rsaCert) { + pushRsaSubjectKeyInfo(); + } else { + pushEccSubjectKeyInfo(); + } + // subject + pushBytes(X509Subject, (short) 0, (short) X509Subject.length); + pushValidity(); + // issuer - der encoded + // pushBytes(repo.getCertDataBuffer(), repo.getIssuer(), repo.getIssuerLen()); + pushBytes( + KMByteBlob.cast(issuer).getBuffer(), + KMByteBlob.cast(issuer).getStartOff(), + KMByteBlob.cast(issuer).length()); + // Algorithm Id + pushAlgorithmId(X509SignAlgIdentifier); + // Serial Number + pushByte(SERIAL_NUM); + pushIntegerHeader((short) 1); + // Version + pushByte(X509_VERSION); + pushIntegerHeader((short) 1); + pushByte((byte) 0x03); + pushByte((byte) 0xA0); + // Finally sequence header. + pushSequenceHeader((short) (last - stackPtr)); + } + + private static void pushExtensions() { + short last = stackPtr; + // byte keyusage = 0; + // byte unusedBits = 8; + pushAuthKeyId(); + /* + if (KMEnumArrayTag.contains(KMType.PURPOSE, KMType.SIGN, hwParams)) { + keyusage = (byte) (keyusage | keyUsageSign); + unusedBits = 7; + } + if (KMEnumArrayTag.contains(KMType.PURPOSE, KMType.WRAP_KEY, hwParams)) { + keyusage = (byte) (keyusage | keyUsageKeyEncipher); + unusedBits = 5; + } + if (KMEnumArrayTag.contains(KMType.PURPOSE, KMType.DECRYPT, hwParams)) { + keyusage = (byte) (keyusage | keyUsageDataEncipher); + unusedBits = 4; + } + + */ + if (keyUsage != 0) pushKeyUsage(keyUsage, unusedBits); + pushKeyDescription(); + pushSequenceHeader((short) (last - stackPtr)); + // Extensions have explicit tag of [3] + pushLength((short) (last - stackPtr)); + pushByte((byte) 0xA3); + } + + // Time SEQUENCE{UTCTime, UTC or Generalized Time) + private static void pushValidity() { + short last = stackPtr; + if (notAfter != 0) { + pushBytes( + KMByteBlob.cast(notAfter).getBuffer(), + KMByteBlob.cast(notAfter).getStartOff(), + KMByteBlob.cast(notAfter).length()); + } else { + // TODO move this to keymaster applet + // pushBytes(repo.getCertDataBuffer(), repo.getCertExpiryTime(), repo.getCertExpiryTimeLen()); + } + pushTimeHeader(KMByteBlob.cast(notAfter).length()); + pushBytes( + KMByteBlob.cast(notBefore).getBuffer(), + KMByteBlob.cast(notBefore).getStartOff(), + KMByteBlob.cast(notBefore).length()); + pushTimeHeader(KMByteBlob.cast(notBefore).length()); + pushSequenceHeader((short) (last - stackPtr)); + } + + private static void pushTimeHeader(short len) { + if (len == 13) { // UTC Time + pushLength((short) 0x0D); + pushByte((byte) 0x17); + } else if (len == 15) { // Generalized Time + pushLength((short) 0x0F); + pushByte((byte) 0x18); + } else { + KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + } + } + + // SEQUENCE{SEQUENCE{algId, NULL}, bitString{SEQUENCE{ modulus as positive integer, public + // exponent + // as positive integer} + private static void pushRsaSubjectKeyInfo() { + short last = stackPtr; + pushBytes(pubExponent, (short) 0, (short) pubExponent.length); + pushIntegerHeader((short) pubExponent.length); + pushBytes( + KMByteBlob.cast(pubKey).getBuffer(), + KMByteBlob.cast(pubKey).getStartOff(), + KMByteBlob.cast(pubKey).length()); + + // encode modulus as positive if the MSB is 1. + if (KMByteBlob.cast(pubKey).get((short) 0) < 0) { + pushByte((byte) 0x00); + pushIntegerHeader((short) (KMByteBlob.cast(pubKey).length() + 1)); + } else { + pushIntegerHeader(KMByteBlob.cast(pubKey).length()); + } + pushSequenceHeader((short) (last - stackPtr)); + pushBitStringHeader((byte) 0x00, (short) (last - stackPtr)); + pushRsaEncryption(); + pushSequenceHeader((short) (last - stackPtr)); + } + // SEQUENCE{SEQUENCE{ecPubKey, prime256v1}, bitString{pubKey}} + private static void pushEccSubjectKeyInfo() { + short last = stackPtr; + pushBytes( + KMByteBlob.cast(pubKey).getBuffer(), + KMByteBlob.cast(pubKey).getStartOff(), + KMByteBlob.cast(pubKey).length()); + pushBitStringHeader((byte) 0x00, KMByteBlob.cast(pubKey).length()); + pushEcDsa(); + pushSequenceHeader((short) (last - stackPtr)); + } + + private static void pushEcDsa() { + short last = stackPtr; + pushBytes(prime256v1, (short) 0, (short) prime256v1.length); + pushBytes(eccPubKey, (short) 0, (short) eccPubKey.length); + pushSequenceHeader((short) (last - stackPtr)); + } + + private static void pushRsaEncryption() { + short last = stackPtr; + pushNullHeader(); + pushBytes(rsaEncryption, (short) 0, (short) rsaEncryption.length); + pushSequenceHeader((short) (last - stackPtr)); + } + // KeyDescription ::= SEQUENCE { + // attestationVersion INTEGER, # Value 3 + // attestationSecurityLevel SecurityLevel, # See below + // keymasterVersion INTEGER, # Value 4 + // keymasterSecurityLevel SecurityLevel, # See below + // attestationChallenge OCTET_STRING, # Tag::ATTESTATION_CHALLENGE from attestParams + // uniqueId OCTET_STRING, # Empty unless key has Tag::INCLUDE_UNIQUE_ID + // softwareEnforced AuthorizationList, # See below + // hardwareEnforced AuthorizationList, # See below + // } + private static void pushKeyDescription() { + short last = stackPtr; + pushHWParams(); + pushSWParams(); + if (uniqueId != 0) { + pushOctetString( + KMByteBlob.cast(uniqueId).getBuffer(), + KMByteBlob.cast(uniqueId).getStartOff(), + KMByteBlob.cast(uniqueId).length()); + } else { + pushOctetStringHeader((short) 0); + } + pushOctetString( + KMByteBlob.cast(attChallenge).getBuffer(), + KMByteBlob.cast(attChallenge).getStartOff(), + KMByteBlob.cast(attChallenge).length()); + pushEnumerated(KMType.STRONGBOX); + pushByte(KEYMASTER_VERSION); + pushIntegerHeader((short) 1); + pushEnumerated(KMType.STRONGBOX); + pushByte(ATTESTATION_VERSION); + pushIntegerHeader((short) 1); + pushSequenceHeader((short) (last - stackPtr)); + pushOctetStringHeader((short) (last - stackPtr)); + pushBytes(androidExtn, (short) 0, (short) androidExtn.length); + pushSequenceHeader((short) (last - stackPtr)); + } + + private static void pushSWParams() { + short last = stackPtr; + // ATTESTATION_APPLICATION_ID 709 is softwareEnforced. + short[] tagIds = { + 709, 706, 705, 704, 703, 702, 701, 601, 600, 509, 508, 507, 506, 505, 504, 503, 402, 401, 400, + 303, 200, 10, 6, 5, 3, 2, 1 + }; + byte index = 0; + do { + /* + if(tagIds[index] == KMType.ATTESTATION_APPLICATION_ID) { + pushAttIds(tagIds[index]); + continue; + } + */ + pushParams(swParams, swParamsIndex, tagIds[index]); + } while (++index < tagIds.length); + pushSequenceHeader((short) (last - stackPtr)); + } + + private static void pushHWParams() { + short last = stackPtr; + // Attestation ids are not included. As per VTS attestation ids are not supported currenlty. + short[] tagIds = { + 706, 705, 704, 703, 702, 701, 601, 600, 509, 508, 507, 506, 505, 504, 503, 402, 401, 400, 303, + 200, 10, 6, 5, 3, 2, 1 + }; + byte index = 0; + do { + // if(pushAttIds(tagIds[index])) continue; + if (tagIds[index] == KMType.ROOT_OF_TRUST) { + pushRoT(); + continue; + } + if (pushParams(hwParams, hwParamsIndex, tagIds[index])) continue; + } while (++index < tagIds.length); + pushSequenceHeader((short) (last - stackPtr)); + } + + private static boolean pushParams(short[] params, short len, short tagId) { + short index = 0; + while (index < len) { + if (tagId == KMTag.getKey(params[index])) { + pushTag(params[index]); + return true; + } + index++; + } + return false; + } + + private static void pushTag(short tag) { + short type = KMTag.getTagType(tag); + short tagId = KMTag.getKey(tag); + short val; + switch (type) { + case KMType.BYTES_TAG: + val = KMByteTag.cast(tag).getValue(); + pushBytesTag( + tagId, + KMByteBlob.cast(val).getBuffer(), + KMByteBlob.cast(val).getStartOff(), + KMByteBlob.cast(val).length()); + break; + case KMType.ENUM_TAG: + val = KMEnumTag.cast(tag).getValue(); + pushEnumTag(tagId, (byte) val); + break; + case KMType.ENUM_ARRAY_TAG: + val = KMEnumArrayTag.cast(tag).getValues(); + pushEnumArrayTag( + tagId, + KMByteBlob.cast(val).getBuffer(), + KMByteBlob.cast(val).getStartOff(), + KMByteBlob.cast(val).length()); + break; + case KMType.UINT_TAG: + case KMType.ULONG_TAG: + case KMType.DATE_TAG: + val = KMIntegerTag.cast(tag).getValue(); + pushIntegerTag( + tagId, + KMInteger.cast(val).getBuffer(), + KMInteger.cast(val).getStartOff(), + KMInteger.cast(val).length()); + break; + case KMType.UINT_ARRAY_TAG: + case KMType.ULONG_ARRAY_TAG: + // TODO According to keymaster hal only one user secure id is used but this conflicts with + // tag type which is ULONG-REP. Currently this is encoded as SET OF INTEGERS + val = KMIntegerArrayTag.cast(tag).getValues(); + pushIntegerArrayTag(tagId, val); + break; + case KMType.BOOL_TAG: + val = KMBoolTag.cast(tag).getVal(); + pushBoolTag(tagId); + break; + default: + KMException.throwIt(KMError.INVALID_TAG); + break; + } + } + // RootOfTrust ::= SEQUENCE { + // verifiedBootKey OCTET_STRING, + // deviceLocked BOOLEAN, + // verifiedBootState VerifiedBootState, + // verifiedBootHash OCTET_STRING, + // } + // VerifiedBootState ::= ENUMERATED { + // Verified (0), + // SelfSigned (1), + // Unverified (2), + // Failed (3), + // } + private static void pushRoT() { + short last = stackPtr; + byte val = 0x00; + // verified boot hash + // pushOctetString(repo.verifiedBootHash, (short) 0, (short) repo.verifiedBootHash.length); + pushOctetString( + KMByteBlob.cast(verifiedHash).getBuffer(), + KMByteBlob.cast(verifiedHash).getStartOff(), + KMByteBlob.cast(verifiedHash).length()); + /* + // verified boot state + // TODO change this once verifiedBootState is supported in repo + if (repo.selfSignedBootFlag) val = KMType.SELF_SIGNED_BOOT; + else if (repo.verifiedBootFlag) val = KMType.VERIFIED_BOOT; + else val = KMType.UNVERIFIED_BOOT; + + pushEnumerated(val); + + */ + pushEnumerated(verifiedState); + // device locked + /*val = 0x00; + if (repo.deviceLockedFlag) val = (byte) 0xFF; + pushBoolean(val); + */ + pushBoolean(deviceLocked); + // verified boot Key + pushOctetString( + KMByteBlob.cast(verifiedBootKey).getBuffer(), + KMByteBlob.cast(verifiedBootKey).getStartOff(), + KMByteBlob.cast(verifiedBootKey).length()); + // pushOctetString(repo.verifiedBootKey, (short) 0, (short) repo.verifiedBootKey.length); + // Finally sequence header + pushSequenceHeader((short) (last - stackPtr)); + // ... and tag Id + pushTagIdHeader(KMType.ROOT_OF_TRUST, (short) (last - stackPtr)); + } + + private static void pushOctetString(byte[] buf, short start, short len) { + pushBytes(buf, start, len); + pushOctetStringHeader(len); + } + + private static void pushBoolean(byte val) { + pushByte(val); + pushBooleanHeader((short) 1); + } + + private static void pushBooleanHeader(short len) { + pushLength(len); + pushByte((byte) 0x01); + } + /* + // All Attestation Id tags are byte tags/octet strings + private static boolean pushAttIds(short tagId) { + if(!repo.isAttIdSupported()) return true; + byte index = 0; + while (index < repo.ATT_ID_TABLE_SIZE) { + if (repo.getAttIdLen(index) != 0) { + if(tagId == repo.getAttIdTag(index)) { + pushBytesTag( + repo.getAttIdTag(index), + repo.getAttIdBuffer(index), + repo.getAttIdOffset(index), + repo.getAttIdLen(index)); + return true; + } + } + index++; + } + return false; + } + */ + // Only SET of INTEGERS supported are padding, digest, purpose and blockmode + // All of these are enum array tags i.e. byte long values + private static void pushEnumArrayTag(short tagId, byte[] buf, short start, short len) { + short last = stackPtr; + short index = 0; + while (index < len) { + pushByte(buf[(short) (start + index)]); + pushIntegerHeader((short) 1); + index++; + } + pushSetHeader((short) (last - stackPtr)); + pushTagIdHeader(tagId, (short) (last - stackPtr)); + } + // Only SET of INTEGERS supported are padding, digest, purpose and blockmode + // All of these are enum array tags i.e. byte long values + private static void pushIntegerArrayTag(short tagId, short arr) { + short last = stackPtr; + short index = 0; + short len = KMArray.cast(arr).length(); + short ptr; + while (index < len) { + ptr = KMArray.cast(arr).get(index); + pushInteger( + KMInteger.cast(ptr).getBuffer(), + KMInteger.cast(ptr).getStartOff(), + KMInteger.cast(ptr).length()); + index++; + } + pushSetHeader((short) (last - stackPtr)); + pushTagIdHeader(tagId, (short) (last - stackPtr)); + } + + private static void pushSetHeader(short len) { + pushLength(len); + pushByte((byte) 0x31); + } + + private static void pushEnumerated(byte val) { + short last = stackPtr; + pushByte(val); + pushEnumeratedHeader((short) (last - stackPtr)); + } + + private static void pushEnumeratedHeader(short len) { + pushLength(len); + pushByte((byte) 0x0A); + } + + private static void pushBoolTag(short tagId) { + short last = stackPtr; + pushNullHeader(); + pushTagIdHeader(tagId, (short) (last - stackPtr)); + } + + private static void pushNullHeader() { + pushByte((byte) 0); + pushByte((byte) 0x05); + } + + private static void pushEnumTag(short tagId, byte val) { + short last = stackPtr; + pushByte(val); + pushIntegerHeader((short) (last - stackPtr)); + pushTagIdHeader(tagId, (short) (last - stackPtr)); + } + + private static void pushIntegerTag(short tagId, byte[] buf, short start, short len) { + short last = stackPtr; + pushInteger(buf, start, len); + // pushIntegerHeader((short) (last - stackPtr)); + pushTagIdHeader(tagId, (short) (last - stackPtr)); + } + // Ignore leading zeros. Only Unsigned Integers are required hence if MSB is set then add 0x00 + // as most significant byte. + private static void pushInteger(byte[] buf, short start, short len) { + short last = stackPtr; + byte index = 0; + while (index < (byte) len) { + if (buf[(short) (start + index)] != 0) break; + index++; + } + if (index == (byte) len) { + pushByte((byte) 0x00); + } else { + pushBytes(buf, (short) (start + index), (short) (len - index)); + if (buf[(short) (start + index)] < 0) { // MSB is 1 + pushByte((byte) 0x00); // always unsigned int + } + } + pushIntegerHeader((short) (last - stackPtr)); + } + // Bytes Tag is a octet string and tag id is added explicitly + private static void pushBytesTag(short tagId, byte[] buf, short start, short len) { + short last = stackPtr; + pushBytes(buf, start, len); + pushOctetStringHeader((short) (last - stackPtr)); + pushTagIdHeader(tagId, (short) (last - stackPtr)); + } + + // tag id <= 30 ---> 0xA0 | {tagId} + // 30 < tagId < 128 ---> 0xBF 0x{tagId} + // tagId >= 128 ---> 0xBF 0x80+(tagId/128) 0x{tagId - (128*(tagId/128))} + private static void pushTagIdHeader(short tagId, short len) { + pushLength(len); + short count = (short) (tagId / 128); + if (count > 0) { + pushByte((byte) (tagId - (128 * count))); + pushByte((byte) (0x80 + count)); + pushByte((byte) 0xBF); + } else if (tagId > 30) { + pushByte((byte) tagId); + pushByte((byte) 0xBF); + } else { + pushByte((byte) (0xA0 | (byte) tagId)); + } + } + // SEQUENCE {ObjId, OCTET STRING{BIT STRING{keyUsage}}} + private static void pushKeyUsage(byte keyUsage, byte unusedBits) { + short last = stackPtr; + pushByte(keyUsage); + pushBitStringHeader(unusedBits, (short) (last - stackPtr)); + pushOctetStringHeader((short) (last - stackPtr)); + pushBytes(keyUsageExtn, (short) 0, (short) keyUsageExtn.length); + pushSequenceHeader((short) (last - stackPtr)); + } + + // SEQUENCE {ObjId, OCTET STRING{SEQUENCE{[0]keyIdentifier}}} + private static void pushAuthKeyId() { + short last = stackPtr; + // if (repo.getAuthKeyId() == 0) return; + if (authKey == 0) return; + /* + pushKeyIdentifier( + repo.getCertDataBuffer(), + repo.getAuthKeyId(), + repo.getAuthKeyIdLen()); // key identifier is [0]'th tagged in a sequence + + */ + pushKeyIdentifier( + KMByteBlob.cast(authKey).getBuffer(), + KMByteBlob.cast(authKey).getStartOff(), + KMByteBlob.cast(authKey).length()); + pushSequenceHeader((short) (last - stackPtr)); + pushOctetStringHeader((short) (last - stackPtr)); + pushBytes(authKeyIdExtn, (short) 0, (short) authKeyIdExtn.length); // ObjId + pushSequenceHeader((short) (last - stackPtr)); + } + + private static void pushKeyIdentifier(byte[] buf, short start, short len) { + pushBytes(buf, start, len); // keyIdentifier + pushLength(len); // len + pushByte((byte) 0x80); // Context specific tag [0] + } + + private static void pushAlgorithmId(byte[] algId) { + pushBytes(algId, (short) 0, (short) algId.length); + } + + private static short pushSignature(byte[] buf, short start, short len) { + pushBytes(buf, start, len); + short signatureOff = stackPtr; + pushBitStringHeader((byte) 0, len); + return signatureOff; + } + + private static void pushIntegerHeader(short len) { + pushLength(len); + pushByte((byte) 0x02); + } + + private static void pushOctetStringHeader(short len) { + pushLength(len); + pushByte((byte) 0x04); + } + + private static void pushSequenceHeader(short len) { + pushLength(len); + pushByte((byte) 0x30); + } + + private static void pushBitStringHeader(byte unusedBits, short len) { + pushByte(unusedBits); + pushLength((short) (len + 1)); // 1 extra byte for unused bits byte + pushByte((byte) 0x03); + } + + private static void pushLength(short len) { + if (len < 128) { + pushByte((byte) len); + } else if (len < 256) { + pushByte((byte) len); + pushByte((byte) 0x81); + } else { + pushShort(len); + pushByte((byte) 0x82); + } + } + + private static void pushShort(short val) { + decrementStackPtr((short) 2); + Util.setShort(stack, stackPtr, val); + } + + private static void pushByte(byte val) { + decrementStackPtr((short) 1); + stack[stackPtr] = val; + } + + private static void pushBytes(byte[] buf, short start, short len) { + decrementStackPtr(len); + if (buf != null) { + Util.arrayCopyNonAtomic(buf, start, stack, stackPtr, len); + } + } + + private static void decrementStackPtr(short cnt) { + stackPtr = (short) (stackPtr - cnt); + if (start > stackPtr) KMException.throwIt(KMError.UNKNOWN_ERROR); + } + + public static short sign( + KMSEProvider seProv, + byte[] privBuf, + short privStart, + short privLength, + byte[] modBuf, + short modStart, + short modLength) { + // short ret = signer.sign(stack,tbsOffset,tbsLength,stack,signatureOffset); + // print(getBuffer(),getCertStart(),getCertLength()); + return seProv.rsaSignPKCS1256( + privBuf, + privStart, + privLength, + modBuf, + modStart, + modLength, + stack, + tbsOffset, + tbsLength, + stack, + signatureOffset); + } + + @Override + public KMAttestationCert buffer(byte[] buf, short bufStart, short maxLen) { + stack = buf; + start = bufStart; + length = maxLen; + stackPtr = (short) (start + length); + return this; + } + + @Override + public KMAttestationCert signingKey(short privKey, short modulus) { + signPriv = privKey; + signMod = modulus; + return this; + } + + @Override + public short getCertStart() { + return certStart; + } + + @Override + public short getCertEnd() { + return (short) (start + length - 1); + } + + @Override + public short getCertLength() { + return (short) (getCertEnd() - getCertStart() + 1); + } + + @Override + public void build() { + short last = stackPtr; + decrementStackPtr((short) 256); + signatureOffset = stackPtr; + pushBitStringHeader((byte) 0, (short) (last - stackPtr)); + // signatureOffset = pushSignature(null, (short) 0, (short) 256); + pushAlgorithmId(X509SignAlgIdentifier); + tbsLength = stackPtr; + pushTbsCert(rsaCert); + tbsOffset = stackPtr; + tbsLength = (short) (tbsLength - tbsOffset); + pushSequenceHeader((short) (last - stackPtr)); + certStart = stackPtr; + KMSEProviderImpl.instance() + .rsaSignPKCS1256( + KMByteBlob.cast(signPriv).getBuffer(), + KMByteBlob.cast(signPriv).getStartOff(), + KMByteBlob.cast(signPriv).length(), + KMByteBlob.cast(signMod).getBuffer(), + KMByteBlob.cast(signMod).getStartOff(), + KMByteBlob.cast(signMod).length(), + stack, + tbsOffset, + tbsLength, + stack, + signatureOffset); + // print(stack, stackPtr, (short)(last - stackPtr)); + } + + /* private static void print(byte[] buf, short start, short length){ + StringBuilder sb = new StringBuilder(); + for(int i = start; i < (start+length); i++){ + sb.append(String.format("%02X", buf[i])) ; + //if((i-start)%16 == 0 && (i-start) != 0) sb.append(String.format("\n")); + } + System.out.println(sb.toString()); + } + + */ +} diff --git a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMInstance.java b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMInstance.java new file mode 100644 index 00000000..3bf35e97 --- /dev/null +++ b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMInstance.java @@ -0,0 +1,7 @@ +package com.android.javacard.keymaster; + +public class KMInstance { + public byte reserved; + public Object object; + public byte instanceCount; +} diff --git a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMJCOPSimProvider.java b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMJCOPSimProvider.java new file mode 100644 index 00000000..fc343c54 --- /dev/null +++ b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMJCOPSimProvider.java @@ -0,0 +1,1371 @@ +/* + * Copyright(C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" (short)0IS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.javacard.keymaster; + +import com.android.javacard.keymaster.KMAttestationCert; +import com.android.javacard.keymaster.KMError; +import com.android.javacard.keymaster.KMException; +import com.android.javacard.keymaster.KMInstance; +import com.android.javacard.keymaster.KMKeymasterApplet; +import com.android.javacard.keymaster.KMOperation; +import com.android.javacard.keymaster.KMRepository; +import com.android.javacard.keymaster.KMSEProvider; +import com.android.javacard.keymaster.KMType; + +import javacard.framework.ISO7816; +import javacard.framework.ISOException; +import javacard.framework.JCSystem; +import javacard.framework.Util; +import javacard.security.AESKey; +import javacard.security.CryptoException; +import javacard.security.DESKey; +import javacard.security.ECPrivateKey; +import javacard.security.ECPublicKey; +import javacard.security.HMACKey; +import javacard.security.Key; +import javacard.security.KeyBuilder; +import javacard.security.KeyPair; +import javacard.security.MessageDigest; +import javacard.security.RSAPrivateKey; +import javacard.security.RSAPublicKey; +import javacard.security.RandomData; +import javacard.security.Signature; +import javacardx.crypto.AEADCipher; +import javacardx.crypto.Cipher; + +public class KMJCOPSimProvider implements KMSEProvider { + // static final variables + // -------------------------------------------------------------- + // P-256 Curve Parameters + static final byte[] secp256r1_P = { + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF }; + + static final byte[] secp256r1_A = { + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFC }; + + static final byte[] secp256r1_B = { + (byte) 0x5A, (byte) 0xC6, (byte) 0x35, (byte) 0xD8, (byte) 0xAA, + (byte) 0x3A, (byte) 0x93, (byte) 0xE7, (byte) 0xB3, (byte) 0xEB, + (byte) 0xBD, (byte) 0x55, (byte) 0x76, (byte) 0x98, (byte) 0x86, + (byte) 0xBC, (byte) 0x65, (byte) 0x1D, (byte) 0x06, (byte) 0xB0, + (byte) 0xCC, (byte) 0x53, (byte) 0xB0, (byte) 0xF6, (byte) 0x3B, + (byte) 0xCE, (byte) 0x3C, (byte) 0x3E, (byte) 0x27, (byte) 0xD2, + (byte) 0x60, (byte) 0x4B }; + + static final byte[] secp256r1_S = { + (byte) 0xC4, (byte) 0x9D, (byte) 0x36, (byte) 0x08, (byte) 0x86, + (byte) 0xE7, (byte) 0x04, (byte) 0x93, (byte) 0x6A, (byte) 0x66, + (byte) 0x78, (byte) 0xE1, (byte) 0x13, (byte) 0x9D, (byte) 0x26, + (byte) 0xB7, (byte) 0x81, (byte) 0x9F, (byte) 0x7E, (byte) 0x90 }; + + // Uncompressed form + static final byte[] secp256r1_UCG = { + (byte) 0x04, (byte) 0x6B, (byte) 0x17, (byte) 0xD1, (byte) 0xF2, + (byte) 0xE1, (byte) 0x2C, (byte) 0x42, (byte) 0x47, (byte) 0xF8, + (byte) 0xBC, (byte) 0xE6, (byte) 0xE5, (byte) 0x63, (byte) 0xA4, + (byte) 0x40, (byte) 0xF2, (byte) 0x77, (byte) 0x03, (byte) 0x7D, + (byte) 0x81, (byte) 0x2D, (byte) 0xEB, (byte) 0x33, (byte) 0xA0, + (byte) 0xF4, (byte) 0xA1, (byte) 0x39, (byte) 0x45, (byte) 0xD8, + (byte) 0x98, (byte) 0xC2, (byte) 0x96, (byte) 0x4F, (byte) 0xE3, + (byte) 0x42, (byte) 0xE2, (byte) 0xFE, (byte) 0x1A, (byte) 0x7F, + (byte) 0x9B, (byte) 0x8E, (byte) 0xE7, (byte) 0xEB, (byte) 0x4A, + (byte) 0x7C, (byte) 0x0F, (byte) 0x9E, (byte) 0x16, (byte) 0x2B, + (byte) 0xCE, (byte) 0x33, (byte) 0x57, (byte) 0x6B, (byte) 0x31, + (byte) 0x5E, (byte) 0xCE, (byte) 0xCB, (byte) 0xB6, (byte) 0x40, + (byte) 0x68, (byte) 0x37, (byte) 0xBF, (byte) 0x51, (byte) 0xF5 }; + + static final byte[] secp256r1_N = { + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xBC, (byte) 0xE6, (byte) 0xFA, (byte) 0xAD, + (byte) 0xA7, (byte) 0x17, (byte) 0x9E, (byte) 0x84, (byte) 0xF3, + (byte) 0xB9, (byte) 0xCA, (byte) 0xC2, (byte) 0xFC, (byte) 0x63, + (byte) 0x25, (byte) 0x51 }; + static final short secp256r1_H = 1; + // -------------------------------------------------------------- + public static final short AES_GCM_TAG_LENGTH = 12; + public static final short AES_GCM_NONCE_LENGTH = 12; + public static final byte KEYSIZE_128_OFFSET = 0x00; + public static final byte KEYSIZE_256_OFFSET = 0x01; + public static final short TMP_ARRAY_SIZE = 256; // TODO + public static final short AUTH_DATA_LEN = 650; // TODO + public static final short MAX_RND_NUM_SIZE = 64; + public static final short ENTROPY_POOL_SIZE = 16; + public static final byte[] aesICV = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + final byte[] CIPHER_ALGS = { + Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, + Cipher.ALG_AES_BLOCK_128_ECB_NOPAD, Cipher.ALG_DES_CBC_NOPAD, + Cipher.ALG_DES_ECB_NOPAD, Cipher.ALG_AES_CTR, Cipher.ALG_RSA_PKCS1,// NoDigest + Cipher.ALG_RSA_PKCS1_OAEP, // SHA256 + Cipher.ALG_RSA_NOPAD, // NoDigest + // AEADCipher.ALG_AES_CCM, + AEADCipher.ALG_AES_GCM }; + final byte[] SIG_ALGS = { + // Signature.ALG_AES_CMAC_128, + Signature.ALG_RSA_SHA_256_PKCS1, Signature.ALG_RSA_SHA_256_PKCS1_PSS, + Signature.ALG_ECDSA_SHA_256, Signature.ALG_HMAC_SHA_256, + KMRsa2048NoDigestSignature.ALG_RSA_SIGN_NOPAD, + KMRsa2048NoDigestSignature.ALG_RSA_PKCS1_NODIGEST }; + + // AESKey + private AESKey aesKeys[]; + // DES3Key + private DESKey triDesKey; + // HMACKey + private HMACKey hmacKeys[]; + // RSA Key Pair + private KeyPair rsaKeyPair; + // EC Key Pair. + private KeyPair ecKeyPair; + // Temporary array. + public byte[] tmpArray; + // public byte[] tmpAuthDataArray; + private short tmpArrayIndex; + // This is used for internal encryption/decryption operations. + private static AEADCipher aesGcmCipher; + // Cipher pool + private Object[] cipherPool; + // Signature pool + private Object[] sigPool; + // KMOperationImpl pool + private Object[] operationPool; + + private static Signature kdf; + + private static Signature hmacSignature; + + // RNG + private static byte[] rngCounter; + private static AESKey aesRngKey; + private static Cipher aesRngCipher; + private static byte[] entropyPool; + private static byte[] rndNum; + + private static KMJCOPSimProvider jcopProvider = null; + + public static KMJCOPSimProvider getInstance() { + if (jcopProvider == null) + jcopProvider = new KMJCOPSimProvider(); + return jcopProvider; + } + + private KMJCOPSimProvider() { + // Re-usable AES,DES and HMAC keys in persisted memory. + aesKeys = new AESKey[2]; + aesKeys[KEYSIZE_128_OFFSET] = (AESKey) KeyBuilder.buildKey( + KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false); + aesKeys[KEYSIZE_256_OFFSET] = (AESKey) KeyBuilder.buildKey( + KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_256, false); + triDesKey = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES, + KeyBuilder.LENGTH_DES3_3KEY, false); + hmacKeys = new HMACKey[2]; + hmacKeys[KEYSIZE_128_OFFSET] = (HMACKey) KeyBuilder.buildKey( + KeyBuilder.TYPE_HMAC, (short) 128, false); + hmacKeys[KEYSIZE_256_OFFSET] = (HMACKey) KeyBuilder.buildKey( + KeyBuilder.TYPE_HMAC, (short) 256, false); + rsaKeyPair = new KeyPair(KeyPair.ALG_RSA, KeyBuilder.LENGTH_RSA_2048); + initECKey(); + + // Re-usable cipher and signature instances + cipherPool = new Object[(short) (CIPHER_ALGS.length * 4)]; + sigPool = new Object[(short) (SIG_ALGS.length * 4)]; + operationPool = new Object[4]; + // Creates an instance of each cipher algorithm once. + initializeCipherPool(); + // Creates an instance of each signature algorithm once. + initializeSigPool(); + initializeOperationPool(); + + kdf = Signature.getInstance(Signature.ALG_AES_CMAC_128, false); + hmacSignature = Signature.getInstance(Signature.ALG_HMAC_SHA_256, false); + + // Temporary transient array created to use locally inside functions. + tmpArray = JCSystem.makeTransientByteArray(TMP_ARRAY_SIZE, + JCSystem.CLEAR_ON_DESELECT); + // tmpAuthDataArray = JCSystem.makeTransientByteArray(AUTH_DATA_LEN, + // JCSystem.CLEAR_ON_DESELECT); + + // Random number generator initialisation. + rndNum = JCSystem.makeTransientByteArray(MAX_RND_NUM_SIZE, + JCSystem.CLEAR_ON_RESET); + entropyPool = JCSystem.makeTransientByteArray(ENTROPY_POOL_SIZE, + JCSystem.CLEAR_ON_RESET); + rngCounter = JCSystem.makeTransientByteArray((short) 8, + JCSystem.CLEAR_ON_RESET); + initEntropyPool(entropyPool); + try { + aesRngCipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, + false); + } catch (CryptoException exp) { + ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + } + aesRngKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, + KeyBuilder.LENGTH_AES_128, false); + } + + public short alloc(short length) { + if (((short) (tmpArrayIndex + length)) > tmpArray.length) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } + tmpArrayIndex += length; + return (short) (tmpArrayIndex - length); + } + + public void clean() { + Util.arrayFillNonAtomic(tmpArray, (short) 0, tmpArrayIndex, (byte) 0); + tmpArrayIndex = 0; + } + + private void initECKey() { + ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256); + ECPrivateKey privKey = (ECPrivateKey) ecKeyPair.getPrivate(); + ECPublicKey pubkey = (ECPublicKey) ecKeyPair.getPublic(); + pubkey.setFieldFP(secp256r1_P, (short) 0, (short) secp256r1_P.length); + pubkey.setA(secp256r1_A, (short) 0, (short) secp256r1_A.length); + pubkey.setB(secp256r1_B, (short) 0, (short) secp256r1_B.length); + pubkey.setG(secp256r1_UCG, (short) 0, (short) secp256r1_UCG.length); + pubkey.setK(secp256r1_H); + pubkey.setR(secp256r1_N, (short) 0, (short) secp256r1_N.length); + + privKey.setFieldFP(secp256r1_P, (short) 0, (short) secp256r1_P.length); + privKey.setA(secp256r1_A, (short) 0, (short) secp256r1_A.length); + privKey.setB(secp256r1_B, (short) 0, (short) secp256r1_B.length); + privKey.setG(secp256r1_UCG, (short) 0, (short) secp256r1_UCG.length); + privKey.setK(secp256r1_H); + privKey.setR(secp256r1_N, (short) 0, (short) secp256r1_N.length); + } + + private boolean isCipherAlgorithm(byte alg) { + short index = 0; + while (index < CIPHER_ALGS.length) { + if (CIPHER_ALGS[index++] == alg) { + return true; + } + } + return false; + } + + private boolean isSignerAlgorithm(byte alg) { + short index = 0; + while (index < SIG_ALGS.length) { + if (SIG_ALGS[index++] == alg) { + return true; + } + } + return false; + } + + private void initializeOperationPool() { + short index = 0; + while (index < 4) { + operationPool[index] = new KMInstance(); + ((KMInstance) operationPool[index]).instanceCount = 1; + ((KMInstance) operationPool[index]).object = new KMOperationImpl(); + ((KMInstance) operationPool[index]).reserved = 0; + index++; + } + } + + // Create a signature instance of each algorithm once. + private void initializeSigPool() { + short index = 0; + while (index < SIG_ALGS.length) { + sigPool[index] = new KMInstance(); + ((KMInstance) sigPool[index]).instanceCount = 1; + ((KMInstance) sigPool[index]).object = getSignatureInstance(SIG_ALGS[index]);// Signature.getInstance(SIG_ALGS[index], + // false); + ((KMInstance) sigPool[index]).reserved = 0; + index++; + } + } + + private Signature getSignatureInstance(byte alg) { + if (KMRsa2048NoDigestSignature.ALG_RSA_SIGN_NOPAD == alg + || KMRsa2048NoDigestSignature.ALG_RSA_PKCS1_NODIGEST == alg) { + return new KMRsa2048NoDigestSignature(alg); + } else { + return Signature.getInstance(alg, false); + } + } + + private Cipher getCipherInstance(byte alg) { + if (Cipher.ALG_RSA_PKCS1_OAEP == alg) { + return Cipher.getInstance(Cipher.CIPHER_RSA, + Cipher.PAD_PKCS1_OAEP_SHA256, false); + } else { + return Cipher.getInstance(alg, false); + } + } + + private byte getCipherAlgorithm(Cipher c) { + if (0 == c.getAlgorithm()) { + if (Cipher.PAD_PKCS1_OAEP_SHA256 == c.getPaddingAlgorithm()) { + return Cipher.ALG_RSA_PKCS1_OAEP; + } else { + // TODO: What should we do here. + KMException.throwIt(KMError.UNSUPPORTED_PADDING_MODE); + return 0; + } + } else { + return c.getAlgorithm(); + } + } + + // Create a cipher instance of each algorithm once. + private void initializeCipherPool() { + short index = 0; + while (index < CIPHER_ALGS.length) { + cipherPool[index] = new KMInstance(); + ((KMInstance) cipherPool[index]).instanceCount = 1; + ((KMInstance) cipherPool[index]).object = getCipherInstance(CIPHER_ALGS[index]); + ((KMInstance) cipherPool[index]).reserved = 0; + index++; + } + } + + private KMOperationImpl getOperationInstanceFromPool() { + return (KMOperationImpl) getInstanceFromPool(operationPool, (byte) 0x00); + } + + public void releaseOperationInstance(KMOperationImpl operation) { + releaseInstance(operationPool, operation); + } + + private Signature getSignatureInstanceFromPool(byte alg) { + return (Signature) getInstanceFromPool(sigPool, alg); + } + + public void releaseSignatureInstance(Signature signer) { + releaseInstance(sigPool, signer); + } + + private Cipher getCipherInstanceFromPool(byte alg) { + return (Cipher) getInstanceFromPool(cipherPool, alg); + } + + public void releaseCipherInstance(Cipher cipher) { + releaseInstance(cipherPool, cipher); + } + + // This pool implementation can create a maximum of total 4 instances per + // algorithm. + // This function returns the unreserved Cipher/Signature instance of type + // algorithm from pool. If + // there is no unreserved cipher/signature instance of algorithm type in the + // pool and Cipher/Signature + // algorithm instance count is less than 4 then it creates and returns a new + // Cipher/Signature + // instance of algorithm type. If there is no unreserved cipher/signature and + // maximum instance + // count reaches four it throws exception. + private Object getInstanceFromPool(Object[] pool, byte alg) { + short index = 0; + short instanceCount = 0; + Object object = null; + boolean isCipher = isCipherAlgorithm(alg); + boolean isSigner = isSignerAlgorithm(alg); + short len = (short) pool.length; + while (index < len) { + if (null == pool[index]) { + // No instance of cipher/signature with this algorithm is found + if (instanceCount < 4) { + pool[index] = new KMInstance(); + JCSystem.beginTransaction(); + ((KMInstance) pool[index]).instanceCount = (byte) (++instanceCount); + if (isCipher) + ((KMInstance) pool[index]).object = object = getCipherInstance(alg); + else + // Signature + ((KMInstance) pool[index]).object = object = getSignatureInstance(alg); + ((KMInstance) pool[index]).reserved = 1; + JCSystem.commitTransaction(); + break; + } else { + // Cipher/Signature instance count reached its maximum limit. + break; + } + } + object = ((KMInstance) pool[index]).object; + if ((isCipher && (alg == getCipherAlgorithm((Cipher) object))) + || ((isSigner && (alg == ((Signature) object).getAlgorithm())))) { + instanceCount = ((KMInstance) pool[index]).instanceCount; + if (((KMInstance) pool[index]).reserved == 0) { + JCSystem.beginTransaction(); + ((KMInstance) pool[index]).reserved = 1; + JCSystem.commitTransaction(); + break; + } + } else { + if (!isCipher && !isSigner) { + // OperationImpl + if (((KMInstance) pool[index]).reserved == 0) { + JCSystem.beginTransaction(); + ((KMInstance) pool[index]).reserved = 1; + JCSystem.commitTransaction(); + break; + } + } + } + object = null; + index++; + } + return object; + } + + private void releaseInstance(Object[] pool, Object object) { + short index = 0; + short len = (short) pool.length; + while (index < len) { + if (pool[index] != null) { + if (object == ((KMInstance) pool[index]).object) { + JCSystem.beginTransaction(); + ((KMInstance) pool[index]).reserved = 0; + JCSystem.commitTransaction(); + break; + } + } else { + // Reached end. + break; + } + index++; + } + } + + public AESKey createAESKey(short keysize) { + newRandomNumber(tmpArray, (short) 0, (short) (keysize / 8)); + return createAESKey(tmpArray, (short) 0, (short) (keysize / 8)); + } + + public AESKey createAESKey(byte[] buf, short startOff, short length) { + AESKey key = null; + short keysize = (short) (length * 8); + if (keysize == 128) { + key = (AESKey) aesKeys[KEYSIZE_128_OFFSET]; + key.setKey(buf, (short) startOff); + } else if (keysize == 256) { + key = (AESKey) aesKeys[KEYSIZE_256_OFFSET]; + key.setKey(buf, (short) startOff); + } + return key; + } + + public DESKey createTDESKey() { + newRandomNumber(tmpArray, (short) 0, + (short) (KeyBuilder.LENGTH_DES3_3KEY / 8)); + return createTDESKey(tmpArray, (short) 0, + (short) (KeyBuilder.LENGTH_DES3_3KEY / 8)); + } + + public DESKey createTDESKey(byte[] secretBuffer, short secretOff, + short secretLength) { + triDesKey.setKey(secretBuffer, secretOff); + return triDesKey; + } + + public HMACKey createHMACKey(short keysize) { + if ((keysize % 8 != 0) || !(keysize >= 64 && keysize <= 512)) { + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } + newRandomNumber(tmpArray, (short) 0, (short) (keysize / 8)); + return createHMACKey(tmpArray, (short) 0, (short) (keysize / 8)); + } + + public HMACKey createHMACKey(byte[] secretBuffer, short secretOff, + short secretLength) { + HMACKey key = null; + if (secretLength == 32) { + key = (HMACKey) hmacKeys[KEYSIZE_256_OFFSET]; + } else { + key = (HMACKey) hmacKeys[KEYSIZE_128_OFFSET]; + } + key.setKey(secretBuffer, secretOff, secretLength); + return key; + } + + public KeyPair createRsaKeyPair() { + rsaKeyPair.genKeyPair(); + return rsaKeyPair; + } + + public RSAPrivateKey createRsaKey(byte[] modBuffer, short modOff, + short modLength, byte[] privBuffer, short privOff, short privLength) { + RSAPrivateKey privKey = (RSAPrivateKey) rsaKeyPair.getPrivate(); + privKey.setExponent(privBuffer, privOff, privLength); + privKey.setModulus(modBuffer, modOff, modLength); + return privKey; + } + + public KeyPair createECKeyPair() { + ecKeyPair.genKeyPair(); + return ecKeyPair; + } + + public ECPrivateKey createEcKey(byte[] privBuffer, short privOff, + short privLength) { + ECPrivateKey privKey = (ECPrivateKey) ecKeyPair.getPrivate(); + privKey.setS(privBuffer, privOff, privLength); + return privKey; + } + + @Override + public short createSymmetricKey(byte alg, short keysize, byte[] buf, + short startOff) { + switch (alg) { + case KMType.AES: + AESKey aesKey = createAESKey(keysize); + return aesKey.getKey(buf, startOff); + case KMType.DES: + DESKey desKey = createTDESKey(); + return desKey.getKey(buf, startOff); + case KMType.HMAC: + HMACKey hmacKey = createHMACKey(keysize); + return hmacKey.getKey(buf, startOff); + default: + CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); + break; + } + return 0; + } + + @Override + public void createAsymmetricKey(byte alg, byte[] privKeyBuf, + short privKeyStart, short privKeyLength, byte[] pubModBuf, + short pubModStart, short pubModLength, short[] lengths) { + switch (alg) { + case KMType.RSA: + KeyPair rsaKey = createRsaKeyPair(); + RSAPrivateKey privKey = (RSAPrivateKey) rsaKey.getPrivate(); + lengths[0] = privKey.getExponent(privKeyBuf, privKeyStart); + lengths[1] = privKey.getModulus(pubModBuf, pubModStart); + if (lengths[0] > privKeyLength || lengths[1] > pubModLength) { + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } + break; + case KMType.EC: + KeyPair ecKey = createECKeyPair(); + ECPublicKey ecPubKey = (ECPublicKey) ecKey.getPublic(); + ECPrivateKey ecPrivKey = (ECPrivateKey) ecKey.getPrivate(); + lengths[0] = ecPrivKey.getS(privKeyBuf, privKeyStart); + lengths[1] = ecPubKey.getW(pubModBuf, pubModStart); + if (lengths[0] > privKeyLength || lengths[1] > pubModLength) { + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } + break; + default: + CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); + break; + } + } + + @Override + public boolean importSymmetricKey(byte alg, short keysize, byte[] buf, + short startOff, short length) { + switch (alg) { + case KMType.AES: + createAESKey(buf, startOff, length); + break; + case KMType.DES: + createTDESKey(buf, startOff, length); + break; + case KMType.HMAC: + createHMACKey(buf, startOff, length); + break; + default: + CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); + break; + } + return true; + } + + /* + * @Override public boolean importAsymmetricKey(byte alg, byte[] buf, short + * start, short length, byte[] privKeyBuf, short privKeyStart, short + * privKeyLength, byte[] pubModBuf, short pubModStart, short pubModLength) { + * return false; } + */ + + @Override + public boolean importAsymmetricKey(byte alg, byte[] privKeyBuf, + short privKeyStart, short privKeyLength, byte[] pubModBuf, + short pubModStart, short pubModLength) { + switch (alg) { + case KMType.RSA: + createRsaKey(pubModBuf, pubModStart, pubModLength, privKeyBuf, + privKeyStart, privKeyLength); + break; + case KMType.EC: + createEcKey(privKeyBuf, privKeyStart, privKeyLength); + break; + default: + CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); + break; + } + return true; + } + + private void initEntropyPool(byte[] pool) { + byte index = 0; + RandomData trng; + while (index < rngCounter.length) { + rngCounter[index++] = 0; + } + try { + trng = RandomData.getInstance(RandomData.ALG_TRNG); + trng.nextBytes(pool, (short) 0, (short) pool.length); + } catch (CryptoException exp) { + if (exp.getReason() == CryptoException.NO_SUCH_ALGORITHM) { + // TODO change this when possible + // simulator does not support TRNG algorithm. So, PRNG algorithm + // (deprecated) is used. + trng = RandomData.getInstance(RandomData.ALG_PSEUDO_RANDOM); + trng.nextBytes(pool, (short) 0, (short) pool.length); + } else { + // TODO change this to proper error code + ISOException.throwIt(ISO7816.SW_UNKNOWN); + } + } + } + + // Generate a secure random number from existing entropy pool. This uses aes + // cbc algorithm with + // 8 byte rngCounter and 16 byte block size. + @Override + public void newRandomNumber(byte[] num, short startOff, short length) { + KMRepository repository = KMRepository.instance(); + byte[] bufPtr = repository.getHeap(); + short countBufInd = repository.alloc(KMKeymasterApplet.AES_BLOCK_SIZE); + short randBufInd = repository.alloc(KMKeymasterApplet.AES_BLOCK_SIZE); + short len = KMKeymasterApplet.AES_BLOCK_SIZE; + aesRngKey.setKey(entropyPool, (short) 0); + aesRngCipher.init(aesRngKey, Cipher.MODE_ENCRYPT, aesICV, (short) 0, + (short) 16); + while (length > 0) { + if (length < len) + len = length; + // increment rngCounter by one + incrementCounter(); + // copy the 8 byte rngCounter into the 16 byte rngCounter buffer. + Util.arrayCopy(rngCounter, (short) 0, bufPtr, countBufInd, + (short) rngCounter.length); + // encrypt the rngCounter buffer with existing entropy which forms the aes + // key. + aesRngCipher.doFinal(bufPtr, countBufInd, + KMKeymasterApplet.AES_BLOCK_SIZE, bufPtr, randBufInd); + // copy the encrypted rngCounter block to buffer passed in the argument + Util.arrayCopy(bufPtr, randBufInd, num, startOff, len); + length = (short) (length - len); + startOff = (short) (startOff + len); + } + } + + // increment 8 byte rngCounter by one + private void incrementCounter() { + // start with least significant byte + short index = (short) (rngCounter.length - 1); + while (index >= 0) { + // if the msb of current byte is set then it will be negative + if (rngCounter[index] < 0) { + // then increment the rngCounter + rngCounter[index]++; + // is the msb still set? i.e. no carry over + if (rngCounter[index] < 0) + break; // then break + else + index--; // else go to the higher order byte + } else { + // if msb is not set then increment the rngCounter + rngCounter[index]++; + break; + } + } + } + + @Override + public void addRngEntropy(byte[] num, short offset, short length) { + // Maximum length can be 256 bytes. But currently we support max 32 bytes + // seed. + // Get existing entropy pool. + if (length > 32) + length = 32; + // Create new temporary pool. + // Populate the new pool with the entropy which is derived from current + // entropy pool. + newRandomNumber(rndNum, (short) 0, (short) entropyPool.length); + // Copy the entropy to the current pool - updates the entropy pool. + Util.arrayCopy(rndNum, (short) 0, entropyPool, (short) 0, + (short) entropyPool.length); + short index = 0; + short randIndex = 0; + // XOR the seed received from the master in the entropy pool - 16 bytes + // (entPool.length). + // at a time. + while (index < length) { + entropyPool[randIndex] = (byte) (entropyPool[randIndex] ^ num[(short) (offset + index)]); + randIndex++; + index++; + if (randIndex >= entropyPool.length) { + randIndex = 0; + } + } + } + + /* + * @Override public byte[] getTrueRandomNumber(short len) { //TODO ignore the + * size as simulator only supports 128 bit entropy return entropyPool; } + */ + @Override + public short aesGCMEncrypt(byte[] aesKey, short aesKeyStart, short aesKeyLen, + byte[] secret, short secretStart, short secretLen, byte[] encSecret, + short encSecretStart, byte[] nonce, short nonceStart, short nonceLen, + byte[] authData, short authDataStart, short authDataLen, + byte[] authTag, short authTagStart, short authTagLen) { + + if (authTagLen != AES_GCM_TAG_LENGTH) { + KMException.throwIt(KMError.UNKNOWN_ERROR); + } + if (nonceLen != AES_GCM_NONCE_LENGTH) { + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } + if (aesGcmCipher == null) { + aesGcmCipher = (AEADCipher) Cipher.getInstance(AEADCipher.ALG_AES_GCM, + false); + } + AESKey key = createAESKey(aesKey, aesKeyStart, aesKeyLen); + try { + aesGcmCipher.init(key, Cipher.MODE_ENCRYPT, nonce, nonceStart, nonceLen); + } catch (CryptoException exp) { + KMException.throwIt(exp.getReason()); + } + aesGcmCipher.updateAAD(authData, authDataStart, authDataLen); + short ciphLen = aesGcmCipher.doFinal(secret, secretStart, secretLen, + encSecret, encSecretStart); + // TODO if this retrieveTag fails, then allocate + // The tag buffer must be exact size otherwise simulator returns 0 tag. + aesGcmCipher.retrieveTag(authTag, authTagStart, authTagLen); + return ciphLen; + } + + @Override + public boolean aesGCMDecrypt(byte[] aesKey, short aesKeyStart, + short aesKeyLen, byte[] encSecret, short encSecretStart, + short encSecretLen, byte[] secret, short secretStart, byte[] nonce, + short nonceStart, short nonceLen, byte[] authData, + short authDataStart, short authDataLen, byte[] authTag, + short authTagStart, short authTagLen) { + // TODO Test and remove unnecessary trasientArrays. + if (aesGcmCipher == null) { + aesGcmCipher = (AEADCipher) Cipher.getInstance(AEADCipher.ALG_AES_GCM, + false); + } + // allocate aad buffer of exact size - otherwise simulator throws exception + // byte[] aad = JCSystem.makeTransientByteArray(authDataLen, + // JCSystem.CLEAR_ON_RESET); + + // Util.arrayCopyNonAtomic(authData, authDataStart, tmpAuthDataArray, + // (short) 0, + // authDataLen); + // allocate tag of exact size. + // byte[] tag = JCSystem.makeTransientByteArray(AES_GCM_TAG_LENGTH, + // JCSystem.CLEAR_ON_RESET); + // Util.arrayCopyNonAtomic(authTag, authTagStart, tmpArray, (short) 0, + // authTagLen); + boolean verification = false; + AESKey key = createAESKey(aesKey, aesKeyStart, aesKeyLen); + try { + aesGcmCipher.init(key, Cipher.MODE_DECRYPT, nonce, nonceStart, nonceLen); + aesGcmCipher.updateAAD(authData, authDataStart, authDataLen); + // byte[] plain = JCSystem.makeTransientByteArray(encSecretLen, + // JCSystem.CLEAR_ON_RESET); + // encrypt the secret + aesGcmCipher.doFinal(encSecret, encSecretStart, encSecretLen, secret, + secretStart); + verification = aesGcmCipher.verifyTag(authTag, authTagStart, (short) 12, + (short) 12); + } catch (CryptoException exp) { + KMException.throwIt(KMError.UNKNOWN_ERROR); + } + return verification; + } + + public HMACKey cmacKdf(byte[] keyMaterial, short keyMaterialStart, + short keyMaterialLen, byte[] label, short labelStart, short labelLen, + byte[] context, short contextStart, short contextLength) { + // This is hardcoded to requirement - 32 byte output with two concatenated + // 16 bytes K1 and K2. + final byte n = 2; // hardcoded + final byte[] L = { + 0, 0, 1, 0 }; // [L] 256 bits - hardcoded 32 bits as per + // reference impl in keymaster. + final byte[] zero = { + 0 }; // byte + short iBufLen = 4; + short keyOutLen = n * 16; + // [i] counter - 32 bits + Util.arrayFillNonAtomic(tmpArray, (short) 0, iBufLen, (byte) 0); + // byte[] iBuf = new byte[] { 0, 0, 0, 0 }; // [i] counter - 32 bits + // byte[] keyOut = new byte[(short) (n * 16)]; + Util.arrayFillNonAtomic(tmpArray, (short) iBufLen, keyOutLen, (byte) 0); + // Signature prf = Signature.getInstance(Signature.ALG_AES_CMAC_128, false); + aesKeys[KEYSIZE_256_OFFSET].setKey(keyMaterial, (short) keyMaterialStart); + // AESKey key = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, + // KeyBuilder.LENGTH_AES_256, false); + // key.setKey(keyMaterial, (short) 0); + kdf.init(aesKeys[KEYSIZE_256_OFFSET], Signature.MODE_SIGN); + byte i = 1; + short pos = 0; + while (i <= n) { + tmpArray[3] = i; + kdf.update(tmpArray, (short) 0, (short) iBufLen); // 4 bytes of iBuf with + // counter in + // it + kdf.update(label, labelStart, (short) labelLen); // label + kdf.update(zero, (short) 0, (short) 1); // 1 byte of 0x00 + kdf.update(context, contextStart, contextLength); // context + pos = kdf + .sign(L, (short) 0, (short) 4, tmpArray, (short) (iBufLen + pos)); // 4 + // bytes + // of + // L + // - + // signature of 16 + // bytes + i++; + } + return createHMACKey(tmpArray, (short) iBufLen, (short) keyOutLen); + } + + public short hmacSign(HMACKey key, byte[] data, short dataStart, + short dataLength, byte[] mac, short macStart) { + hmacSignature.init(key, Signature.MODE_SIGN); + return hmacSignature.sign(data, dataStart, dataLength, mac, macStart); + } + + public boolean hmacVerify(HMACKey key, byte[] data, short dataStart, + short dataLength, byte[] mac, short macStart, short macLength) { + hmacSignature.init(key, Signature.MODE_VERIFY); + return hmacSignature.verify(data, dataStart, dataLength, mac, macStart, + macLength); + } + + @Override + public short hmacSign(byte[] keyBuf, short keyStart, short keyLength, + byte[] data, short dataStart, short dataLength, byte[] mac, + short macStart) { + HMACKey key = createHMACKey(keyBuf, keyStart, keyLength); + return hmacSign(key, data, dataStart, dataLength, mac, macStart); + } + + @Override + public boolean hmacVerify(byte[] keyBuf, short keyStart, short keyLength, + byte[] data, short dataStart, short dataLength, byte[] mac, + short macStart, short macLength) { + HMACKey key = createHMACKey(keyBuf, keyStart, keyLength); + return hmacVerify(key, data, dataStart, dataLength, mac, macStart, + macLength); + } + + @Override + public short rsaDecipherOAEP256(byte[] secret, short secretStart, + short secretLength, byte[] modBuffer, short modOff, short modLength, + byte[] inputDataBuf, short inputDataStart, short inputDataLength, + byte[] outputDataBuf, short outputDataStart) { + Cipher.OneShot cipher = null; + RSAPrivateKey key = (RSAPrivateKey) rsaKeyPair.getPrivate(); + key.setExponent(secret, secretStart, secretLength); + key.setModulus(modBuffer, modOff, modLength); + try { + cipher = Cipher.OneShot.open(Cipher.CIPHER_RSA, + Cipher.PAD_PKCS1_OAEP_SHA256); + cipher.init(key, Cipher.MODE_DECRYPT); + return cipher.doFinal(inputDataBuf, inputDataStart, inputDataLength, + outputDataBuf, (short) outputDataStart); + + } catch (SecurityException e) { + KMException.throwIt(KMError.SECURE_HW_ACCESS_DENIED); + } catch (CryptoException e) { + KMException.throwIt(e.getReason()); + } finally { + if (cipher != null) + cipher.close(); + } + return 0; + } + + @Override + public short rsaSignPKCS1256(byte[] secret, short secretStart, + short secretLength, byte[] modBuffer, short modOff, short modLength, + byte[] inputDataBuf, short inputDataStart, short inputDataLength, + byte[] outputDataBuf, short outputDataStart) { + Signature.OneShot signer = null; + RSAPrivateKey key = (RSAPrivateKey) rsaKeyPair.getPrivate(); + key.setExponent(secret, secretStart, secretLength); + key.setModulus(modBuffer, modOff, modLength); + try { + signer = Signature.OneShot.open(MessageDigest.ALG_SHA_256, + Signature.SIG_CIPHER_RSA, Cipher.PAD_PKCS1); + signer.init(key, Signature.MODE_SIGN); + return signer.sign(inputDataBuf, inputDataStart, inputDataLength, + outputDataBuf, outputDataStart); + } finally { + signer.close(); + } + } + + private byte mapPurpose(short purpose) { + switch (purpose) { + case KMType.ENCRYPT: + return Cipher.MODE_ENCRYPT; + case KMType.DECRYPT: + return Cipher.MODE_DECRYPT; + case KMType.SIGN: + return Signature.MODE_SIGN; + case KMType.VERIFY: + return Signature.MODE_VERIFY; + } + return -1; + } + + private byte mapSignature256Alg(byte alg, byte padding, byte digest) { + switch (alg) { + case KMType.RSA: + switch (padding) { + case KMType.RSA_PKCS1_1_5_SIGN: { + if (digest == KMType.DIGEST_NONE) + return KMRsa2048NoDigestSignature.ALG_RSA_PKCS1_NODIGEST; + else + return Signature.ALG_RSA_SHA_256_PKCS1; + } + case KMType.RSA_PSS: + return Signature.ALG_RSA_SHA_256_PKCS1_PSS; + case KMType.PADDING_NONE: + return KMRsa2048NoDigestSignature.ALG_RSA_SIGN_NOPAD; + } + break; + case KMType.EC: + return Signature.ALG_ECDSA_SHA_256; + case KMType.HMAC: + return Signature.ALG_HMAC_SHA_256; + } + return -1; + } + + private byte mapCipherAlg(byte alg, byte padding, byte blockmode) { + switch (alg) { + case KMType.AES: + switch (blockmode) { + case KMType.ECB: + return Cipher.ALG_AES_BLOCK_128_ECB_NOPAD; + case KMType.CBC: + return Cipher.ALG_AES_BLOCK_128_CBC_NOPAD; + case KMType.CTR: + return Cipher.ALG_AES_CTR; + case KMType.GCM: + return AEADCipher.ALG_AES_GCM; + } + break; + case KMType.DES: + switch (blockmode) { + case KMType.ECB: + return Cipher.ALG_DES_ECB_NOPAD; + case KMType.CBC: + return Cipher.ALG_DES_CBC_NOPAD; + } + break; + case KMType.RSA: + switch (padding) { + case KMType.PADDING_NONE: + return Cipher.ALG_RSA_NOPAD; + case KMType.RSA_PKCS1_1_5_ENCRYPT: + return Cipher.ALG_RSA_PKCS1; + case KMType.RSA_OAEP: + return Cipher.ALG_RSA_PKCS1_OAEP; + } + break; + } + return -1; + } + + public Cipher createSymmetricCipher(short alg, short purpose, + short blockMode, short padding, byte[] secret, short secretStart, + short secretLength, byte[] ivBuffer, short ivStart, short ivLength) { + Key key = null; + Cipher symmCipher = null; + short len = 0; + switch (secretLength) { + case 32: + key = aesKeys[KEYSIZE_256_OFFSET]; + break; + case 16: + key = aesKeys[KEYSIZE_128_OFFSET]; + break; + case 24: + key = triDesKey; + break; + default: + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + break; + } + short cipherAlg = mapCipherAlg((byte) alg, (byte) padding, (byte) blockMode); + symmCipher = getCipherInstanceFromPool((byte) cipherAlg); + switch (cipherAlg) { + case Cipher.ALG_AES_BLOCK_128_CBC_NOPAD: + case Cipher.ALG_AES_CTR: + symmCipher.init(key, mapPurpose(purpose), ivBuffer, ivStart, ivLength); + break; + case Cipher.ALG_AES_BLOCK_128_ECB_NOPAD: + case Cipher.ALG_DES_ECB_NOPAD: + symmCipher.init(key, mapPurpose(purpose)); + break; + case Cipher.ALG_DES_CBC_NOPAD: + // TODO Consume only 8 bytes of iv. the random number for iv is of 16 + // bytes. + // While sending back the iv send only 8 bytes. + symmCipher.init(key, mapPurpose(purpose), ivBuffer, ivStart, (short) 8); + break; + case AEADCipher.ALG_AES_GCM: + ((AEADCipher) symmCipher).init(key, mapPurpose(purpose), ivBuffer, + ivStart, ivLength); + break; + default:// This should never happen + CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); + break; + } + return symmCipher; + } + + public Signature createHmacSignerVerifier(short purpose, short digest, + byte[] secret, short secretStart, short secretLength) { + byte alg = Signature.ALG_HMAC_SHA_256; + if (digest != KMType.SHA2_256) + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + Signature hmacSignerVerifier = getSignatureInstanceFromPool(alg); + HMACKey key = createHMACKey(secret, secretStart, secretLength); + hmacSignerVerifier.init(key, (byte) mapPurpose(purpose)); + return hmacSignerVerifier; + } + + @Override + public KMOperation initSymmetricOperation(byte purpose, byte alg, + byte digest, byte padding, byte blockMode, byte[] keyBuf, + short keyStart, short keyLength, byte[] ivBuf, short ivStart, + short ivLength, short macLength) { + KMOperationImpl opr = null; + switch (alg) { + case KMType.AES: + case KMType.DES: + Cipher cipher = createSymmetricCipher(alg, purpose, blockMode, padding, + keyBuf, keyStart, keyLength, ivBuf, ivStart, ivLength); + opr = getOperationInstanceFromPool(); + // Convert macLength to bytes + macLength = (short) (macLength / 8); + JCSystem.beginTransaction(); + opr.setCipher(cipher); + opr.setCipherAlgorithm(alg); + opr.setBlockMode(blockMode); + opr.setPaddingAlgorithm(padding); + opr.setMode(purpose); + opr.setMacLength(macLength); + JCSystem.commitTransaction(); + break; + case KMType.HMAC: + Signature signerVerifier = createHmacSignerVerifier(purpose, digest, + keyBuf, keyStart, keyLength); + opr = getOperationInstanceFromPool(); + JCSystem.beginTransaction(); + opr.setSignature(signerVerifier); + JCSystem.commitTransaction(); + break; + default: + CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); + break; + } + return opr; + } + + public Signature createRsaSigner(short digest, short padding, byte[] secret, + short secretStart, short secretLength, byte[] modBuffer, + short modOff, short modLength) { + byte alg = mapSignature256Alg(KMType.RSA, (byte) padding, (byte) digest); + byte opMode; + if (padding == KMType.PADDING_NONE + || (padding == KMType.RSA_PKCS1_1_5_SIGN && digest == KMType.DIGEST_NONE)) { + // return createNoDigestSigner(padding,secret, secretStart, secretLength, + // modBuffer, modOff, modLength); + opMode = Cipher.MODE_DECRYPT; + } else { + opMode = Signature.MODE_SIGN; + } + Signature rsaSigner = getSignatureInstanceFromPool(alg); + RSAPrivateKey key = (RSAPrivateKey) rsaKeyPair.getPrivate(); + key.setExponent(secret, secretStart, secretLength); + key.setModulus(modBuffer, modOff, modLength); + rsaSigner.init(key, opMode); + return rsaSigner; + } + + public Signature createRsaVerifier(short digest, short padding, + byte[] modBuffer, short modOff, short modLength) { + byte alg = mapSignature256Alg(KMType.RSA, (byte) padding, (byte) digest); + if (digest == KMType.DIGEST_NONE || padding == KMType.PADDING_NONE) + CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); + + Signature rsaVerifier = getSignatureInstanceFromPool(alg); + RSAPublicKey key = (RSAPublicKey) rsaKeyPair.getPublic(); + // setExponent + Util.setShort(tmpArray, (short) 0, (short) 0x0001); + Util.setShort(tmpArray, (short) 2, (short) 0x0001); + // byte[] exponent = new byte[] { 0x01, 0x00, 0x01 }; + key.setExponent(tmpArray, (short) 0, (short) 4); + key.setModulus(modBuffer, modOff, modLength); + rsaVerifier.init(key, Signature.MODE_VERIFY); + return rsaVerifier; + } + + // TODO Remove commented code. + /* + * private Signature createNoDigestSigner(short padding, byte[] secret, short + * secretStart, short secretLength, byte[] modBuffer, short modOff, short + * modLength) { Cipher rsaCipher = + * getCipherInstanceFromPool(Cipher.ALG_RSA_NOPAD + * );//Cipher.getInstance(Cipher.ALG_RSA_NOPAD,false); RSAPrivateKey key = + * (RSAPrivateKey) KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PRIVATE, + * KeyBuilder.LENGTH_RSA_2048, false); + * key.setExponent(secret,secretStart,secretLength); key.setModulus(modBuffer, + * modOff, modLength); rsaCipher.init(key,Cipher.MODE_DECRYPT); + * KMRsa2048NoDigestSignature inst = new + * KMRsa2048NoDigestSignature(rsaCipher,(byte)padding, + * modBuffer,modOff,modLength); return inst; } + */ + + public Cipher createRsaCipher(short padding, short digest, byte[] modBuffer, + short modOff, short modLength) { + byte cipherAlg = mapCipherAlg(KMType.RSA, (byte) padding, (byte) 0); + // TODO: Implement from NXP. + /* + * if (cipherAlg == Cipher.ALG_RSA_PKCS1_OAEP) { //TODO: Implement from NXP. + * KMException.throwIt(KMError.UNIMPLEMENTED); } + */ + Cipher rsaCipher = getCipherInstanceFromPool(cipherAlg); + RSAPublicKey key = (RSAPublicKey) rsaKeyPair.getPublic(); + // setExponent + Util.setShort(tmpArray, (short) 0, (short) 0x0001); + Util.setShort(tmpArray, (short) 2, (short) 0x0001); + // byte[] exponent = new byte[] { 0x01, 0x00, 0x01 }; + key.setExponent(tmpArray, (short) 0, (short) 4); + key.setModulus(modBuffer, modOff, modLength); + rsaCipher.init(key, Cipher.MODE_ENCRYPT); + return rsaCipher; + } + + public Cipher createRsaDecipher(short padding, short digest, byte[] secret, + short secretStart, short secretLength, byte[] modBuffer, + short modOff, short modLength) { + byte cipherAlg = mapCipherAlg(KMType.RSA, (byte) padding, (byte) 0); + /* + * if (cipherAlg == Cipher.ALG_RSA_PKCS1_OAEP) { //TODO: Implement from NXP. + * KMException.throwIt(KMError.UNIMPLEMENTED); } + */ + Cipher rsaCipher = getCipherInstanceFromPool(cipherAlg); + RSAPrivateKey key = (RSAPrivateKey) rsaKeyPair.getPrivate(); + key.setExponent(secret, secretStart, secretLength); + key.setModulus(modBuffer, modOff, modLength); + rsaCipher.init(key, Cipher.MODE_DECRYPT); + return rsaCipher; + } + + public Signature createEcSigner(short digest, byte[] secret, + short secretStart, short secretLength) { + byte alg = mapSignature256Alg(KMType.EC, (byte) 0, (byte) digest); + Signature ecSigner = null; + if (digest == KMType.DIGEST_NONE) { + // TODO: Implement from NXP. + KMException.throwIt(KMError.UNIMPLEMENTED); + } else { + ECPrivateKey key = (ECPrivateKey) ecKeyPair.getPrivate(); + key.setS(secret, secretStart, secretLength); + ecSigner = getSignatureInstanceFromPool(alg); + ecSigner.init(key, Signature.MODE_SIGN); + } + return ecSigner; + } + + public Signature createEcVerifier(short digest, byte[] pubKey, + short pubKeyStart, short pubKeyLength) { + byte alg = mapSignature256Alg(KMType.EC, (byte) 0, (byte) digest); + Signature ecVerifier = null; + // if(msgDigestAlg == MessageDigest.ALG_NULL) + // CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); + if (digest == KMType.DIGEST_NONE) { + // TODO: Implement from NXP. + KMException.throwIt(KMError.UNIMPLEMENTED); + } else { + ECPublicKey key = (ECPublicKey) ecKeyPair.getPublic(); + key.setW(pubKey, pubKeyStart, pubKeyLength); + ecVerifier = getSignatureInstanceFromPool(alg); + ecVerifier.init(key, Signature.MODE_VERIFY); + } + return ecVerifier; + } + + @Override + public KMOperation initAsymmetricOperation(byte purpose, byte alg, + byte padding, byte digest, byte[] privKeyBuf, short privKeyStart, + short privKeyLength, byte[] pubModBuf, short pubModStart, + short pubModLength) { + KMOperationImpl opr = null; + if (alg == KMType.RSA) { + switch (purpose) { + case KMType.SIGN: + Signature signer = createRsaSigner(digest, padding, privKeyBuf, + privKeyStart, privKeyLength, pubModBuf, pubModStart, + pubModLength); + opr = getOperationInstanceFromPool(); + JCSystem.beginTransaction(); + opr.setSignature(signer); + opr.setCipherAlgorithm(alg); + opr.setPaddingAlgorithm(padding); + opr.setMode(purpose); + JCSystem.commitTransaction(); + break; + case KMType.VERIFY: + Signature verifier = createRsaVerifier(digest, padding, pubModBuf, + pubModStart, pubModLength); + opr = getOperationInstanceFromPool(); + JCSystem.beginTransaction(); + opr.setSignature(verifier); + opr.setCipherAlgorithm(alg); + opr.setPaddingAlgorithm(padding); + opr.setMode(purpose); + JCSystem.commitTransaction(); + break; + case KMType.ENCRYPT: + Cipher cipher = createRsaCipher(padding, digest, pubModBuf, + pubModStart, pubModLength); + opr = getOperationInstanceFromPool(); + JCSystem.beginTransaction(); + opr.setCipher(cipher); + opr.setCipherAlgorithm(alg); + opr.setPaddingAlgorithm(padding); + opr.setMode(purpose); + JCSystem.commitTransaction(); + break; + case KMType.DECRYPT: + Cipher decipher = createRsaDecipher(padding, digest, privKeyBuf, + privKeyStart, privKeyLength, pubModBuf, pubModStart, + pubModLength); + opr = getOperationInstanceFromPool(); + JCSystem.beginTransaction(); + opr.setCipher(decipher); + opr.setCipherAlgorithm(alg); + opr.setPaddingAlgorithm(padding); + opr.setMode(purpose); + JCSystem.commitTransaction(); + break; + default: + break; + } + } else if (alg == KMType.EC) { + switch (purpose) { + case KMType.SIGN: + Signature signer = createEcSigner(digest, privKeyBuf, privKeyStart, + privKeyLength); + opr = getOperationInstanceFromPool(); + JCSystem.beginTransaction(); + opr.setSignature(signer); + JCSystem.commitTransaction(); + break; + case KMType.VERIFY: + Signature verifier = createEcVerifier(digest, pubModBuf, pubModStart, + pubModLength); + opr = getOperationInstanceFromPool(); + JCSystem.beginTransaction(); + opr.setSignature(verifier); + JCSystem.commitTransaction(); + break; + } + } else { + CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); + } + return opr; + + } + + @Override + public KMAttestationCert getAttestationCert(boolean rsaCert) { + return KMAttestationCertImpl.instance(rsaCert); + } + + @Override + public short aesCCMSign(byte[] bufIn, short bufInStart, short buffInLength, + byte[] masterKeySecret, short masterKeyStart, short masterKeyLen, + byte[] bufOut, short bufStart) { + if (masterKeyLen > 16) { + return -1; + } + aesKeys[KEYSIZE_128_OFFSET].setKey(masterKeySecret, (short) masterKeyStart); + kdf.init(aesKeys[KEYSIZE_128_OFFSET], Signature.MODE_SIGN); + return kdf.sign(bufIn, bufInStart, buffInLength, bufOut, bufStart); + } + + @Override + public boolean isBackupRestoreSupported() { + // TODO Auto-generated method stub + return false; + } + + @Override + public void backup(byte[] buf, short start, short len) { + // TODO Auto-generated method stub + + } + + @Override + public short restore(byte[] buf, short start) { + // TODO Auto-generated method stub + return 0; + } + + @Override + public void getTrueRandomNumber(byte[] buf, short start, short length) { + Util.arrayCopy(entropyPool, (short) 0, buf, start, length); + } + + @Override + public short cmacKdf(byte[] keyMaterial, short keyMaterialStart, + short keyMaterialLen, byte[] label, short labelStart, short labelLen, + byte[] context, short contextStart, short contextLength, + byte[] keyBuf, short keyStart) { + HMACKey key = cmacKdf(keyMaterial, keyMaterialStart, keyMaterialLen, label, + labelStart, labelLen, context, contextStart, contextLength); + return key.getKey(keyBuf, keyStart); + } + +} diff --git a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMOperationImpl.java b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMOperationImpl.java new file mode 100644 index 00000000..5b325321 --- /dev/null +++ b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMOperationImpl.java @@ -0,0 +1,240 @@ +package com.android.javacard.keymaster; + +import javacard.framework.JCSystem; +import javacard.framework.Util; +import javacard.security.CryptoException; +import javacard.security.Signature; +import javacardx.crypto.AEADCipher; +import javacardx.crypto.Cipher; + +public class KMOperationImpl implements KMOperation { + private Cipher cipher; + private Signature signature; + private short cipherAlg; + private short padding; + private short mode; + private boolean verificationFlag; + private short blockMode; + private short macLength; + private short aesGcmUpdatedLen; + + public KMOperationImpl() { + } + + public short getMode() { + return mode; + } + + public void setMode(short mode) { + this.mode = mode; + } + + public short getMacLength() { + return macLength; + } + + public void setMacLength(short macLength) { + this.macLength = macLength; + } + + public short getPaddingAlgorithm() { + return padding; + } + + public void setPaddingAlgorithm(short alg) { + padding = alg; + } + + public void setBlockMode(short mode){ + blockMode = mode; + } + + public short getBlockMode(){ + return blockMode; + } + + public short getCipherAlgorithm() { + return cipherAlg; + } + + public void setCipherAlgorithm(short cipherAlg) { + this.cipherAlg = cipherAlg; + } + + + public void setCipher(Cipher cipher) { + this.cipher = cipher; + } + + public void setSignature(Signature signer) { + this.signature = signer; + } + + private void resetCipher() { + JCSystem.beginTransaction(); + cipher = null; + macLength = 0; + aesGcmUpdatedLen = 0; + blockMode = 0; + mode = 0; + cipherAlg = 0; + JCSystem.commitTransaction(); + } + + //@Override + public short update(byte[] inputDataBuf, short inputDataStart, short inputDataLength, + byte[] outputDataBuf, short outputDataStart) { + short len = cipher.update(inputDataBuf,inputDataStart,inputDataLength,outputDataBuf,outputDataStart); + if(cipherAlg == KMType.AES && blockMode == KMType.GCM) { + //Every time Block size data is stored as intermediate result. + aesGcmUpdatedLen += (short)(inputDataLength - len); + } + return len; + } + + //@Override + public short update(byte[] inputDataBuf, short inputDataStart, short inputDataLength) { + signature.update(inputDataBuf,inputDataStart,inputDataLength); + return 0; + } + + //@Override + public short finish(byte[] inputDataBuf, short inputDataStart, + short inputDataLen, byte[] outputDataBuf, short outputDataStart) { + byte[] tmpArray = KMJCOPSimProvider.getInstance().tmpArray; + //byte[] tmpArray = JCSystem.makeTransientByteArray((short)256, JCSystem.CLEAR_ON_DESELECT); + short len = 0; + try { + if(cipherAlg == KMType.AES && blockMode == KMType.GCM) { + if(mode == KMType.DECRYPT) { + inputDataLen = (short)(inputDataLen - macLength); + } + } else if(cipherAlg == KMType.RSA && padding == KMType.PADDING_NONE && mode == KMType.ENCRYPT ){ + // Length cannot be greater then key size according to JcardSim + if(inputDataLen > 256) KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + // make input equal to 255 bytes + //byte[] tmp = new byte[255]; + Util.arrayFillNonAtomic(tmpArray,(short)0,(short)256, (byte)0); + Util.arrayCopyNonAtomic( + inputDataBuf, + inputDataStart, + tmpArray, (short)(256 - inputDataLen),inputDataLen); + inputDataStart = 0; + inputDataLen = 256; + inputDataBuf = tmpArray; + + } else if((cipherAlg == KMType.DES || cipherAlg == KMType.AES) && padding ==KMType.PKCS7 && mode == KMType.ENCRYPT){ + byte blkSize = 16; + byte paddingBytes; + short inputlen = inputDataLen; + if (cipherAlg == KMType.DES) blkSize = 8; + // padding bytes + if (inputlen % blkSize == 0) paddingBytes = blkSize; + else paddingBytes = (byte) (blkSize - (inputlen % blkSize)); + // final len with padding + inputlen = (short) (inputlen + paddingBytes); + // intermediate buffer to copy input data+padding + //byte[] tmp = new byte[len]; + // fill in the padding + Util.arrayFillNonAtomic(tmpArray, (short) 0, inputlen, paddingBytes); + // copy the input data + Util.arrayCopyNonAtomic(inputDataBuf,inputDataStart, tmpArray, (short)0, inputDataLen); + inputDataBuf = tmpArray; + inputDataLen = inputlen; + inputDataStart = 0; + } + len = cipher.doFinal(inputDataBuf, inputDataStart, inputDataLen, outputDataBuf, outputDataStart); + // JCOPProvider removes leading zeros during decryption in case of no padding - so add that back. + if (cipherAlg == KMType.RSA && padding == KMType.PADDING_NONE && mode == KMType.DECRYPT && len < 256) { + //byte[] tempBuf = new byte[256]; + //TODO Is this code required ?? + /*Util.arrayFill(tmpArray, (short) 0, (short) 256, (byte) 0); + Util.arrayCopy(outputDataBuf, (short) 0, tmpArray, (short) (outputDataStart + 256 - len), len); + Util.arrayCopy(tmpArray, (short) 0, outputDataBuf, outputDataStart, (short) 256); + len = 256;*/ + } else if((cipherAlg == KMType.AES || cipherAlg == KMType.DES) // PKCS7 + && padding == KMType.PKCS7 + && mode == KMType.DECRYPT){ + byte blkSize = 16; + if (cipherAlg == KMType.DES) blkSize = 8; + if(len >0) { + //verify if padding is corrupted. + byte paddingByte = outputDataBuf[(short)(outputDataStart+len -1)]; + //padding byte always should be <= block size + if((short)paddingByte > blkSize || + (short)paddingByte <= 0) KMException.throwIt(KMError.INVALID_ARGUMENT); + len = (short)(len - (short)paddingByte);// remove the padding bytes + } + } else if(cipherAlg == KMType.AES && blockMode == KMType.GCM) { + if(mode == KMType.ENCRYPT) { + len += ((AEADCipher) cipher).retrieveTag(outputDataBuf, (short)(outputDataStart+len), macLength); + } else { + boolean verified = ((AEADCipher) cipher).verifyTag(inputDataBuf, (short)(inputDataStart+inputDataLen), macLength, macLength); + if(!verified) KMException.throwIt(KMError.VERIFICATION_FAILED); + } + } + } finally { + //KMJCOPSimProvider.getInstance().clean(); + KMJCOPSimProvider.getInstance().releaseCipherInstance(cipher); + resetCipher(); + } + return len; + } + + //@Override + public short sign(byte[] inputDataBuf, short inputDataStart, short inputDataLength, byte[] signBuf, short signStart) { + short len = 0; + try { + len = signature.sign(inputDataBuf,inputDataStart,inputDataLength,signBuf,signStart); + } finally { + KMJCOPSimProvider.getInstance().releaseSignatureInstance(signature); + signature = null; + } + return len; + } + + //@Override + public boolean verify(byte[] inputDataBuf, short inputDataStart, short inputDataLength, byte[] signBuf, short signStart, short signLength) { + boolean ret = false; + try { + ret = signature.verify(inputDataBuf,inputDataStart,inputDataLength,signBuf,signStart,signLength); + } finally { + KMJCOPSimProvider.getInstance().releaseSignatureInstance(signature); + signature = null; + } + return ret; + } + + //@Override + public void abort() { + // do nothing + if(cipher != null) { + KMJCOPSimProvider.getInstance().releaseCipherInstance(cipher); + cipher = null; + } + if(signature != null) { + KMJCOPSimProvider.getInstance().releaseSignatureInstance(signature); + signature = null; + } + } + + //@Override + public void updateAAD(byte[] dataBuf, short dataStart, short dataLength) { + ((AEADCipher) cipher).updateAAD(dataBuf, dataStart, dataLength); + } + + //@Override + public short getAESGCMOutputSize(short dataSize, short macLength) { + if (mode == KMType.ENCRYPT) { + return (short) (aesGcmUpdatedLen + dataSize + macLength); + } else { + return (short) (aesGcmUpdatedLen + dataSize - macLength); + } + } + + //@Override + public void release() { + KMJCOPSimProvider.getInstance().releaseOperationInstance(this); + } + +} diff --git a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java new file mode 100644 index 00000000..94eb6355 --- /dev/null +++ b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java @@ -0,0 +1,135 @@ +package com.android.javacard.keymaster; + +import javacard.framework.JCSystem; +import javacard.framework.Util; +import javacard.security.CryptoException; +import javacard.security.Key; +import javacard.security.MessageDigest; +import javacard.security.Signature; +import javacardx.crypto.Cipher; + +public class KMRsa2048NoDigestSignature extends Signature { + private Cipher inst; // ALG_RSA_NOPAD.; + //TODO ?? + //private byte[] rsaModulus; // to compare with the data value + + public static final byte ALG_RSA_SIGN_NOPAD = (byte)0x65; //TODO Change value later + public static final byte ALG_RSA_PKCS1_NODIGEST = (byte)0x66; //TODO Change value later + private byte algorithm; + + public KMRsa2048NoDigestSignature(byte alg){ + algorithm = alg; + inst = Cipher.getInstance(Cipher.ALG_RSA_NOPAD, false); + } + + /*public KMRsa2048NoDigestSignature(Cipher ciph, byte padding, byte[]mod, short start, short len){ + inst = ciph; + this.padding = padding; + if(len != 256) CryptoException.throwIt(CryptoException.INVALID_INIT); + rsaModulus = new byte[256]; + Util.arrayCopyNonAtomic(mod,start,rsaModulus,(short)0,len); + }*/ + + @Override + public void init(Key key, byte b) throws CryptoException { + inst.init(key, b); + } + + @Override + public void init(Key key, byte b, byte[] bytes, short i, short i1) throws CryptoException { + inst.init(key, b, bytes, i, i1); + } + + @Override + public void setInitialDigest(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) throws CryptoException { + //TODO + } + + @Override + public byte getAlgorithm() { + return algorithm; + } + + @Override + public byte getMessageDigestAlgorithm() { + return MessageDigest.ALG_NULL; + } + + @Override + public byte getCipherAlgorithm() { + return algorithm; + } + + @Override + public byte getPaddingAlgorithm() { + return Cipher.PAD_NULL; + } + + @Override + public short getLength() throws CryptoException { + return 0; + } + + @Override + public void update(byte[] bytes, short i, short i1) throws CryptoException { + // HAL accumulates the data and send it at finish operation. + } + + @Override + public short sign(byte[] bytes, short i, short i1, byte[] bytes1, short i2) throws CryptoException { + padData(bytes,i,i1, KMJCOPSimProvider.getInstance().tmpArray, (short)0); + return inst.doFinal(KMJCOPSimProvider.getInstance().tmpArray,(short)0,(short)256, bytes1, i2); + } + + @Override + public short signPreComputedHash(byte[] bytes, short i, short i1, byte[] bytes1, short i2) throws CryptoException { + return 0; + } + + @Override + public boolean verify(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) throws CryptoException { + // Cannot support this method as javacard cipher api does not allow 256 byte for public key + // encryption without padding. It only allows 255 bytes data. + return false; + } + + @Override + public boolean verifyPreComputedHash(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) throws CryptoException { + return false; + } + + private void padData(byte[] buf, short start, short len, + byte[] outBuf, short outBufStart){ + //byte[] inputData = new byte[256]; + //TODO ? + /*if(!isValidData(buf, start,len)){ + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + }*/ + Util.arrayFillNonAtomic(outBuf, (short) outBufStart, (short) 256, (byte) 0x00); + if (algorithm == ALG_RSA_SIGN_NOPAD) { // add zero to right + } else if (algorithm == ALG_RSA_PKCS1_NODIGEST) {// 0x00||0x01||PS||0x00 + outBuf[0] = 0x00; + outBuf[1] = 0x01; + Util.arrayFillNonAtomic(outBuf,(short)2,(short)(256-len-3),(byte)0xFF); + outBuf[(short)(256-len-1)] = 0x00; + }else{ + CryptoException.throwIt(CryptoException.ILLEGAL_USE); + } + Util.arrayCopyNonAtomic(buf, start, outBuf,(short)(256 -len), len); + } + + /*private boolean isValidData(byte[] buf, short start, short len) { + if (padding == KMType.PADDING_NONE) { + if (len > 256) return false; + else if (len == 256) { + short v = Util.arrayCompare(buf, start, rsaModulus, (short) 0, len); + if (v > 0) return false; + } + } else {//pkcs1 no digest + if(len > 245){ + return false; + } + } + return true; + }*/ +} diff --git a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMSEProviderImpl.java b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMSEProviderImpl.java new file mode 100644 index 00000000..9abdc548 --- /dev/null +++ b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMSEProviderImpl.java @@ -0,0 +1,8 @@ + +package com.android.javacard.keymaster; + +public class KMSEProviderImpl { + public static KMSEProvider instance(){ + return KMJCOPSimProvider.getInstance(); + } +} diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMOperationImpl.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMOperationImpl.java index 755b7134..941fd6cd 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMOperationImpl.java +++ b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMOperationImpl.java @@ -57,4 +57,10 @@ public short getAESGCMOutputSize(short dataSize, short macLength) { return cipher.getAesGcmOutputSize(dataSize, macLength); } +@Override +public void release() { + // TODO Auto-generated method stub + +} + } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 4dc5ce9a..6b6f21f3 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -2693,7 +2693,7 @@ private void beginSignVerifyOperation(KMOperationState op) { try { op.setOperation( seProvider.initSymmetricOperation( - (byte) op.getPurpose(), + (byte) KMType.SIGN, op.getAlgorithm(), op.getDigest(), op.getPadding(), @@ -3948,7 +3948,8 @@ private static short deriveKey(byte[] scratchPad) { tmpVariables[2], KMByteBlob.cast(tmpVariables[4]).getBuffer(), KMByteBlob.cast(tmpVariables[4]).getStartOff(), - KMByteBlob.cast(tmpVariables[4]).length(), + KMByteBlob.cast(tmpVariables[4 + ]).length(), scratchPad, (short) 0); if (tmpVariables[3] < 0) { diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMOperation.java b/Applet/Applet/src/com/android/javacard/keymaster/KMOperation.java index 4011d7f5..88cda5b4 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMOperation.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMOperation.java @@ -34,4 +34,6 @@ boolean verify(byte[] inputDataBuf, short inputDataStart, short inputDataLength, // include the auth tag which is appended at the end of the encrypted data. For decryption this will be // size of the decrypted data only. short getAESGCMOutputSize(short dataSize, short macLength); + + void release(); } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMOperationState.java b/Applet/Applet/src/com/android/javacard/keymaster/KMOperationState.java index 62a499f2..7934ef29 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMOperationState.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMOperationState.java @@ -129,12 +129,13 @@ private void dataUpdated(){ } public void release() { + Object[] ops = ((Object[]) slot[REFS]); + ((KMOperation)ops[OPERATION]).release(); JCSystem.beginTransaction(); Util.arrayFillNonAtomic( (byte[]) slot[0], (short) 0, (short) ((byte[]) slot[0]).length, (byte) 0); - Object[] ops = ((Object[]) slot[1]); - ops[0] = null; - ops[1] = null; + ops[OPERATION] = null; + ops[HMAC_SIGNER] = null; JCSystem.commitTransaction(); reset(); } From b4a3d6595c8f3487f53229075f40d00ec4c57240 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Tue, 6 Oct 2020 11:37:14 +0100 Subject: [PATCH 02/42] In update operation, the inputConsumed len is equal to input length --- .../com/android/javacard/keymaster/KMKeymasterApplet.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 6b6f21f3..af596c48 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -2124,6 +2124,9 @@ private void processUpdateOperationCmd(APDU apdu) { // Allocate output buffer as input data is already block aligned data[OUTPUT_DATA] = KMByteBlob.instance(tmpVariables[0]); // Otherwise just update the data. + //HAL consumes all the input and maintains a buffered data inside it. So the + //applet inputConsumed as the input length. + tmpVariables[3] = tmpVariables[0]; try { tmpVariables[0] = op.getOperation() @@ -2159,7 +2162,7 @@ private void processUpdateOperationCmd(APDU apdu) { data[OUTPUT_DATA] = KMByteBlob.instance((short) 0); } KMArray.cast(tmpVariables[2]).add((short) 0, KMInteger.uint_16(KMError.OK)); - KMArray.cast(tmpVariables[2]).add((short) 1, KMInteger.uint_16(tmpVariables[0])); + KMArray.cast(tmpVariables[2]).add((short) 1, KMInteger.uint_16(tmpVariables[3])); KMArray.cast(tmpVariables[2]).add((short) 2, tmpVariables[1]); KMArray.cast(tmpVariables[2]).add((short) 3, data[OUTPUT_DATA]); // Encode the response From 76c5c97223df4d99dd95ef723c7d641dc1927b4d Mon Sep 17 00:00:00 2001 From: bvenkatswarlu Date: Fri, 16 Oct 2020 00:48:10 +0530 Subject: [PATCH 03/42] Added code for ECDSA No Digest Fixed few bugs relating to Hmac operation, abort operation Modified the KMKeymasterApplet code to send back the inputConsumed length equal to input length. --- .../javacard/keymaster/KMJCOPSimProvider.java | 56 +++++++------------ .../javacard/keymaster/KMOperationImpl.java | 27 ++++----- .../keymaster/KMRsa2048NoDigestSignature.java | 1 - .../javacard/keymaster/KMKeymasterApplet.java | 11 +++- .../javacard/keymaster/KMOperation.java | 2 - .../javacard/keymaster/KMOperationState.java | 2 +- 6 files changed, 39 insertions(+), 60 deletions(-) diff --git a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMJCOPSimProvider.java b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMJCOPSimProvider.java index fc343c54..18cf2fae 100644 --- a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMJCOPSimProvider.java +++ b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMJCOPSimProvider.java @@ -15,16 +15,6 @@ */ package com.android.javacard.keymaster; -import com.android.javacard.keymaster.KMAttestationCert; -import com.android.javacard.keymaster.KMError; -import com.android.javacard.keymaster.KMException; -import com.android.javacard.keymaster.KMInstance; -import com.android.javacard.keymaster.KMKeymasterApplet; -import com.android.javacard.keymaster.KMOperation; -import com.android.javacard.keymaster.KMRepository; -import com.android.javacard.keymaster.KMSEProvider; -import com.android.javacard.keymaster.KMType; - import javacard.framework.ISO7816; import javacard.framework.ISOException; import javacard.framework.JCSystem; @@ -133,14 +123,15 @@ public class KMJCOPSimProvider implements KMSEProvider { Signature.ALG_RSA_SHA_256_PKCS1, Signature.ALG_RSA_SHA_256_PKCS1_PSS, Signature.ALG_ECDSA_SHA_256, Signature.ALG_HMAC_SHA_256, KMRsa2048NoDigestSignature.ALG_RSA_SIGN_NOPAD, - KMRsa2048NoDigestSignature.ALG_RSA_PKCS1_NODIGEST }; + KMRsa2048NoDigestSignature.ALG_RSA_PKCS1_NODIGEST, + KMEcdsa256NoDigestSignature.ALG_ECDSA_NODIGEST}; // AESKey private AESKey aesKeys[]; // DES3Key private DESKey triDesKey; // HMACKey - private HMACKey hmacKeys[]; + private HMACKey hmacKey; // RSA Key Pair private KeyPair rsaKeyPair; // EC Key Pair. @@ -186,11 +177,8 @@ private KMJCOPSimProvider() { KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_256, false); triDesKey = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES, KeyBuilder.LENGTH_DES3_3KEY, false); - hmacKeys = new HMACKey[2]; - hmacKeys[KEYSIZE_128_OFFSET] = (HMACKey) KeyBuilder.buildKey( - KeyBuilder.TYPE_HMAC, (short) 128, false); - hmacKeys[KEYSIZE_256_OFFSET] = (HMACKey) KeyBuilder.buildKey( - KeyBuilder.TYPE_HMAC, (short) 256, false); + hmacKey = (HMACKey) KeyBuilder.buildKey( + KeyBuilder.TYPE_HMAC, (short) 512, false); rsaKeyPair = new KeyPair(KeyPair.ALG_RSA, KeyBuilder.LENGTH_RSA_2048); initECKey(); @@ -311,6 +299,8 @@ private Signature getSignatureInstance(byte alg) { if (KMRsa2048NoDigestSignature.ALG_RSA_SIGN_NOPAD == alg || KMRsa2048NoDigestSignature.ALG_RSA_PKCS1_NODIGEST == alg) { return new KMRsa2048NoDigestSignature(alg); + } else if(KMEcdsa256NoDigestSignature.ALG_ECDSA_NODIGEST == alg) { + return new KMEcdsa256NoDigestSignature(alg); } else { return Signature.getInstance(alg, false); } @@ -500,14 +490,8 @@ public HMACKey createHMACKey(short keysize) { public HMACKey createHMACKey(byte[] secretBuffer, short secretOff, short secretLength) { - HMACKey key = null; - if (secretLength == 32) { - key = (HMACKey) hmacKeys[KEYSIZE_256_OFFSET]; - } else { - key = (HMACKey) hmacKeys[KEYSIZE_128_OFFSET]; - } - key.setKey(secretBuffer, secretOff, secretLength); - return key; + hmacKey.setKey(secretBuffer, secretOff, secretLength); + return hmacKey; } public KeyPair createRsaKeyPair() { @@ -970,7 +954,10 @@ private byte mapSignature256Alg(byte alg, byte padding, byte digest) { } break; case KMType.EC: - return Signature.ALG_ECDSA_SHA_256; + if (digest == KMType.DIGEST_NONE) + return KMEcdsa256NoDigestSignature.ALG_ECDSA_NODIGEST; + else + return Signature.ALG_ECDSA_SHA_256; case KMType.HMAC: return Signature.ALG_HMAC_SHA_256; } @@ -1018,16 +1005,18 @@ public Cipher createSymmetricCipher(short alg, short purpose, short secretLength, byte[] ivBuffer, short ivStart, short ivLength) { Key key = null; Cipher symmCipher = null; - short len = 0; switch (secretLength) { case 32: key = aesKeys[KEYSIZE_256_OFFSET]; + ((AESKey) key).setKey(secret,secretStart); break; case 16: key = aesKeys[KEYSIZE_128_OFFSET]; + ((AESKey) key).setKey(secret,secretStart); break; case 24: key = triDesKey; + ((DESKey) key).setKey(secret,secretStart); break; default: CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); @@ -1205,15 +1194,10 @@ public Signature createEcSigner(short digest, byte[] secret, short secretStart, short secretLength) { byte alg = mapSignature256Alg(KMType.EC, (byte) 0, (byte) digest); Signature ecSigner = null; - if (digest == KMType.DIGEST_NONE) { - // TODO: Implement from NXP. - KMException.throwIt(KMError.UNIMPLEMENTED); - } else { - ECPrivateKey key = (ECPrivateKey) ecKeyPair.getPrivate(); - key.setS(secret, secretStart, secretLength); - ecSigner = getSignatureInstanceFromPool(alg); - ecSigner.init(key, Signature.MODE_SIGN); - } + ECPrivateKey key = (ECPrivateKey) ecKeyPair.getPrivate(); + key.setS(secret, secretStart, secretLength); + ecSigner = getSignatureInstanceFromPool(alg); + ecSigner.init(key, Signature.MODE_SIGN); return ecSigner; } diff --git a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMOperationImpl.java b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMOperationImpl.java index 5b325321..6429cff2 100644 --- a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMOperationImpl.java +++ b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMOperationImpl.java @@ -2,7 +2,6 @@ import javacard.framework.JCSystem; import javacard.framework.Util; -import javacard.security.CryptoException; import javacard.security.Signature; import javacardx.crypto.AEADCipher; import javacardx.crypto.Cipher; @@ -13,7 +12,6 @@ public class KMOperationImpl implements KMOperation { private short cipherAlg; private short padding; private short mode; - private boolean verificationFlag; private short blockMode; private short macLength; private short aesGcmUpdatedLen; @@ -81,7 +79,7 @@ private void resetCipher() { JCSystem.commitTransaction(); } - //@Override + @Override public short update(byte[] inputDataBuf, short inputDataStart, short inputDataLength, byte[] outputDataBuf, short outputDataStart) { short len = cipher.update(inputDataBuf,inputDataStart,inputDataLength,outputDataBuf,outputDataStart); @@ -92,13 +90,13 @@ public short update(byte[] inputDataBuf, short inputDataStart, short inputDataLe return len; } - //@Override + @Override public short update(byte[] inputDataBuf, short inputDataStart, short inputDataLength) { signature.update(inputDataBuf,inputDataStart,inputDataLength); return 0; } - //@Override + @Override public short finish(byte[] inputDataBuf, short inputDataStart, short inputDataLen, byte[] outputDataBuf, short outputDataStart) { byte[] tmpArray = KMJCOPSimProvider.getInstance().tmpArray; @@ -181,7 +179,7 @@ public short finish(byte[] inputDataBuf, short inputDataStart, return len; } - //@Override + @Override public short sign(byte[] inputDataBuf, short inputDataStart, short inputDataLength, byte[] signBuf, short signStart) { short len = 0; try { @@ -193,7 +191,7 @@ public short sign(byte[] inputDataBuf, short inputDataStart, short inputDataLeng return len; } - //@Override + @Override public boolean verify(byte[] inputDataBuf, short inputDataStart, short inputDataLength, byte[] signBuf, short signStart, short signLength) { boolean ret = false; try { @@ -205,25 +203,26 @@ public boolean verify(byte[] inputDataBuf, short inputDataStart, short inputData return ret; } - //@Override + @Override public void abort() { // do nothing if(cipher != null) { KMJCOPSimProvider.getInstance().releaseCipherInstance(cipher); - cipher = null; + resetCipher(); } if(signature != null) { KMJCOPSimProvider.getInstance().releaseSignatureInstance(signature); signature = null; } + KMJCOPSimProvider.getInstance().releaseOperationInstance(this); } - //@Override + @Override public void updateAAD(byte[] dataBuf, short dataStart, short dataLength) { ((AEADCipher) cipher).updateAAD(dataBuf, dataStart, dataLength); } - //@Override + @Override public short getAESGCMOutputSize(short dataSize, short macLength) { if (mode == KMType.ENCRYPT) { return (short) (aesGcmUpdatedLen + dataSize + macLength); @@ -231,10 +230,4 @@ public short getAESGCMOutputSize(short dataSize, short macLength) { return (short) (aesGcmUpdatedLen + dataSize - macLength); } } - - //@Override - public void release() { - KMJCOPSimProvider.getInstance().releaseOperationInstance(this); - } - } diff --git a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java index 94eb6355..24aac2f6 100644 --- a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java +++ b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java @@ -1,6 +1,5 @@ package com.android.javacard.keymaster; -import javacard.framework.JCSystem; import javacard.framework.Util; import javacard.security.CryptoException; import javacard.security.Key; diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index af596c48..0c8b9cb9 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -228,6 +228,9 @@ public boolean select() { keymasterState = KMKeymasterApplet.FIRST_SELECT_STATE; } else if (keymasterState == KMKeymasterApplet.INACTIVE_STATE) { keymasterState = KMKeymasterApplet.ACTIVE_STATE; + } else if (keymasterState == KMKeymasterApplet.ACTIVE_STATE || + keymasterState == KMKeymasterApplet.FIRST_SELECT_STATE) { + return true; } else { return false; } @@ -2095,6 +2098,7 @@ private void processUpdateOperationCmd(APDU apdu) { } // TODO refactor and optimize this tmpVariables[0] = KMByteBlob.cast(data[INPUT_DATA]).length(); + short additionalExpOutLen = 0; if (op.getAlgorithm() == KMType.AES) { if (op.getBlockMode() == KMType.GCM) { updateAAD(op, (byte) 0x00); @@ -2108,6 +2112,7 @@ private void processUpdateOperationCmd(APDU apdu) { op.setAesGcmUpdateComplete(); } } + additionalExpOutLen = 16; } else { // input data must be block aligned. // 128 bit block size - HAL must send block aligned data @@ -2122,10 +2127,10 @@ private void processUpdateOperationCmd(APDU apdu) { } } // Allocate output buffer as input data is already block aligned - data[OUTPUT_DATA] = KMByteBlob.instance(tmpVariables[0]); + data[OUTPUT_DATA] = KMByteBlob.instance((short)(tmpVariables[0]+additionalExpOutLen)); // Otherwise just update the data. //HAL consumes all the input and maintains a buffered data inside it. So the - //applet inputConsumed as the input length. + //applet sends the inputConsumed length as same as the input length. tmpVariables[3] = tmpVariables[0]; try { tmpVariables[0] = @@ -2141,7 +2146,7 @@ private void processUpdateOperationCmd(APDU apdu) { } // Adjust the Output data if it is not equal to input data. // This happens in case of JCardSim provider. - if (tmpVariables[0] != KMByteBlob.cast(data[INPUT_DATA]).length()) { + if (tmpVariables[0] != KMByteBlob.cast(data[OUTPUT_DATA]).length()) { data[INPUT_DATA] = data[OUTPUT_DATA]; data[OUTPUT_DATA] = KMByteBlob.instance(tmpVariables[0]); Util.arrayCopy( diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMOperation.java b/Applet/Applet/src/com/android/javacard/keymaster/KMOperation.java index 88cda5b4..4011d7f5 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMOperation.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMOperation.java @@ -34,6 +34,4 @@ boolean verify(byte[] inputDataBuf, short inputDataStart, short inputDataLength, // include the auth tag which is appended at the end of the encrypted data. For decryption this will be // size of the decrypted data only. short getAESGCMOutputSize(short dataSize, short macLength); - - void release(); } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMOperationState.java b/Applet/Applet/src/com/android/javacard/keymaster/KMOperationState.java index 7934ef29..6647a6a8 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMOperationState.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMOperationState.java @@ -130,7 +130,7 @@ private void dataUpdated(){ public void release() { Object[] ops = ((Object[]) slot[REFS]); - ((KMOperation)ops[OPERATION]).release(); + ((KMOperation)ops[OPERATION]).abort(); JCSystem.beginTransaction(); Util.arrayFillNonAtomic( (byte[]) slot[0], (short) 0, (short) ((byte[]) slot[0]).length, (byte) 0); From 3e1b42dfacea39910a7e99fe888da19f56dd082a Mon Sep 17 00:00:00 2001 From: bvenkatswarlu Date: Mon, 19 Oct 2020 18:47:55 +0530 Subject: [PATCH 04/42] Added no digest ecdsa file --- .../KMEcdsa256NoDigestSignature.java | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java diff --git a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java new file mode 100644 index 00000000..c7455c83 --- /dev/null +++ b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java @@ -0,0 +1,113 @@ +package com.android.javacard.keymaster; + +import javacard.security.CryptoException; +import javacard.framework.Util; +import javacard.security.Key; +import javacard.security.MessageDigest; +import javacard.security.Signature; +import javacardx.crypto.Cipher; + +public class KMEcdsa256NoDigestSignature extends Signature { + + public static final byte ALG_ECDSA_NODIGEST = (byte) 0x67; + public static final short MAX_NO_DIGEST_MSG_LEN = 32; + private byte algorithm; + private Signature inst; + + public KMEcdsa256NoDigestSignature(byte alg) { + algorithm = alg; + inst = Signature.getInstance(Signature.ALG_ECDSA_SHA_256, false); + } + + @Override + public void init(Key key, byte b) throws CryptoException { + inst.init(key, b); + } + + @Override + public void init(Key key, byte b, byte[] bytes, short i, short i1) + throws CryptoException { + inst.init(key, b, bytes, i, i1); + } + + @Override + public void setInitialDigest(byte[] bytes, short i, short i1, byte[] bytes1, + short i2, short i3) throws CryptoException { + + } + + @Override + public byte getAlgorithm() { + return algorithm; + } + + @Override + public byte getMessageDigestAlgorithm() { + return MessageDigest.ALG_NULL; + } + + @Override + public byte getCipherAlgorithm() { + return 0; + } + + @Override + public byte getPaddingAlgorithm() { + return Cipher.PAD_NULL; + } + + @Override + public short getLength() throws CryptoException { + return inst.getLength(); + } + + @Override + public void update(byte[] message, short msgStart, short messageLength) + throws CryptoException { + // HAL accumulates the data and send it at finish operation. + } + + @Override + public short sign(byte[] bytes, short i, short i1, byte[] bytes1, short i2) + throws CryptoException { + if (i1 > MAX_NO_DIGEST_MSG_LEN) + CryptoException.throwIt(CryptoException.ILLEGAL_USE); + // add zeros to the left + if (i1 < MAX_NO_DIGEST_MSG_LEN) { + Util.arrayFillNonAtomic(KMJCOPSimProvider.getInstance().tmpArray, + (short) 0, (short) MAX_NO_DIGEST_MSG_LEN, (byte) 0); + } + Util.arrayCopyNonAtomic(bytes, i, KMJCOPSimProvider.getInstance().tmpArray, + (short) (MAX_NO_DIGEST_MSG_LEN-i1), i1); + return inst.signPreComputedHash(KMJCOPSimProvider.getInstance().tmpArray, + (short)0, (short)MAX_NO_DIGEST_MSG_LEN, bytes1, i2); + } + + @Override + public short signPreComputedHash(byte[] bytes, short i, short i1, + byte[] bytes1, short i2) throws CryptoException { + return inst.sign(bytes, i, i1, bytes1, i2); + } + + @Override + public boolean verify(byte[] bytes, short i, short i1, byte[] bytes1, + short i2, short i3) throws CryptoException { + if (i1 > MAX_NO_DIGEST_MSG_LEN) + CryptoException.throwIt(CryptoException.ILLEGAL_USE); + // add zeros to the left + if (i1 < MAX_NO_DIGEST_MSG_LEN) { + Util.arrayFillNonAtomic(KMJCOPSimProvider.getInstance().tmpArray, + (short) 0, (short) MAX_NO_DIGEST_MSG_LEN, (byte) 0); + } + Util.arrayCopyNonAtomic(bytes, i, KMJCOPSimProvider.getInstance().tmpArray, + (short) (MAX_NO_DIGEST_MSG_LEN-i1), i1); + return inst.verifyPreComputedHash(KMJCOPSimProvider.getInstance().tmpArray, + (short)0, (short)MAX_NO_DIGEST_MSG_LEN, bytes1, i2, i3); + } + + @Override + public boolean verifyPreComputedHash(byte[] bytes, short i, short i1, + byte[] bytes1, short i2, short i3) throws CryptoException { + return inst.verify(bytes, i, i1, bytes1, i2, i3); + } +} \ No newline at end of file From 021ddd0e466ad264c209173e8bf2338e24be3840 Mon Sep 17 00:00:00 2001 From: bvenkatswarlu Date: Tue, 20 Oct 2020 20:52:26 +0530 Subject: [PATCH 05/42] Removed commented code and indentation --- .../javacard/keymaster/KMJCOPSimProvider.java | 43 +++++++------------ 1 file changed, 16 insertions(+), 27 deletions(-) diff --git a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMJCOPSimProvider.java b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMJCOPSimProvider.java index 18cf2fae..d6d0da04 100644 --- a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMJCOPSimProvider.java +++ b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMJCOPSimProvider.java @@ -103,8 +103,7 @@ public class KMJCOPSimProvider implements KMSEProvider { public static final short AES_GCM_NONCE_LENGTH = 12; public static final byte KEYSIZE_128_OFFSET = 0x00; public static final byte KEYSIZE_256_OFFSET = 0x01; - public static final short TMP_ARRAY_SIZE = 256; // TODO - public static final short AUTH_DATA_LEN = 650; // TODO + public static final short TMP_ARRAY_SIZE = 256; public static final short MAX_RND_NUM_SIZE = 64; public static final short ENTROPY_POOL_SIZE = 16; public static final byte[] aesICV = { @@ -112,16 +111,20 @@ public class KMJCOPSimProvider implements KMSEProvider { final byte[] CIPHER_ALGS = { Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, - Cipher.ALG_AES_BLOCK_128_ECB_NOPAD, Cipher.ALG_DES_CBC_NOPAD, - Cipher.ALG_DES_ECB_NOPAD, Cipher.ALG_AES_CTR, Cipher.ALG_RSA_PKCS1,// NoDigest - Cipher.ALG_RSA_PKCS1_OAEP, // SHA256 - Cipher.ALG_RSA_NOPAD, // NoDigest - // AEADCipher.ALG_AES_CCM, + Cipher.ALG_AES_BLOCK_128_ECB_NOPAD, + Cipher.ALG_DES_CBC_NOPAD, + Cipher.ALG_DES_ECB_NOPAD, + Cipher.ALG_AES_CTR, + Cipher.ALG_RSA_PKCS1, + Cipher.ALG_RSA_PKCS1_OAEP, + Cipher.ALG_RSA_NOPAD, AEADCipher.ALG_AES_GCM }; + final byte[] SIG_ALGS = { - // Signature.ALG_AES_CMAC_128, - Signature.ALG_RSA_SHA_256_PKCS1, Signature.ALG_RSA_SHA_256_PKCS1_PSS, - Signature.ALG_ECDSA_SHA_256, Signature.ALG_HMAC_SHA_256, + Signature.ALG_RSA_SHA_256_PKCS1, + Signature.ALG_RSA_SHA_256_PKCS1_PSS, + Signature.ALG_ECDSA_SHA_256, + Signature.ALG_HMAC_SHA_256, KMRsa2048NoDigestSignature.ALG_RSA_SIGN_NOPAD, KMRsa2048NoDigestSignature.ALG_RSA_PKCS1_NODIGEST, KMEcdsa256NoDigestSignature.ALG_ECDSA_NODIGEST}; @@ -138,8 +141,6 @@ public class KMJCOPSimProvider implements KMSEProvider { private KeyPair ecKeyPair; // Temporary array. public byte[] tmpArray; - // public byte[] tmpAuthDataArray; - private short tmpArrayIndex; // This is used for internal encryption/decryption operations. private static AEADCipher aesGcmCipher; // Cipher pool @@ -198,8 +199,6 @@ private KMJCOPSimProvider() { // Temporary transient array created to use locally inside functions. tmpArray = JCSystem.makeTransientByteArray(TMP_ARRAY_SIZE, JCSystem.CLEAR_ON_DESELECT); - // tmpAuthDataArray = JCSystem.makeTransientByteArray(AUTH_DATA_LEN, - // JCSystem.CLEAR_ON_DESELECT); // Random number generator initialisation. rndNum = JCSystem.makeTransientByteArray(MAX_RND_NUM_SIZE, @@ -219,17 +218,8 @@ private KMJCOPSimProvider() { KeyBuilder.LENGTH_AES_128, false); } - public short alloc(short length) { - if (((short) (tmpArrayIndex + length)) > tmpArray.length) { - ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); - } - tmpArrayIndex += length; - return (short) (tmpArrayIndex - length); - } - public void clean() { - Util.arrayFillNonAtomic(tmpArray, (short) 0, tmpArrayIndex, (byte) 0); - tmpArrayIndex = 0; + Util.arrayFillNonAtomic(tmpArray, (short) 0, (short) 256, (byte) 0); } private void initECKey() { @@ -288,8 +278,7 @@ private void initializeSigPool() { while (index < SIG_ALGS.length) { sigPool[index] = new KMInstance(); ((KMInstance) sigPool[index]).instanceCount = 1; - ((KMInstance) sigPool[index]).object = getSignatureInstance(SIG_ALGS[index]);// Signature.getInstance(SIG_ALGS[index], - // false); + ((KMInstance) sigPool[index]).object = getSignatureInstance(SIG_ALGS[index]); ((KMInstance) sigPool[index]).reserved = 0; index++; } @@ -320,7 +309,6 @@ private byte getCipherAlgorithm(Cipher c) { if (Cipher.PAD_PKCS1_OAEP_SHA256 == c.getPaddingAlgorithm()) { return Cipher.ALG_RSA_PKCS1_OAEP; } else { - // TODO: What should we do here. KMException.throwIt(KMError.UNSUPPORTED_PADDING_MODE); return 0; } @@ -400,6 +388,7 @@ private Object getInstanceFromPool(Object[] pool, byte alg) { break; } else { // Cipher/Signature instance count reached its maximum limit. + KMException.throwIt(KMError.TOO_MANY_OPERATIONS); break; } } From 9c1771c25cb96f0619796328c2eb810968f68fe6 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Wed, 21 Oct 2020 15:10:42 +0100 Subject: [PATCH 06/42] 1. Removed native code for random number generation and used RandomData instead. 2. Fill tmpArray to zeros after use. 3. Code indentation, Remove unused code. --- .../KMEcdsa256NoDigestSignature.java | 55 +- .../javacard/keymaster/KMJCOPSimProvider.java | 640 +++++++----------- .../javacard/keymaster/KMOperationImpl.java | 143 ++-- .../keymaster/KMRsa2048NoDigestSignature.java | 94 ++- .../javacard/keymaster/KMOperationImpl.java | 7 - 5 files changed, 383 insertions(+), 556 deletions(-) diff --git a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java index c7455c83..56644b7f 100644 --- a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java +++ b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java @@ -69,18 +69,23 @@ public void update(byte[] message, short msgStart, short messageLength) @Override public short sign(byte[] bytes, short i, short i1, byte[] bytes1, short i2) - throws CryptoException { - if (i1 > MAX_NO_DIGEST_MSG_LEN) - CryptoException.throwIt(CryptoException.ILLEGAL_USE); - // add zeros to the left - if (i1 < MAX_NO_DIGEST_MSG_LEN) { - Util.arrayFillNonAtomic(KMJCOPSimProvider.getInstance().tmpArray, - (short) 0, (short) MAX_NO_DIGEST_MSG_LEN, (byte) 0); + throws CryptoException { + try { + if (i1 > MAX_NO_DIGEST_MSG_LEN) + CryptoException.throwIt(CryptoException.ILLEGAL_USE); + // add zeros to the left + if (i1 < MAX_NO_DIGEST_MSG_LEN) { + Util.arrayFillNonAtomic(KMJCOPSimProvider.getInstance().tmpArray, + (short) 0, (short) MAX_NO_DIGEST_MSG_LEN, (byte) 0); + } + Util.arrayCopyNonAtomic(bytes, i, + KMJCOPSimProvider.getInstance().tmpArray, + (short) (MAX_NO_DIGEST_MSG_LEN - i1), i1); + return inst.signPreComputedHash(KMJCOPSimProvider.getInstance().tmpArray, + (short) 0, (short) MAX_NO_DIGEST_MSG_LEN, bytes1, i2); + } finally { + KMJCOPSimProvider.getInstance().clean(); } - Util.arrayCopyNonAtomic(bytes, i, KMJCOPSimProvider.getInstance().tmpArray, - (short) (MAX_NO_DIGEST_MSG_LEN-i1), i1); - return inst.signPreComputedHash(KMJCOPSimProvider.getInstance().tmpArray, - (short)0, (short)MAX_NO_DIGEST_MSG_LEN, bytes1, i2); } @Override @@ -91,18 +96,24 @@ public short signPreComputedHash(byte[] bytes, short i, short i1, @Override public boolean verify(byte[] bytes, short i, short i1, byte[] bytes1, - short i2, short i3) throws CryptoException { - if (i1 > MAX_NO_DIGEST_MSG_LEN) - CryptoException.throwIt(CryptoException.ILLEGAL_USE); - // add zeros to the left - if (i1 < MAX_NO_DIGEST_MSG_LEN) { - Util.arrayFillNonAtomic(KMJCOPSimProvider.getInstance().tmpArray, - (short) 0, (short) MAX_NO_DIGEST_MSG_LEN, (byte) 0); + short i2, short i3) throws CryptoException { + try { + if (i1 > MAX_NO_DIGEST_MSG_LEN) + CryptoException.throwIt(CryptoException.ILLEGAL_USE); + // add zeros to the left + if (i1 < MAX_NO_DIGEST_MSG_LEN) { + Util.arrayFillNonAtomic(KMJCOPSimProvider.getInstance().tmpArray, + (short) 0, (short) MAX_NO_DIGEST_MSG_LEN, (byte) 0); + } + Util.arrayCopyNonAtomic(bytes, i, + KMJCOPSimProvider.getInstance().tmpArray, + (short) (MAX_NO_DIGEST_MSG_LEN - i1), i1); + return inst.verifyPreComputedHash( + KMJCOPSimProvider.getInstance().tmpArray, (short) 0, + (short) MAX_NO_DIGEST_MSG_LEN, bytes1, i2, i3); + } finally { + KMJCOPSimProvider.getInstance().clean(); } - Util.arrayCopyNonAtomic(bytes, i, KMJCOPSimProvider.getInstance().tmpArray, - (short) (MAX_NO_DIGEST_MSG_LEN-i1), i1); - return inst.verifyPreComputedHash(KMJCOPSimProvider.getInstance().tmpArray, - (short)0, (short)MAX_NO_DIGEST_MSG_LEN, bytes1, i2, i3); } @Override diff --git a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMJCOPSimProvider.java b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMJCOPSimProvider.java index d6d0da04..98775ab7 100644 --- a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMJCOPSimProvider.java +++ b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMJCOPSimProvider.java @@ -15,8 +15,6 @@ */ package com.android.javacard.keymaster; -import javacard.framework.ISO7816; -import javacard.framework.ISOException; import javacard.framework.JCSystem; import javacard.framework.Util; import javacard.security.AESKey; @@ -104,10 +102,6 @@ public class KMJCOPSimProvider implements KMSEProvider { public static final byte KEYSIZE_128_OFFSET = 0x00; public static final byte KEYSIZE_256_OFFSET = 0x01; public static final short TMP_ARRAY_SIZE = 256; - public static final short MAX_RND_NUM_SIZE = 64; - public static final short ENTROPY_POOL_SIZE = 16; - public static final byte[] aesICV = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; final byte[] CIPHER_ALGS = { Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, @@ -150,16 +144,12 @@ public class KMJCOPSimProvider implements KMSEProvider { // KMOperationImpl pool private Object[] operationPool; - private static Signature kdf; + private Signature kdf; - private static Signature hmacSignature; + private Signature hmacSignature; - // RNG - private static byte[] rngCounter; - private static AESKey aesRngKey; - private static Cipher aesRngCipher; - private static byte[] entropyPool; - private static byte[] rndNum; + // Entropy + private RandomData rng; private static KMJCOPSimProvider jcopProvider = null; @@ -173,13 +163,13 @@ private KMJCOPSimProvider() { // Re-usable AES,DES and HMAC keys in persisted memory. aesKeys = new AESKey[2]; aesKeys[KEYSIZE_128_OFFSET] = (AESKey) KeyBuilder.buildKey( - KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false); + KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false); aesKeys[KEYSIZE_256_OFFSET] = (AESKey) KeyBuilder.buildKey( - KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_256, false); + KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_256, false); triDesKey = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES, - KeyBuilder.LENGTH_DES3_3KEY, false); - hmacKey = (HMACKey) KeyBuilder.buildKey( - KeyBuilder.TYPE_HMAC, (short) 512, false); + KeyBuilder.LENGTH_DES3_3KEY, false); + hmacKey = (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC, (short) 512, + false); rsaKeyPair = new KeyPair(KeyPair.ALG_RSA, KeyBuilder.LENGTH_RSA_2048); initECKey(); @@ -198,24 +188,10 @@ private KMJCOPSimProvider() { // Temporary transient array created to use locally inside functions. tmpArray = JCSystem.makeTransientByteArray(TMP_ARRAY_SIZE, - JCSystem.CLEAR_ON_DESELECT); + JCSystem.CLEAR_ON_DESELECT); // Random number generator initialisation. - rndNum = JCSystem.makeTransientByteArray(MAX_RND_NUM_SIZE, - JCSystem.CLEAR_ON_RESET); - entropyPool = JCSystem.makeTransientByteArray(ENTROPY_POOL_SIZE, - JCSystem.CLEAR_ON_RESET); - rngCounter = JCSystem.makeTransientByteArray((short) 8, - JCSystem.CLEAR_ON_RESET); - initEntropyPool(entropyPool); - try { - aesRngCipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, - false); - } catch (CryptoException exp) { - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); - } - aesRngKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, - KeyBuilder.LENGTH_AES_128, false); + rng = RandomData.getInstance(RandomData.ALG_KEYGENERATION); } public void clean() { @@ -286,9 +262,9 @@ private void initializeSigPool() { private Signature getSignatureInstance(byte alg) { if (KMRsa2048NoDigestSignature.ALG_RSA_SIGN_NOPAD == alg - || KMRsa2048NoDigestSignature.ALG_RSA_PKCS1_NODIGEST == alg) { + || KMRsa2048NoDigestSignature.ALG_RSA_PKCS1_NODIGEST == alg) { return new KMRsa2048NoDigestSignature(alg); - } else if(KMEcdsa256NoDigestSignature.ALG_ECDSA_NODIGEST == alg) { + } else if (KMEcdsa256NoDigestSignature.ALG_ECDSA_NODIGEST == alg) { return new KMEcdsa256NoDigestSignature(alg); } else { return Signature.getInstance(alg, false); @@ -298,7 +274,7 @@ private Signature getSignatureInstance(byte alg) { private Cipher getCipherInstance(byte alg) { if (Cipher.ALG_RSA_PKCS1_OAEP == alg) { return Cipher.getInstance(Cipher.CIPHER_RSA, - Cipher.PAD_PKCS1_OAEP_SHA256, false); + Cipher.PAD_PKCS1_OAEP_SHA256, false); } else { return Cipher.getInstance(alg, false); } @@ -354,16 +330,13 @@ public void releaseCipherInstance(Cipher cipher) { } // This pool implementation can create a maximum of total 4 instances per - // algorithm. - // This function returns the unreserved Cipher/Signature instance of type - // algorithm from pool. If - // there is no unreserved cipher/signature instance of algorithm type in the - // pool and Cipher/Signature - // algorithm instance count is less than 4 then it creates and returns a new - // Cipher/Signature - // instance of algorithm type. If there is no unreserved cipher/signature and - // maximum instance - // count reaches four it throws exception. + // algorithm. This function returns the unreserved Cipher/Signature instance + // of type algorithm from pool. If there is no unreserved cipher/signature + // instance of algorithm type in the pool and Cipher/Signature algorithm + // instance count is less than 4 then it creates and returns a new + // Cipher/Signature instance of algorithm type. If there is no unreserved + // cipher/signature and maximum instance count reaches four it throws + // exception. private Object getInstanceFromPool(Object[] pool, byte alg) { short index = 0; short instanceCount = 0; @@ -378,11 +351,12 @@ private Object getInstanceFromPool(Object[] pool, byte alg) { pool[index] = new KMInstance(); JCSystem.beginTransaction(); ((KMInstance) pool[index]).instanceCount = (byte) (++instanceCount); - if (isCipher) + if (isCipher) { ((KMInstance) pool[index]).object = object = getCipherInstance(alg); - else + } else { // Signature ((KMInstance) pool[index]).object = object = getSignatureInstance(alg); + } ((KMInstance) pool[index]).reserved = 1; JCSystem.commitTransaction(); break; @@ -394,7 +368,7 @@ private Object getInstanceFromPool(Object[] pool, byte alg) { } object = ((KMInstance) pool[index]).object; if ((isCipher && (alg == getCipherAlgorithm((Cipher) object))) - || ((isSigner && (alg == ((Signature) object).getAlgorithm())))) { + || ((isSigner && (alg == ((Signature) object).getAlgorithm())))) { instanceCount = ((KMInstance) pool[index]).instanceCount; if (((KMInstance) pool[index]).reserved == 0) { JCSystem.beginTransaction(); @@ -439,8 +413,12 @@ private void releaseInstance(Object[] pool, Object object) { } public AESKey createAESKey(short keysize) { - newRandomNumber(tmpArray, (short) 0, (short) (keysize / 8)); - return createAESKey(tmpArray, (short) 0, (short) (keysize / 8)); + try { + newRandomNumber(tmpArray, (short) 0, (short) (keysize / 8)); + return createAESKey(tmpArray, (short) 0, (short) (keysize / 8)); + } finally { + clean(); + } } public AESKey createAESKey(byte[] buf, short startOff, short length) { @@ -457,14 +435,18 @@ public AESKey createAESKey(byte[] buf, short startOff, short length) { } public DESKey createTDESKey() { - newRandomNumber(tmpArray, (short) 0, - (short) (KeyBuilder.LENGTH_DES3_3KEY / 8)); - return createTDESKey(tmpArray, (short) 0, - (short) (KeyBuilder.LENGTH_DES3_3KEY / 8)); + try { + newRandomNumber(tmpArray, (short) 0, + (short) (KeyBuilder.LENGTH_DES3_3KEY / 8)); + return createTDESKey(tmpArray, (short) 0, + (short) (KeyBuilder.LENGTH_DES3_3KEY / 8)); + } finally { + clean(); + } } public DESKey createTDESKey(byte[] secretBuffer, short secretOff, - short secretLength) { + short secretLength) { triDesKey.setKey(secretBuffer, secretOff); return triDesKey; } @@ -473,12 +455,16 @@ public HMACKey createHMACKey(short keysize) { if ((keysize % 8 != 0) || !(keysize >= 64 && keysize <= 512)) { CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } - newRandomNumber(tmpArray, (short) 0, (short) (keysize / 8)); - return createHMACKey(tmpArray, (short) 0, (short) (keysize / 8)); + try { + newRandomNumber(tmpArray, (short) 0, (short) (keysize / 8)); + return createHMACKey(tmpArray, (short) 0, (short) (keysize / 8)); + } finally { + clean(); + } } public HMACKey createHMACKey(byte[] secretBuffer, short secretOff, - short secretLength) { + short secretLength) { hmacKey.setKey(secretBuffer, secretOff, secretLength); return hmacKey; } @@ -489,7 +475,7 @@ public KeyPair createRsaKeyPair() { } public RSAPrivateKey createRsaKey(byte[] modBuffer, short modOff, - short modLength, byte[] privBuffer, short privOff, short privLength) { + short modLength, byte[] privBuffer, short privOff, short privLength) { RSAPrivateKey privKey = (RSAPrivateKey) rsaKeyPair.getPrivate(); privKey.setExponent(privBuffer, privOff, privLength); privKey.setModulus(modBuffer, modOff, modLength); @@ -502,7 +488,7 @@ public KeyPair createECKeyPair() { } public ECPrivateKey createEcKey(byte[] privBuffer, short privOff, - short privLength) { + short privLength) { ECPrivateKey privKey = (ECPrivateKey) ecKeyPair.getPrivate(); privKey.setS(privBuffer, privOff, privLength); return privKey; @@ -510,7 +496,7 @@ public ECPrivateKey createEcKey(byte[] privBuffer, short privOff, @Override public short createSymmetricKey(byte alg, short keysize, byte[] buf, - short startOff) { + short startOff) { switch (alg) { case KMType.AES: AESKey aesKey = createAESKey(keysize); @@ -530,8 +516,8 @@ public short createSymmetricKey(byte alg, short keysize, byte[] buf, @Override public void createAsymmetricKey(byte alg, byte[] privKeyBuf, - short privKeyStart, short privKeyLength, byte[] pubModBuf, - short pubModStart, short pubModLength, short[] lengths) { + short privKeyStart, short privKeyLength, byte[] pubModBuf, + short pubModStart, short pubModLength, short[] lengths) { switch (alg) { case KMType.RSA: KeyPair rsaKey = createRsaKeyPair(); @@ -560,7 +546,7 @@ public void createAsymmetricKey(byte alg, byte[] privKeyBuf, @Override public boolean importSymmetricKey(byte alg, short keysize, byte[] buf, - short startOff, short length) { + short startOff, short length) { switch (alg) { case KMType.AES: createAESKey(buf, startOff, length); @@ -578,21 +564,14 @@ public boolean importSymmetricKey(byte alg, short keysize, byte[] buf, return true; } - /* - * @Override public boolean importAsymmetricKey(byte alg, byte[] buf, short - * start, short length, byte[] privKeyBuf, short privKeyStart, short - * privKeyLength, byte[] pubModBuf, short pubModStart, short pubModLength) { - * return false; } - */ - @Override public boolean importAsymmetricKey(byte alg, byte[] privKeyBuf, - short privKeyStart, short privKeyLength, byte[] pubModBuf, - short pubModStart, short pubModLength) { + short privKeyStart, short privKeyLength, byte[] pubModBuf, + short pubModStart, short pubModLength) { switch (alg) { case KMType.RSA: createRsaKey(pubModBuf, pubModStart, pubModLength, privKeyBuf, - privKeyStart, privKeyLength); + privKeyStart, privKeyLength); break; case KMType.EC: createEcKey(privKeyBuf, privKeyStart, privKeyLength); @@ -604,122 +583,27 @@ public boolean importAsymmetricKey(byte alg, byte[] privKeyBuf, return true; } - private void initEntropyPool(byte[] pool) { - byte index = 0; - RandomData trng; - while (index < rngCounter.length) { - rngCounter[index++] = 0; - } - try { - trng = RandomData.getInstance(RandomData.ALG_TRNG); - trng.nextBytes(pool, (short) 0, (short) pool.length); - } catch (CryptoException exp) { - if (exp.getReason() == CryptoException.NO_SUCH_ALGORITHM) { - // TODO change this when possible - // simulator does not support TRNG algorithm. So, PRNG algorithm - // (deprecated) is used. - trng = RandomData.getInstance(RandomData.ALG_PSEUDO_RANDOM); - trng.nextBytes(pool, (short) 0, (short) pool.length); - } else { - // TODO change this to proper error code - ISOException.throwIt(ISO7816.SW_UNKNOWN); - } - } + @Override + public void getTrueRandomNumber(byte[] buf, short start, short length) { + newRandomNumber(buf, start, length); } - // Generate a secure random number from existing entropy pool. This uses aes - // cbc algorithm with - // 8 byte rngCounter and 16 byte block size. @Override public void newRandomNumber(byte[] num, short startOff, short length) { - KMRepository repository = KMRepository.instance(); - byte[] bufPtr = repository.getHeap(); - short countBufInd = repository.alloc(KMKeymasterApplet.AES_BLOCK_SIZE); - short randBufInd = repository.alloc(KMKeymasterApplet.AES_BLOCK_SIZE); - short len = KMKeymasterApplet.AES_BLOCK_SIZE; - aesRngKey.setKey(entropyPool, (short) 0); - aesRngCipher.init(aesRngKey, Cipher.MODE_ENCRYPT, aesICV, (short) 0, - (short) 16); - while (length > 0) { - if (length < len) - len = length; - // increment rngCounter by one - incrementCounter(); - // copy the 8 byte rngCounter into the 16 byte rngCounter buffer. - Util.arrayCopy(rngCounter, (short) 0, bufPtr, countBufInd, - (short) rngCounter.length); - // encrypt the rngCounter buffer with existing entropy which forms the aes - // key. - aesRngCipher.doFinal(bufPtr, countBufInd, - KMKeymasterApplet.AES_BLOCK_SIZE, bufPtr, randBufInd); - // copy the encrypted rngCounter block to buffer passed in the argument - Util.arrayCopy(bufPtr, randBufInd, num, startOff, len); - length = (short) (length - len); - startOff = (short) (startOff + len); - } - } - - // increment 8 byte rngCounter by one - private void incrementCounter() { - // start with least significant byte - short index = (short) (rngCounter.length - 1); - while (index >= 0) { - // if the msb of current byte is set then it will be negative - if (rngCounter[index] < 0) { - // then increment the rngCounter - rngCounter[index]++; - // is the msb still set? i.e. no carry over - if (rngCounter[index] < 0) - break; // then break - else - index--; // else go to the higher order byte - } else { - // if msb is not set then increment the rngCounter - rngCounter[index]++; - break; - } - } + rng.nextBytes(num, startOff, length); } @Override public void addRngEntropy(byte[] num, short offset, short length) { - // Maximum length can be 256 bytes. But currently we support max 32 bytes - // seed. - // Get existing entropy pool. - if (length > 32) - length = 32; - // Create new temporary pool. - // Populate the new pool with the entropy which is derived from current - // entropy pool. - newRandomNumber(rndNum, (short) 0, (short) entropyPool.length); - // Copy the entropy to the current pool - updates the entropy pool. - Util.arrayCopy(rndNum, (short) 0, entropyPool, (short) 0, - (short) entropyPool.length); - short index = 0; - short randIndex = 0; - // XOR the seed received from the master in the entropy pool - 16 bytes - // (entPool.length). - // at a time. - while (index < length) { - entropyPool[randIndex] = (byte) (entropyPool[randIndex] ^ num[(short) (offset + index)]); - randIndex++; - index++; - if (randIndex >= entropyPool.length) { - randIndex = 0; - } - } + rng.setSeed(num, offset, length); } - /* - * @Override public byte[] getTrueRandomNumber(short len) { //TODO ignore the - * size as simulator only supports 128 bit entropy return entropyPool; } - */ @Override public short aesGCMEncrypt(byte[] aesKey, short aesKeyStart, short aesKeyLen, - byte[] secret, short secretStart, short secretLen, byte[] encSecret, - short encSecretStart, byte[] nonce, short nonceStart, short nonceLen, - byte[] authData, short authDataStart, short authDataLen, - byte[] authTag, short authTagStart, short authTagLen) { + byte[] secret, short secretStart, short secretLen, byte[] encSecret, + short encSecretStart, byte[] nonce, short nonceStart, short nonceLen, + byte[] authData, short authDataStart, short authDataLen, byte[] authTag, + short authTagStart, short authTagLen) { if (authTagLen != AES_GCM_TAG_LENGTH) { KMException.throwIt(KMError.UNKNOWN_ERROR); @@ -729,186 +613,153 @@ public short aesGCMEncrypt(byte[] aesKey, short aesKeyStart, short aesKeyLen, } if (aesGcmCipher == null) { aesGcmCipher = (AEADCipher) Cipher.getInstance(AEADCipher.ALG_AES_GCM, - false); + false); } AESKey key = createAESKey(aesKey, aesKeyStart, aesKeyLen); - try { - aesGcmCipher.init(key, Cipher.MODE_ENCRYPT, nonce, nonceStart, nonceLen); - } catch (CryptoException exp) { - KMException.throwIt(exp.getReason()); - } + aesGcmCipher.init(key, Cipher.MODE_ENCRYPT, nonce, nonceStart, nonceLen); aesGcmCipher.updateAAD(authData, authDataStart, authDataLen); short ciphLen = aesGcmCipher.doFinal(secret, secretStart, secretLen, - encSecret, encSecretStart); - // TODO if this retrieveTag fails, then allocate - // The tag buffer must be exact size otherwise simulator returns 0 tag. + encSecret, encSecretStart); aesGcmCipher.retrieveTag(authTag, authTagStart, authTagLen); return ciphLen; } @Override public boolean aesGCMDecrypt(byte[] aesKey, short aesKeyStart, - short aesKeyLen, byte[] encSecret, short encSecretStart, - short encSecretLen, byte[] secret, short secretStart, byte[] nonce, - short nonceStart, short nonceLen, byte[] authData, - short authDataStart, short authDataLen, byte[] authTag, - short authTagStart, short authTagLen) { - // TODO Test and remove unnecessary trasientArrays. + short aesKeyLen, byte[] encSecret, short encSecretStart, + short encSecretLen, byte[] secret, short secretStart, byte[] nonce, + short nonceStart, short nonceLen, byte[] authData, short authDataStart, + short authDataLen, byte[] authTag, short authTagStart, short authTagLen) { if (aesGcmCipher == null) { aesGcmCipher = (AEADCipher) Cipher.getInstance(AEADCipher.ALG_AES_GCM, - false); + false); } - // allocate aad buffer of exact size - otherwise simulator throws exception - // byte[] aad = JCSystem.makeTransientByteArray(authDataLen, - // JCSystem.CLEAR_ON_RESET); - - // Util.arrayCopyNonAtomic(authData, authDataStart, tmpAuthDataArray, - // (short) 0, - // authDataLen); - // allocate tag of exact size. - // byte[] tag = JCSystem.makeTransientByteArray(AES_GCM_TAG_LENGTH, - // JCSystem.CLEAR_ON_RESET); - // Util.arrayCopyNonAtomic(authTag, authTagStart, tmpArray, (short) 0, - // authTagLen); boolean verification = false; AESKey key = createAESKey(aesKey, aesKeyStart, aesKeyLen); - try { - aesGcmCipher.init(key, Cipher.MODE_DECRYPT, nonce, nonceStart, nonceLen); - aesGcmCipher.updateAAD(authData, authDataStart, authDataLen); - // byte[] plain = JCSystem.makeTransientByteArray(encSecretLen, - // JCSystem.CLEAR_ON_RESET); - // encrypt the secret - aesGcmCipher.doFinal(encSecret, encSecretStart, encSecretLen, secret, - secretStart); - verification = aesGcmCipher.verifyTag(authTag, authTagStart, (short) 12, - (short) 12); - } catch (CryptoException exp) { - KMException.throwIt(KMError.UNKNOWN_ERROR); - } + aesGcmCipher.init(key, Cipher.MODE_DECRYPT, nonce, nonceStart, nonceLen); + aesGcmCipher.updateAAD(authData, authDataStart, authDataLen); + // encrypt the secret + aesGcmCipher.doFinal(encSecret, encSecretStart, encSecretLen, secret, + secretStart); + verification = aesGcmCipher.verifyTag(authTag, authTagStart, (short) 12, + (short) 12); return verification; } public HMACKey cmacKdf(byte[] keyMaterial, short keyMaterialStart, - short keyMaterialLen, byte[] label, short labelStart, short labelLen, - byte[] context, short contextStart, short contextLength) { - // This is hardcoded to requirement - 32 byte output with two concatenated - // 16 bytes K1 and K2. - final byte n = 2; // hardcoded - final byte[] L = { - 0, 0, 1, 0 }; // [L] 256 bits - hardcoded 32 bits as per - // reference impl in keymaster. - final byte[] zero = { - 0 }; // byte - short iBufLen = 4; - short keyOutLen = n * 16; - // [i] counter - 32 bits - Util.arrayFillNonAtomic(tmpArray, (short) 0, iBufLen, (byte) 0); - // byte[] iBuf = new byte[] { 0, 0, 0, 0 }; // [i] counter - 32 bits - // byte[] keyOut = new byte[(short) (n * 16)]; - Util.arrayFillNonAtomic(tmpArray, (short) iBufLen, keyOutLen, (byte) 0); - // Signature prf = Signature.getInstance(Signature.ALG_AES_CMAC_128, false); - aesKeys[KEYSIZE_256_OFFSET].setKey(keyMaterial, (short) keyMaterialStart); - // AESKey key = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, - // KeyBuilder.LENGTH_AES_256, false); - // key.setKey(keyMaterial, (short) 0); - kdf.init(aesKeys[KEYSIZE_256_OFFSET], Signature.MODE_SIGN); - byte i = 1; - short pos = 0; - while (i <= n) { - tmpArray[3] = i; - kdf.update(tmpArray, (short) 0, (short) iBufLen); // 4 bytes of iBuf with - // counter in - // it - kdf.update(label, labelStart, (short) labelLen); // label - kdf.update(zero, (short) 0, (short) 1); // 1 byte of 0x00 - kdf.update(context, contextStart, contextLength); // context - pos = kdf - .sign(L, (short) 0, (short) 4, tmpArray, (short) (iBufLen + pos)); // 4 - // bytes - // of - // L - // - - // signature of 16 - // bytes - i++; + short keyMaterialLen, byte[] label, short labelStart, short labelLen, + byte[] context, short contextStart, short contextLength) { + try { + // This is hardcoded to requirement - 32 byte output with two concatenated + // 16 bytes K1 and K2. + final byte n = 2; // hardcoded + // [L] 256 bits - hardcoded 32 bits as per + // reference impl in keymaster. + final byte[] L = { + 0, 0, 1, 0 + }; + // byte + final byte[] zero = { + 0 + }; + // [i] counter - 32 bits + short iBufLen = 4; + short keyOutLen = n * 16; + Util.arrayFillNonAtomic(tmpArray, (short) 0, iBufLen, (byte) 0); + Util.arrayFillNonAtomic(tmpArray, (short) iBufLen, keyOutLen, (byte) 0); + aesKeys[KEYSIZE_256_OFFSET].setKey(keyMaterial, (short) keyMaterialStart); + kdf.init(aesKeys[KEYSIZE_256_OFFSET], Signature.MODE_SIGN); + byte i = 1; + short pos = 0; + while (i <= n) { + tmpArray[3] = i; + // 4 bytes of iBuf with counter in it + kdf.update(tmpArray, (short) 0, (short) iBufLen); + kdf.update(label, labelStart, (short) labelLen); // label + kdf.update(zero, (short) 0, (short) 1); // 1 byte of 0x00 + kdf.update(context, contextStart, contextLength); // context + // 4 bytes of L - signature of 16 bytes + pos = kdf.sign(L, (short) 0, (short) 4, tmpArray, + (short) (iBufLen + pos)); + i++; + } + return createHMACKey(tmpArray, (short) iBufLen, (short) keyOutLen); + } finally { + clean(); } - return createHMACKey(tmpArray, (short) iBufLen, (short) keyOutLen); } public short hmacSign(HMACKey key, byte[] data, short dataStart, - short dataLength, byte[] mac, short macStart) { + short dataLength, byte[] mac, short macStart) { hmacSignature.init(key, Signature.MODE_SIGN); return hmacSignature.sign(data, dataStart, dataLength, mac, macStart); } public boolean hmacVerify(HMACKey key, byte[] data, short dataStart, - short dataLength, byte[] mac, short macStart, short macLength) { + short dataLength, byte[] mac, short macStart, short macLength) { hmacSignature.init(key, Signature.MODE_VERIFY); return hmacSignature.verify(data, dataStart, dataLength, mac, macStart, - macLength); + macLength); } @Override public short hmacSign(byte[] keyBuf, short keyStart, short keyLength, - byte[] data, short dataStart, short dataLength, byte[] mac, - short macStart) { + byte[] data, short dataStart, short dataLength, byte[] mac, short macStart) { HMACKey key = createHMACKey(keyBuf, keyStart, keyLength); return hmacSign(key, data, dataStart, dataLength, mac, macStart); } @Override public boolean hmacVerify(byte[] keyBuf, short keyStart, short keyLength, - byte[] data, short dataStart, short dataLength, byte[] mac, - short macStart, short macLength) { + byte[] data, short dataStart, short dataLength, byte[] mac, + short macStart, short macLength) { HMACKey key = createHMACKey(keyBuf, keyStart, keyLength); return hmacVerify(key, data, dataStart, dataLength, mac, macStart, - macLength); + macLength); } @Override public short rsaDecipherOAEP256(byte[] secret, short secretStart, - short secretLength, byte[] modBuffer, short modOff, short modLength, - byte[] inputDataBuf, short inputDataStart, short inputDataLength, - byte[] outputDataBuf, short outputDataStart) { + short secretLength, byte[] modBuffer, short modOff, short modLength, + byte[] inputDataBuf, short inputDataStart, short inputDataLength, + byte[] outputDataBuf, short outputDataStart) { Cipher.OneShot cipher = null; - RSAPrivateKey key = (RSAPrivateKey) rsaKeyPair.getPrivate(); - key.setExponent(secret, secretStart, secretLength); - key.setModulus(modBuffer, modOff, modLength); try { + RSAPrivateKey key = (RSAPrivateKey) rsaKeyPair.getPrivate(); + key.setExponent(secret, secretStart, secretLength); + key.setModulus(modBuffer, modOff, modLength); + cipher = Cipher.OneShot.open(Cipher.CIPHER_RSA, - Cipher.PAD_PKCS1_OAEP_SHA256); + Cipher.PAD_PKCS1_OAEP_SHA256); cipher.init(key, Cipher.MODE_DECRYPT); return cipher.doFinal(inputDataBuf, inputDataStart, inputDataLength, - outputDataBuf, (short) outputDataStart); + outputDataBuf, (short) outputDataStart); - } catch (SecurityException e) { - KMException.throwIt(KMError.SECURE_HW_ACCESS_DENIED); - } catch (CryptoException e) { - KMException.throwIt(e.getReason()); } finally { if (cipher != null) cipher.close(); } - return 0; } @Override public short rsaSignPKCS1256(byte[] secret, short secretStart, - short secretLength, byte[] modBuffer, short modOff, short modLength, - byte[] inputDataBuf, short inputDataStart, short inputDataLength, - byte[] outputDataBuf, short outputDataStart) { + short secretLength, byte[] modBuffer, short modOff, short modLength, + byte[] inputDataBuf, short inputDataStart, short inputDataLength, + byte[] outputDataBuf, short outputDataStart) { Signature.OneShot signer = null; - RSAPrivateKey key = (RSAPrivateKey) rsaKeyPair.getPrivate(); - key.setExponent(secret, secretStart, secretLength); - key.setModulus(modBuffer, modOff, modLength); try { + RSAPrivateKey key = (RSAPrivateKey) rsaKeyPair.getPrivate(); + key.setExponent(secret, secretStart, secretLength); + key.setModulus(modBuffer, modOff, modLength); + signer = Signature.OneShot.open(MessageDigest.ALG_SHA_256, - Signature.SIG_CIPHER_RSA, Cipher.PAD_PKCS1); + Signature.SIG_CIPHER_RSA, Cipher.PAD_PKCS1); signer.init(key, Signature.MODE_SIGN); return signer.sign(inputDataBuf, inputDataStart, inputDataLength, - outputDataBuf, outputDataStart); + outputDataBuf, outputDataStart); } finally { - signer.close(); + if (signer != null) + signer.close(); } } @@ -990,22 +841,22 @@ private byte mapCipherAlg(byte alg, byte padding, byte blockmode) { } public Cipher createSymmetricCipher(short alg, short purpose, - short blockMode, short padding, byte[] secret, short secretStart, - short secretLength, byte[] ivBuffer, short ivStart, short ivLength) { + short blockMode, short padding, byte[] secret, short secretStart, + short secretLength, byte[] ivBuffer, short ivStart, short ivLength) { Key key = null; Cipher symmCipher = null; switch (secretLength) { case 32: key = aesKeys[KEYSIZE_256_OFFSET]; - ((AESKey) key).setKey(secret,secretStart); + ((AESKey) key).setKey(secret, secretStart); break; case 16: key = aesKeys[KEYSIZE_128_OFFSET]; - ((AESKey) key).setKey(secret,secretStart); + ((AESKey) key).setKey(secret, secretStart); break; case 24: key = triDesKey; - ((DESKey) key).setKey(secret,secretStart); + ((DESKey) key).setKey(secret, secretStart); break; default: CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); @@ -1023,14 +874,13 @@ public Cipher createSymmetricCipher(short alg, short purpose, symmCipher.init(key, mapPurpose(purpose)); break; case Cipher.ALG_DES_CBC_NOPAD: - // TODO Consume only 8 bytes of iv. the random number for iv is of 16 - // bytes. - // While sending back the iv send only 8 bytes. + // Consume only 8 bytes of iv. the random number for iv is of 16 bytes. + // While sending back the iv, send only 8 bytes. symmCipher.init(key, mapPurpose(purpose), ivBuffer, ivStart, (short) 8); break; case AEADCipher.ALG_AES_GCM: ((AEADCipher) symmCipher).init(key, mapPurpose(purpose), ivBuffer, - ivStart, ivLength); + ivStart, ivLength); break; default:// This should never happen CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); @@ -1040,7 +890,7 @@ public Cipher createSymmetricCipher(short alg, short purpose, } public Signature createHmacSignerVerifier(short purpose, short digest, - byte[] secret, short secretStart, short secretLength) { + byte[] secret, short secretStart, short secretLength) { byte alg = Signature.ALG_HMAC_SHA_256; if (digest != KMType.SHA2_256) CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); @@ -1052,15 +902,15 @@ public Signature createHmacSignerVerifier(short purpose, short digest, @Override public KMOperation initSymmetricOperation(byte purpose, byte alg, - byte digest, byte padding, byte blockMode, byte[] keyBuf, - short keyStart, short keyLength, byte[] ivBuf, short ivStart, - short ivLength, short macLength) { + byte digest, byte padding, byte blockMode, byte[] keyBuf, short keyStart, + short keyLength, byte[] ivBuf, short ivStart, short ivLength, + short macLength) { KMOperationImpl opr = null; switch (alg) { case KMType.AES: case KMType.DES: Cipher cipher = createSymmetricCipher(alg, purpose, blockMode, padding, - keyBuf, keyStart, keyLength, ivBuf, ivStart, ivLength); + keyBuf, keyStart, keyLength, ivBuf, ivStart, ivLength); opr = getOperationInstanceFromPool(); // Convert macLength to bytes macLength = (short) (macLength / 8); @@ -1075,7 +925,7 @@ public KMOperation initSymmetricOperation(byte purpose, byte alg, break; case KMType.HMAC: Signature signerVerifier = createHmacSignerVerifier(purpose, digest, - keyBuf, keyStart, keyLength); + keyBuf, keyStart, keyLength); opr = getOperationInstanceFromPool(); JCSystem.beginTransaction(); opr.setSignature(signerVerifier); @@ -1089,14 +939,12 @@ public KMOperation initSymmetricOperation(byte purpose, byte alg, } public Signature createRsaSigner(short digest, short padding, byte[] secret, - short secretStart, short secretLength, byte[] modBuffer, - short modOff, short modLength) { + short secretStart, short secretLength, byte[] modBuffer, short modOff, + short modLength) { byte alg = mapSignature256Alg(KMType.RSA, (byte) padding, (byte) digest); byte opMode; if (padding == KMType.PADDING_NONE - || (padding == KMType.RSA_PKCS1_1_5_SIGN && digest == KMType.DIGEST_NONE)) { - // return createNoDigestSigner(padding,secret, secretStart, secretLength, - // modBuffer, modOff, modLength); + || (padding == KMType.RSA_PKCS1_1_5_SIGN && digest == KMType.DIGEST_NONE)) { opMode = Cipher.MODE_DECRYPT; } else { opMode = Signature.MODE_SIGN; @@ -1110,67 +958,60 @@ public Signature createRsaSigner(short digest, short padding, byte[] secret, } public Signature createRsaVerifier(short digest, short padding, - byte[] modBuffer, short modOff, short modLength) { - byte alg = mapSignature256Alg(KMType.RSA, (byte) padding, (byte) digest); - if (digest == KMType.DIGEST_NONE || padding == KMType.PADDING_NONE) - CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - - Signature rsaVerifier = getSignatureInstanceFromPool(alg); - RSAPublicKey key = (RSAPublicKey) rsaKeyPair.getPublic(); - // setExponent - Util.setShort(tmpArray, (short) 0, (short) 0x0001); - Util.setShort(tmpArray, (short) 2, (short) 0x0001); - // byte[] exponent = new byte[] { 0x01, 0x00, 0x01 }; - key.setExponent(tmpArray, (short) 0, (short) 4); - key.setModulus(modBuffer, modOff, modLength); - rsaVerifier.init(key, Signature.MODE_VERIFY); - return rsaVerifier; - } - - // TODO Remove commented code. - /* - * private Signature createNoDigestSigner(short padding, byte[] secret, short - * secretStart, short secretLength, byte[] modBuffer, short modOff, short - * modLength) { Cipher rsaCipher = - * getCipherInstanceFromPool(Cipher.ALG_RSA_NOPAD - * );//Cipher.getInstance(Cipher.ALG_RSA_NOPAD,false); RSAPrivateKey key = - * (RSAPrivateKey) KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PRIVATE, - * KeyBuilder.LENGTH_RSA_2048, false); - * key.setExponent(secret,secretStart,secretLength); key.setModulus(modBuffer, - * modOff, modLength); rsaCipher.init(key,Cipher.MODE_DECRYPT); - * KMRsa2048NoDigestSignature inst = new - * KMRsa2048NoDigestSignature(rsaCipher,(byte)padding, - * modBuffer,modOff,modLength); return inst; } - */ + byte[] modBuffer, short modOff, short modLength) { + try { + byte alg = mapSignature256Alg(KMType.RSA, (byte) padding, (byte) digest); + if (digest == KMType.DIGEST_NONE || padding == KMType.PADDING_NONE) + CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); + + Signature rsaVerifier = getSignatureInstanceFromPool(alg); + RSAPublicKey key = (RSAPublicKey) rsaKeyPair.getPublic(); + // setExponent + Util.setShort(tmpArray, (short) 0, (short) 0x0001); + Util.setShort(tmpArray, (short) 2, (short) 0x0001); + key.setExponent(tmpArray, (short) 0, (short) 4); + key.setModulus(modBuffer, modOff, modLength); + rsaVerifier.init(key, Signature.MODE_VERIFY); + return rsaVerifier; + } finally { + clean(); + } + } public Cipher createRsaCipher(short padding, short digest, byte[] modBuffer, - short modOff, short modLength) { - byte cipherAlg = mapCipherAlg(KMType.RSA, (byte) padding, (byte) 0); - // TODO: Implement from NXP. - /* - * if (cipherAlg == Cipher.ALG_RSA_PKCS1_OAEP) { //TODO: Implement from NXP. - * KMException.throwIt(KMError.UNIMPLEMENTED); } - */ - Cipher rsaCipher = getCipherInstanceFromPool(cipherAlg); - RSAPublicKey key = (RSAPublicKey) rsaKeyPair.getPublic(); - // setExponent - Util.setShort(tmpArray, (short) 0, (short) 0x0001); - Util.setShort(tmpArray, (short) 2, (short) 0x0001); - // byte[] exponent = new byte[] { 0x01, 0x00, 0x01 }; - key.setExponent(tmpArray, (short) 0, (short) 4); - key.setModulus(modBuffer, modOff, modLength); - rsaCipher.init(key, Cipher.MODE_ENCRYPT); - return rsaCipher; + short modOff, short modLength) { + try { + byte cipherAlg = mapCipherAlg(KMType.RSA, (byte) padding, (byte) 0); + // TODO Java Card does not support MGF1-SHA1 and digest as SHA256. + // Both digest should be SHA256 as per Java Card, but as per Keymaster + // MGF should use SHA1 and message digest should be SHA256. + if (cipherAlg == Cipher.ALG_RSA_PKCS1_OAEP) { + KMException.throwIt(KMError.UNIMPLEMENTED); + } + Cipher rsaCipher = getCipherInstanceFromPool(cipherAlg); + RSAPublicKey key = (RSAPublicKey) rsaKeyPair.getPublic(); + // setExponent + Util.setShort(tmpArray, (short) 0, (short) 0x0001); + Util.setShort(tmpArray, (short) 2, (short) 0x0001); + key.setExponent(tmpArray, (short) 0, (short) 4); + key.setModulus(modBuffer, modOff, modLength); + rsaCipher.init(key, Cipher.MODE_ENCRYPT); + return rsaCipher; + } finally { + clean(); + } } public Cipher createRsaDecipher(short padding, short digest, byte[] secret, - short secretStart, short secretLength, byte[] modBuffer, - short modOff, short modLength) { + short secretStart, short secretLength, byte[] modBuffer, short modOff, + short modLength) { byte cipherAlg = mapCipherAlg(KMType.RSA, (byte) padding, (byte) 0); - /* - * if (cipherAlg == Cipher.ALG_RSA_PKCS1_OAEP) { //TODO: Implement from NXP. - * KMException.throwIt(KMError.UNIMPLEMENTED); } - */ + // TODO Java Card does not support MGF1-SHA1 and digest as SHA256. + // Both digest should be SHA256 as per Java Card, but as per Keymaster + // MGF should use SHA1 and message digest should be SHA256. + if (cipherAlg == Cipher.ALG_RSA_PKCS1_OAEP) { + KMException.throwIt(KMError.UNIMPLEMENTED); + } Cipher rsaCipher = getCipherInstanceFromPool(cipherAlg); RSAPrivateKey key = (RSAPrivateKey) rsaKeyPair.getPrivate(); key.setExponent(secret, secretStart, secretLength); @@ -1180,7 +1021,7 @@ public Cipher createRsaDecipher(short padding, short digest, byte[] secret, } public Signature createEcSigner(short digest, byte[] secret, - short secretStart, short secretLength) { + short secretStart, short secretLength) { byte alg = mapSignature256Alg(KMType.EC, (byte) 0, (byte) digest); Signature ecSigner = null; ECPrivateKey key = (ECPrivateKey) ecKeyPair.getPrivate(); @@ -1191,35 +1032,27 @@ public Signature createEcSigner(short digest, byte[] secret, } public Signature createEcVerifier(short digest, byte[] pubKey, - short pubKeyStart, short pubKeyLength) { + short pubKeyStart, short pubKeyLength) { byte alg = mapSignature256Alg(KMType.EC, (byte) 0, (byte) digest); Signature ecVerifier = null; - // if(msgDigestAlg == MessageDigest.ALG_NULL) - // CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - if (digest == KMType.DIGEST_NONE) { - // TODO: Implement from NXP. - KMException.throwIt(KMError.UNIMPLEMENTED); - } else { - ECPublicKey key = (ECPublicKey) ecKeyPair.getPublic(); - key.setW(pubKey, pubKeyStart, pubKeyLength); - ecVerifier = getSignatureInstanceFromPool(alg); - ecVerifier.init(key, Signature.MODE_VERIFY); - } + ECPublicKey key = (ECPublicKey) ecKeyPair.getPublic(); + key.setW(pubKey, pubKeyStart, pubKeyLength); + ecVerifier = getSignatureInstanceFromPool(alg); + ecVerifier.init(key, Signature.MODE_VERIFY); return ecVerifier; } @Override public KMOperation initAsymmetricOperation(byte purpose, byte alg, - byte padding, byte digest, byte[] privKeyBuf, short privKeyStart, - short privKeyLength, byte[] pubModBuf, short pubModStart, - short pubModLength) { + byte padding, byte digest, byte[] privKeyBuf, short privKeyStart, + short privKeyLength, byte[] pubModBuf, short pubModStart, + short pubModLength) { KMOperationImpl opr = null; if (alg == KMType.RSA) { switch (purpose) { case KMType.SIGN: Signature signer = createRsaSigner(digest, padding, privKeyBuf, - privKeyStart, privKeyLength, pubModBuf, pubModStart, - pubModLength); + privKeyStart, privKeyLength, pubModBuf, pubModStart, pubModLength); opr = getOperationInstanceFromPool(); JCSystem.beginTransaction(); opr.setSignature(signer); @@ -1230,7 +1063,7 @@ public KMOperation initAsymmetricOperation(byte purpose, byte alg, break; case KMType.VERIFY: Signature verifier = createRsaVerifier(digest, padding, pubModBuf, - pubModStart, pubModLength); + pubModStart, pubModLength); opr = getOperationInstanceFromPool(); JCSystem.beginTransaction(); opr.setSignature(verifier); @@ -1241,7 +1074,7 @@ public KMOperation initAsymmetricOperation(byte purpose, byte alg, break; case KMType.ENCRYPT: Cipher cipher = createRsaCipher(padding, digest, pubModBuf, - pubModStart, pubModLength); + pubModStart, pubModLength); opr = getOperationInstanceFromPool(); JCSystem.beginTransaction(); opr.setCipher(cipher); @@ -1252,8 +1085,7 @@ public KMOperation initAsymmetricOperation(byte purpose, byte alg, break; case KMType.DECRYPT: Cipher decipher = createRsaDecipher(padding, digest, privKeyBuf, - privKeyStart, privKeyLength, pubModBuf, pubModStart, - pubModLength); + privKeyStart, privKeyLength, pubModBuf, pubModStart, pubModLength); opr = getOperationInstanceFromPool(); JCSystem.beginTransaction(); opr.setCipher(decipher); @@ -1269,7 +1101,7 @@ public KMOperation initAsymmetricOperation(byte purpose, byte alg, switch (purpose) { case KMType.SIGN: Signature signer = createEcSigner(digest, privKeyBuf, privKeyStart, - privKeyLength); + privKeyLength); opr = getOperationInstanceFromPool(); JCSystem.beginTransaction(); opr.setSignature(signer); @@ -1277,7 +1109,7 @@ public KMOperation initAsymmetricOperation(byte purpose, byte alg, break; case KMType.VERIFY: Signature verifier = createEcVerifier(digest, pubModBuf, pubModStart, - pubModLength); + pubModLength); opr = getOperationInstanceFromPool(); JCSystem.beginTransaction(); opr.setSignature(verifier); @@ -1298,8 +1130,8 @@ public KMAttestationCert getAttestationCert(boolean rsaCert) { @Override public short aesCCMSign(byte[] bufIn, short bufInStart, short buffInLength, - byte[] masterKeySecret, short masterKeyStart, short masterKeyLen, - byte[] bufOut, short bufStart) { + byte[] masterKeySecret, short masterKeyStart, short masterKeyLen, + byte[] bufOut, short bufStart) { if (masterKeyLen > 16) { return -1; } @@ -1310,34 +1142,26 @@ public short aesCCMSign(byte[] bufIn, short bufInStart, short buffInLength, @Override public boolean isBackupRestoreSupported() { - // TODO Auto-generated method stub return false; } @Override public void backup(byte[] buf, short start, short len) { - // TODO Auto-generated method stub } @Override public short restore(byte[] buf, short start) { - // TODO Auto-generated method stub return 0; } - @Override - public void getTrueRandomNumber(byte[] buf, short start, short length) { - Util.arrayCopy(entropyPool, (short) 0, buf, start, length); - } - @Override public short cmacKdf(byte[] keyMaterial, short keyMaterialStart, - short keyMaterialLen, byte[] label, short labelStart, short labelLen, - byte[] context, short contextStart, short contextLength, - byte[] keyBuf, short keyStart) { + short keyMaterialLen, byte[] label, short labelStart, short labelLen, + byte[] context, short contextStart, short contextLength, byte[] keyBuf, + short keyStart) { HMACKey key = cmacKdf(keyMaterial, keyMaterialStart, keyMaterialLen, label, - labelStart, labelLen, context, contextStart, contextLength); + labelStart, labelLen, context, contextStart, contextLength); return key.getKey(keyBuf, keyStart); } diff --git a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMOperationImpl.java b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMOperationImpl.java index 6429cff2..1183c6eb 100644 --- a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMOperationImpl.java +++ b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMOperationImpl.java @@ -7,6 +7,7 @@ import javacardx.crypto.Cipher; public class KMOperationImpl implements KMOperation { + private Cipher cipher; private Signature signature; private short cipherAlg; @@ -14,9 +15,11 @@ public class KMOperationImpl implements KMOperation { private short mode; private short blockMode; private short macLength; + //This will hold the length of the buffer stored inside the + //Java Card after the GCM update operation. private short aesGcmUpdatedLen; - public KMOperationImpl() { + public KMOperationImpl() { } public short getMode() { @@ -43,14 +46,14 @@ public void setPaddingAlgorithm(short alg) { padding = alg; } - public void setBlockMode(short mode){ - blockMode = mode; + public void setBlockMode(short mode) { + blockMode = mode; } - public short getBlockMode(){ + public short getBlockMode() { return blockMode; } - + public short getCipherAlgorithm() { return cipherAlg; } @@ -59,7 +62,6 @@ public void setCipherAlgorithm(short cipherAlg) { this.cipherAlg = cipherAlg; } - public void setCipher(Cipher cipher) { this.cipher = cipher; } @@ -80,99 +82,100 @@ private void resetCipher() { } @Override - public short update(byte[] inputDataBuf, short inputDataStart, short inputDataLength, - byte[] outputDataBuf, short outputDataStart) { - short len = cipher.update(inputDataBuf,inputDataStart,inputDataLength,outputDataBuf,outputDataStart); - if(cipherAlg == KMType.AES && blockMode == KMType.GCM) { - //Every time Block size data is stored as intermediate result. - aesGcmUpdatedLen += (short)(inputDataLength - len); + public short update(byte[] inputDataBuf, short inputDataStart, + short inputDataLength, byte[] outputDataBuf, short outputDataStart) { + short len = cipher.update(inputDataBuf, inputDataStart, inputDataLength, + outputDataBuf, outputDataStart); + if (cipherAlg == KMType.AES && blockMode == KMType.GCM) { + // Every time Block size data is stored as intermediate result. + aesGcmUpdatedLen += (short) (inputDataLength - len); } return len; } @Override - public short update(byte[] inputDataBuf, short inputDataStart, short inputDataLength) { - signature.update(inputDataBuf,inputDataStart,inputDataLength); + public short update(byte[] inputDataBuf, short inputDataStart, + short inputDataLength) { + signature.update(inputDataBuf, inputDataStart, inputDataLength); return 0; } @Override - public short finish(byte[] inputDataBuf, short inputDataStart, + public short finish(byte[] inputDataBuf, short inputDataStart, short inputDataLen, byte[] outputDataBuf, short outputDataStart) { byte[] tmpArray = KMJCOPSimProvider.getInstance().tmpArray; - //byte[] tmpArray = JCSystem.makeTransientByteArray((short)256, JCSystem.CLEAR_ON_DESELECT); short len = 0; try { - if(cipherAlg == KMType.AES && blockMode == KMType.GCM) { - if(mode == KMType.DECRYPT) { - inputDataLen = (short)(inputDataLen - macLength); + if (cipherAlg == KMType.AES && blockMode == KMType.GCM) { + if (mode == KMType.DECRYPT) { + inputDataLen = (short) (inputDataLen - macLength); } - } else if(cipherAlg == KMType.RSA && padding == KMType.PADDING_NONE && mode == KMType.ENCRYPT ){ - // Length cannot be greater then key size according to JcardSim - if(inputDataLen > 256) KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + } else if (cipherAlg == KMType.RSA && padding == KMType.PADDING_NONE && + mode == KMType.ENCRYPT) { + // Length cannot be greater then key size according to Java Card + if (inputDataLen > 256) + KMException.throwIt(KMError.INVALID_INPUT_LENGTH); // make input equal to 255 bytes - //byte[] tmp = new byte[255]; - Util.arrayFillNonAtomic(tmpArray,(short)0,(short)256, (byte)0); - Util.arrayCopyNonAtomic( - inputDataBuf, - inputDataStart, - tmpArray, (short)(256 - inputDataLen),inputDataLen); + Util.arrayFillNonAtomic(tmpArray, (short) 0, (short) 256, (byte) 0); + Util.arrayCopyNonAtomic(inputDataBuf, inputDataStart, tmpArray, + (short) (256 - inputDataLen), inputDataLen); inputDataStart = 0; inputDataLen = 256; inputDataBuf = tmpArray; - } else if((cipherAlg == KMType.DES || cipherAlg == KMType.AES) && padding ==KMType.PKCS7 && mode == KMType.ENCRYPT){ + } else if ((cipherAlg == KMType.DES || cipherAlg == KMType.AES) && + padding == KMType.PKCS7 && mode == KMType.ENCRYPT) { byte blkSize = 16; byte paddingBytes; short inputlen = inputDataLen; - if (cipherAlg == KMType.DES) blkSize = 8; + if (cipherAlg == KMType.DES) + blkSize = 8; // padding bytes - if (inputlen % blkSize == 0) paddingBytes = blkSize; - else paddingBytes = (byte) (blkSize - (inputlen % blkSize)); + if (inputlen % blkSize == 0) { + paddingBytes = blkSize; + } else { + paddingBytes = (byte) (blkSize - (inputlen % blkSize)); + } // final len with padding inputlen = (short) (inputlen + paddingBytes); // intermediate buffer to copy input data+padding - //byte[] tmp = new byte[len]; // fill in the padding Util.arrayFillNonAtomic(tmpArray, (short) 0, inputlen, paddingBytes); // copy the input data - Util.arrayCopyNonAtomic(inputDataBuf,inputDataStart, tmpArray, (short)0, inputDataLen); + Util.arrayCopyNonAtomic(inputDataBuf, inputDataStart, tmpArray, + (short) 0, inputDataLen); inputDataBuf = tmpArray; inputDataLen = inputlen; inputDataStart = 0; } - len = cipher.doFinal(inputDataBuf, inputDataStart, inputDataLen, outputDataBuf, outputDataStart); - // JCOPProvider removes leading zeros during decryption in case of no padding - so add that back. - if (cipherAlg == KMType.RSA && padding == KMType.PADDING_NONE && mode == KMType.DECRYPT && len < 256) { - //byte[] tempBuf = new byte[256]; - //TODO Is this code required ?? - /*Util.arrayFill(tmpArray, (short) 0, (short) 256, (byte) 0); - Util.arrayCopy(outputDataBuf, (short) 0, tmpArray, (short) (outputDataStart + 256 - len), len); - Util.arrayCopy(tmpArray, (short) 0, outputDataBuf, outputDataStart, (short) 256); - len = 256;*/ - } else if((cipherAlg == KMType.AES || cipherAlg == KMType.DES) // PKCS7 - && padding == KMType.PKCS7 - && mode == KMType.DECRYPT){ + len = cipher.doFinal(inputDataBuf, inputDataStart, inputDataLen, + outputDataBuf, outputDataStart); + if ((cipherAlg == KMType.AES || cipherAlg == KMType.DES) && + padding == KMType.PKCS7 && mode == KMType.DECRYPT) { byte blkSize = 16; - if (cipherAlg == KMType.DES) blkSize = 8; - if(len >0) { - //verify if padding is corrupted. - byte paddingByte = outputDataBuf[(short)(outputDataStart+len -1)]; - //padding byte always should be <= block size - if((short)paddingByte > blkSize || - (short)paddingByte <= 0) KMException.throwIt(KMError.INVALID_ARGUMENT); - len = (short)(len - (short)paddingByte);// remove the padding bytes + if (cipherAlg == KMType.DES) + blkSize = 8; + if (len > 0) { + // verify if padding is corrupted. + byte paddingByte = outputDataBuf[(short) (outputDataStart + len - 1)]; + // padding byte always should be <= block size + if ((short) paddingByte > blkSize || (short) paddingByte <= 0) + KMException.throwIt(KMError.INVALID_ARGUMENT); + len = (short) (len - (short) paddingByte);// remove the padding bytes } - } else if(cipherAlg == KMType.AES && blockMode == KMType.GCM) { - if(mode == KMType.ENCRYPT) { - len += ((AEADCipher) cipher).retrieveTag(outputDataBuf, (short)(outputDataStart+len), macLength); + } else if (cipherAlg == KMType.AES && blockMode == KMType.GCM) { + if (mode == KMType.ENCRYPT) { + len += ((AEADCipher) cipher).retrieveTag(outputDataBuf, + (short) (outputDataStart + len), macLength); } else { - boolean verified = ((AEADCipher) cipher).verifyTag(inputDataBuf, (short)(inputDataStart+inputDataLen), macLength, macLength); - if(!verified) KMException.throwIt(KMError.VERIFICATION_FAILED); + boolean verified = ((AEADCipher) cipher).verifyTag(inputDataBuf, + (short) (inputDataStart + inputDataLen), macLength, macLength); + if (!verified) + KMException.throwIt(KMError.VERIFICATION_FAILED); } } } finally { - //KMJCOPSimProvider.getInstance().clean(); + KMJCOPSimProvider.getInstance().clean(); KMJCOPSimProvider.getInstance().releaseCipherInstance(cipher); resetCipher(); } @@ -180,22 +183,26 @@ public short finish(byte[] inputDataBuf, short inputDataStart, } @Override - public short sign(byte[] inputDataBuf, short inputDataStart, short inputDataLength, byte[] signBuf, short signStart) { + public short sign(byte[] inputDataBuf, short inputDataStart, + short inputDataLength, byte[] signBuf, short signStart) { short len = 0; try { - len = signature.sign(inputDataBuf,inputDataStart,inputDataLength,signBuf,signStart); + len = signature.sign(inputDataBuf, inputDataStart, inputDataLength, + signBuf, signStart); } finally { - KMJCOPSimProvider.getInstance().releaseSignatureInstance(signature); - signature = null; + KMJCOPSimProvider.getInstance().releaseSignatureInstance(signature); + signature = null; } return len; } @Override - public boolean verify(byte[] inputDataBuf, short inputDataStart, short inputDataLength, byte[] signBuf, short signStart, short signLength) { + public boolean verify(byte[] inputDataBuf, short inputDataStart, + short inputDataLength, byte[] signBuf, short signStart, short signLength) { boolean ret = false; try { - ret = signature.verify(inputDataBuf,inputDataStart,inputDataLength,signBuf,signStart,signLength); + ret = signature.verify(inputDataBuf, inputDataStart, inputDataLength, + signBuf, signStart, signLength); } finally { KMJCOPSimProvider.getInstance().releaseSignatureInstance(signature); signature = null; @@ -206,11 +213,11 @@ public boolean verify(byte[] inputDataBuf, short inputDataStart, short inputData @Override public void abort() { // do nothing - if(cipher != null) { + if (cipher != null) { KMJCOPSimProvider.getInstance().releaseCipherInstance(cipher); resetCipher(); } - if(signature != null) { + if (signature != null) { KMJCOPSimProvider.getInstance().releaseSignatureInstance(signature); signature = null; } diff --git a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java index 24aac2f6..242c5eab 100644 --- a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java +++ b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java @@ -8,40 +8,31 @@ import javacardx.crypto.Cipher; public class KMRsa2048NoDigestSignature extends Signature { - private Cipher inst; // ALG_RSA_NOPAD.; - //TODO ?? - //private byte[] rsaModulus; // to compare with the data value - - public static final byte ALG_RSA_SIGN_NOPAD = (byte)0x65; //TODO Change value later - public static final byte ALG_RSA_PKCS1_NODIGEST = (byte)0x66; //TODO Change value later + + public static final byte ALG_RSA_SIGN_NOPAD = (byte) 0x65; + public static final byte ALG_RSA_PKCS1_NODIGEST = (byte) 0x66; private byte algorithm; - - public KMRsa2048NoDigestSignature(byte alg){ + private Cipher inst; + + public KMRsa2048NoDigestSignature(byte alg) { algorithm = alg; inst = Cipher.getInstance(Cipher.ALG_RSA_NOPAD, false); } - /*public KMRsa2048NoDigestSignature(Cipher ciph, byte padding, byte[]mod, short start, short len){ - inst = ciph; - this.padding = padding; - if(len != 256) CryptoException.throwIt(CryptoException.INVALID_INIT); - rsaModulus = new byte[256]; - Util.arrayCopyNonAtomic(mod,start,rsaModulus,(short)0,len); - }*/ - @Override public void init(Key key, byte b) throws CryptoException { inst.init(key, b); } @Override - public void init(Key key, byte b, byte[] bytes, short i, short i1) throws CryptoException { + public void init(Key key, byte b, byte[] bytes, short i, short i1) + throws CryptoException { inst.init(key, b, bytes, i, i1); } @Override - public void setInitialDigest(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) throws CryptoException { - //TODO + public void setInitialDigest(byte[] bytes, short i, short i1, byte[] bytes1, + short i2, short i3) throws CryptoException { } @Override @@ -75,60 +66,61 @@ public void update(byte[] bytes, short i, short i1) throws CryptoException { } @Override - public short sign(byte[] bytes, short i, short i1, byte[] bytes1, short i2) throws CryptoException { - padData(bytes,i,i1, KMJCOPSimProvider.getInstance().tmpArray, (short)0); - return inst.doFinal(KMJCOPSimProvider.getInstance().tmpArray,(short)0,(short)256, bytes1, i2); + public short sign(byte[] bytes, short i, short i1, byte[] bytes1, short i2) + throws CryptoException { + padData(bytes, i, i1, KMJCOPSimProvider.getInstance().tmpArray, (short) 0); + return inst.doFinal(KMJCOPSimProvider.getInstance().tmpArray, (short) 0, + (short) 256, bytes1, i2); } @Override - public short signPreComputedHash(byte[] bytes, short i, short i1, byte[] bytes1, short i2) throws CryptoException { + public short signPreComputedHash(byte[] bytes, short i, short i1, + byte[] bytes1, short i2) throws CryptoException { return 0; } @Override - public boolean verify(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) throws CryptoException { - // Cannot support this method as javacard cipher api does not allow 256 byte for public key - // encryption without padding. It only allows 255 bytes data. + public boolean verify(byte[] bytes, short i, short i1, byte[] bytes1, + short i2, short i3) throws CryptoException { + //Verification is handled inside HAL return false; } @Override - public boolean verifyPreComputedHash(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) throws CryptoException { + public boolean verifyPreComputedHash(byte[] bytes, short i, short i1, + byte[] bytes1, short i2, short i3) throws CryptoException { + //Verification is handled inside HAL return false; } - private void padData(byte[] buf, short start, short len, - byte[] outBuf, short outBufStart){ - //byte[] inputData = new byte[256]; - //TODO ? - /*if(!isValidData(buf, start,len)){ + private void padData(byte[] buf, short start, short len, byte[] outBuf, + short outBufStart) { + if (!isValidData(buf, start, len)) { CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - }*/ - Util.arrayFillNonAtomic(outBuf, (short) outBufStart, (short) 256, (byte) 0x00); + } + Util.arrayFillNonAtomic(outBuf, (short) outBufStart, (short) 256, + (byte) 0x00); if (algorithm == ALG_RSA_SIGN_NOPAD) { // add zero to right } else if (algorithm == ALG_RSA_PKCS1_NODIGEST) {// 0x00||0x01||PS||0x00 outBuf[0] = 0x00; outBuf[1] = 0x01; - Util.arrayFillNonAtomic(outBuf,(short)2,(short)(256-len-3),(byte)0xFF); - outBuf[(short)(256-len-1)] = 0x00; - }else{ + Util.arrayFillNonAtomic(outBuf, (short) 2, (short) (256 - len - 3), + (byte) 0xFF); + outBuf[(short) (256 - len - 1)] = 0x00; + } else { CryptoException.throwIt(CryptoException.ILLEGAL_USE); } - Util.arrayCopyNonAtomic(buf, start, outBuf,(short)(256 -len), len); - } - - /*private boolean isValidData(byte[] buf, short start, short len) { - if (padding == KMType.PADDING_NONE) { - if (len > 256) return false; - else if (len == 256) { - short v = Util.arrayCompare(buf, start, rsaModulus, (short) 0, len); - if (v > 0) return false; - } - } else {//pkcs1 no digest - if(len > 245){ + Util.arrayCopyNonAtomic(buf, start, outBuf, (short) (256 - len), len); + } + + private boolean isValidData(byte[] buf, short start, short len) { + if (algorithm == ALG_RSA_SIGN_NOPAD) { + if (len > 256) + return false; + } else { // ALG_RSA_PKCS1_NODIGEST + if (len > 245) return false; - } } return true; - }*/ + } } diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMOperationImpl.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMOperationImpl.java index 941fd6cd..dec071e6 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMOperationImpl.java +++ b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMOperationImpl.java @@ -56,11 +56,4 @@ public void updateAAD(byte[] dataBuf, short dataStart, short dataLength) { public short getAESGCMOutputSize(short dataSize, short macLength) { return cipher.getAesGcmOutputSize(dataSize, macLength); } - -@Override -public void release() { - // TODO Auto-generated method stub - -} - } From a4ace6f0d8b64a0ed4fba083dbbe5c86331f2c1f Mon Sep 17 00:00:00 2001 From: bvenkatswarlu Date: Tue, 27 Oct 2020 17:43:21 +0530 Subject: [PATCH 07/42] Support for RSA-OAEP encoding scheme --- .../javacard/keymaster/KMJCOPSimProvider.java | 66 ++--- .../javacard/keymaster/KMRsaOAEPEncoding.java | 244 ++++++++++++++++++ 2 files changed, 268 insertions(+), 42 deletions(-) create mode 100644 Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMRsaOAEPEncoding.java diff --git a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMJCOPSimProvider.java b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMJCOPSimProvider.java index 98775ab7..e6f6c56b 100644 --- a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMJCOPSimProvider.java +++ b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMJCOPSimProvider.java @@ -110,7 +110,7 @@ public class KMJCOPSimProvider implements KMSEProvider { Cipher.ALG_DES_ECB_NOPAD, Cipher.ALG_AES_CTR, Cipher.ALG_RSA_PKCS1, - Cipher.ALG_RSA_PKCS1_OAEP, + KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA1, Cipher.ALG_RSA_NOPAD, AEADCipher.ALG_AES_GCM }; @@ -147,6 +147,8 @@ public class KMJCOPSimProvider implements KMSEProvider { private Signature kdf; private Signature hmacSignature; + //For ImportwrappedKey operations. + private KMRsaOAEPEncoding rsaOaepDecipher; // Entropy private RandomData rng; @@ -182,6 +184,8 @@ private KMJCOPSimProvider() { // Creates an instance of each signature algorithm once. initializeSigPool(); initializeOperationPool(); + //RsaOAEP Decipher + rsaOaepDecipher = new KMRsaOAEPEncoding(KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA1); kdf = Signature.getInstance(Signature.ALG_AES_CMAC_128, false); hmacSignature = Signature.getInstance(Signature.ALG_HMAC_SHA_256, false); @@ -272,25 +276,15 @@ private Signature getSignatureInstance(byte alg) { } private Cipher getCipherInstance(byte alg) { - if (Cipher.ALG_RSA_PKCS1_OAEP == alg) { - return Cipher.getInstance(Cipher.CIPHER_RSA, - Cipher.PAD_PKCS1_OAEP_SHA256, false); + if (KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA1 == alg) { + return new KMRsaOAEPEncoding(alg); } else { return Cipher.getInstance(alg, false); } } private byte getCipherAlgorithm(Cipher c) { - if (0 == c.getAlgorithm()) { - if (Cipher.PAD_PKCS1_OAEP_SHA256 == c.getPaddingAlgorithm()) { - return Cipher.ALG_RSA_PKCS1_OAEP; - } else { - KMException.throwIt(KMError.UNSUPPORTED_PADDING_MODE); - return 0; - } - } else { - return c.getAlgorithm(); - } + return c.getAlgorithm(); } // Create a cipher instance of each algorithm once. @@ -723,22 +717,12 @@ public short rsaDecipherOAEP256(byte[] secret, short secretStart, short secretLength, byte[] modBuffer, short modOff, short modLength, byte[] inputDataBuf, short inputDataStart, short inputDataLength, byte[] outputDataBuf, short outputDataStart) { - Cipher.OneShot cipher = null; - try { - RSAPrivateKey key = (RSAPrivateKey) rsaKeyPair.getPrivate(); - key.setExponent(secret, secretStart, secretLength); - key.setModulus(modBuffer, modOff, modLength); - - cipher = Cipher.OneShot.open(Cipher.CIPHER_RSA, - Cipher.PAD_PKCS1_OAEP_SHA256); - cipher.init(key, Cipher.MODE_DECRYPT); - return cipher.doFinal(inputDataBuf, inputDataStart, inputDataLength, - outputDataBuf, (short) outputDataStart); - - } finally { - if (cipher != null) - cipher.close(); - } + RSAPrivateKey key = (RSAPrivateKey) rsaKeyPair.getPrivate(); + key.setExponent(secret, (short)secretStart, (short)secretLength); + key.setModulus(modBuffer, (short)modOff, (short)modLength); + rsaOaepDecipher.init(key, Cipher.MODE_DECRYPT); + return rsaOaepDecipher.doFinal(inputDataBuf, (short)inputDataStart, (short)inputDataLength, + outputDataBuf, (short) outputDataStart); } @Override @@ -804,7 +788,7 @@ private byte mapSignature256Alg(byte alg, byte padding, byte digest) { return -1; } - private byte mapCipherAlg(byte alg, byte padding, byte blockmode) { + private byte mapCipherAlg(byte alg, byte padding, byte blockmode, byte digest) { switch (alg) { case KMType.AES: switch (blockmode) { @@ -832,8 +816,12 @@ private byte mapCipherAlg(byte alg, byte padding, byte blockmode) { return Cipher.ALG_RSA_NOPAD; case KMType.RSA_PKCS1_1_5_ENCRYPT: return Cipher.ALG_RSA_PKCS1; - case KMType.RSA_OAEP: - return Cipher.ALG_RSA_PKCS1_OAEP; + case KMType.RSA_OAEP: { + if (digest == KMType.SHA2_256) + return KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA1; + else + KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM); + } } break; } @@ -862,7 +850,7 @@ public Cipher createSymmetricCipher(short alg, short purpose, CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); break; } - short cipherAlg = mapCipherAlg((byte) alg, (byte) padding, (byte) blockMode); + short cipherAlg = mapCipherAlg((byte) alg, (byte) padding, (byte) blockMode, (byte)0); symmCipher = getCipherInstanceFromPool((byte) cipherAlg); switch (cipherAlg) { case Cipher.ALG_AES_BLOCK_128_CBC_NOPAD: @@ -981,7 +969,7 @@ public Signature createRsaVerifier(short digest, short padding, public Cipher createRsaCipher(short padding, short digest, byte[] modBuffer, short modOff, short modLength) { try { - byte cipherAlg = mapCipherAlg(KMType.RSA, (byte) padding, (byte) 0); + byte cipherAlg = mapCipherAlg(KMType.RSA, (byte) padding, (byte) 0, (byte)digest); // TODO Java Card does not support MGF1-SHA1 and digest as SHA256. // Both digest should be SHA256 as per Java Card, but as per Keymaster // MGF should use SHA1 and message digest should be SHA256. @@ -1005,13 +993,7 @@ public Cipher createRsaCipher(short padding, short digest, byte[] modBuffer, public Cipher createRsaDecipher(short padding, short digest, byte[] secret, short secretStart, short secretLength, byte[] modBuffer, short modOff, short modLength) { - byte cipherAlg = mapCipherAlg(KMType.RSA, (byte) padding, (byte) 0); - // TODO Java Card does not support MGF1-SHA1 and digest as SHA256. - // Both digest should be SHA256 as per Java Card, but as per Keymaster - // MGF should use SHA1 and message digest should be SHA256. - if (cipherAlg == Cipher.ALG_RSA_PKCS1_OAEP) { - KMException.throwIt(KMError.UNIMPLEMENTED); - } + byte cipherAlg = mapCipherAlg(KMType.RSA, (byte) padding, (byte) 0, (byte)digest); Cipher rsaCipher = getCipherInstanceFromPool(cipherAlg); RSAPrivateKey key = (RSAPrivateKey) rsaKeyPair.getPrivate(); key.setExponent(secret, secretStart, secretLength); diff --git a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMRsaOAEPEncoding.java b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMRsaOAEPEncoding.java new file mode 100644 index 00000000..4fb88e68 --- /dev/null +++ b/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMRsaOAEPEncoding.java @@ -0,0 +1,244 @@ +package com.android.javacard.keymaster; + +import javacard.framework.JCSystem; +import javacard.framework.Util; +import javacard.security.CryptoException; +import javacard.security.Key; +import javacard.security.MessageDigest; +import javacard.security.RSAPrivateKey; +import javacardx.crypto.Cipher; + +public class KMRsaOAEPEncoding extends Cipher { + + public static final byte ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA1 = (byte) 0x1E; + public static final byte ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA256 = (byte) 0x1F; + + final short MGF1_BUF_SIZE = 256; + static byte[] mgf1Buf; + private Cipher cipher; + private byte hash; + private byte mgf1Hash; + private byte algorithm; + + public KMRsaOAEPEncoding(byte alg) { + setDigests(alg); + cipher = Cipher.getInstance(Cipher.ALG_RSA_NOPAD, false); + algorithm = alg; + if (null == mgf1Buf) + mgf1Buf = JCSystem.makeTransientByteArray(MGF1_BUF_SIZE, + JCSystem.MEMORY_TYPE_TRANSIENT_DESELECT); + } + + private void setDigests(byte alg) { + switch (alg) { + case ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA1: + hash = MessageDigest.ALG_SHA_256; + mgf1Hash = MessageDigest.ALG_SHA; + break; + case ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA256: + hash = MessageDigest.ALG_SHA_256; + mgf1Hash = MessageDigest.ALG_SHA_256; + break; + default: + CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); + } + } + + private short getDigestLength() { + switch(hash) { + case MessageDigest.ALG_SHA: + return MessageDigest.LENGTH_SHA; + case MessageDigest.ALG_SHA_224: + return MessageDigest.LENGTH_SHA_224; + case MessageDigest.ALG_SHA_256: + return MessageDigest.LENGTH_SHA_256; + case MessageDigest.ALG_SHA_384: + return MessageDigest.LENGTH_SHA_384; + case MessageDigest.ALG_SHA3_512: + return MessageDigest.LENGTH_SHA_512; + default: + CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); + } + return 0; + } + + @Override + public void init(Key theKey, byte theMode) throws CryptoException { + cipher.init(theKey, theMode); + + } + + @Override + public void init(Key theKey, byte theMode, byte[] bArray, short bOff, + short bLen) throws CryptoException { + cipher.init(theKey, theMode, bArray, bOff, bLen); + } + + @Override + public byte getAlgorithm() { + return algorithm; + } + + @Override + public byte getCipherAlgorithm() { + // TODO + return 0; + } + + @Override + public byte getPaddingAlgorithm() { + // TODO + return 0; + } + + @Override + public short doFinal(byte[] inBuff, short inOffset, short inLength, + byte[] outBuff, short outOffset) throws CryptoException { + short len = cipher.doFinal(inBuff, inOffset, inLength, outBuff, outOffset); + + // https://tools.ietf.org/html/rfc8017#section-7.1 + // https://www.inf.pucrs.br/~calazans/graduate/TPVLSI_I/RSA-oaep_spec.pdf + // RSA OAEP Encoding and Decoding Mechanism for a 2048 bit RSA Key. + // Msg -> RSA-OAEP-ENCODE -> RSAEncryption -> RSADecryption -> + // RSA-OAEP-DECODE -> Msg + // RSA-OAEP-ENCODE generates an output length of 255, but RSAEncryption + // requires and input of length 256 so we pad 0 to the left of the input + // message and make the length equal to 256 and pass to RSAEncryption. + // RSADecryption takes input length equal to 256 and generates an + // output of length 256. After decryption the first byte of the output + // should be 0(left padding we did in encryption). + // RSA-OAEP-DECODE takes input of length 255 so remove the left padding of 1 + // byte. + if (len != 256 || outBuff[0] != 0) { + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } + inBuff = outBuff; + inOffset = (short) (outOffset + 1); + return rsaOAEPDecode(inBuff, inOffset, (short) (len - 1), outBuff, + outOffset); + + } + + @Override + public short update(byte[] inBuff, short inOffset, short inLength, + byte[] outBuff, short outOffset) throws CryptoException { + return cipher.update(inBuff, inOffset, inLength, outBuff, outOffset); + } + + private void maskGenerationFunction1(byte[] input, short inputOffset, + short inputLen, short expectedOutLen, byte[] outBuf, short outOffset) { + short counter = 0; + MessageDigest.OneShot md = null; + try { + md = MessageDigest.OneShot.open(mgf1Hash); + short digestLen = md.getLength(); + + Util.arrayCopyNonAtomic(input, inputOffset, mgf1Buf, (short) 0, inputLen); + while (counter < (short) (expectedOutLen / digestLen)) { + I2OS(counter, mgf1Buf, (short) inputLen); + md.doFinal(mgf1Buf, (short) 0, (short) (4 + inputLen), outBuf, + (short) (outOffset + (counter * digestLen))); + counter++; + } + + if ((short) (counter * digestLen) < expectedOutLen) { + I2OS(counter, mgf1Buf, (short) inputLen); + md.doFinal(mgf1Buf, (short) 0, (short) (4 + inputLen), outBuf, + (short) (outOffset + (counter * digestLen))); + } + + } finally { + if (md != null) + md.close(); + Util.arrayFillNonAtomic(mgf1Buf, (short) 0, (short) MGF1_BUF_SIZE, + (byte) 0); + } + } + + // Integer to Octet String conversion. + private void I2OS(short i, byte[] out, short offset) { + Util.arrayFillNonAtomic(out, (short) offset, (short) 4, (byte) 0); + out[(short) (offset + 3)] = (byte) (i >>> 0); + out[(short) (offset + 2)] = (byte) (i >>> 8); + } + + private short rsaOAEPDecode(byte[] encodedMsg, short encodedMsgOff, + short encodedMsgLen, byte[] msg, short offset) { + MessageDigest.OneShot md = null; + byte[] tmpArray = KMJCOPSimProvider.getInstance().tmpArray; + + try { + short hLen = getDigestLength(); + + if (encodedMsgLen < (2 * hLen + 1)) { + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } + // encodedMsg will be in the format of maskedSeed||maskedDB. + // maskedSeed length is hLen and maskedDB length is (encodedMsgLen - hLen) + // Now retrieve the seedMask by calling MGF(maskedDB, hLen). The length + // of the seedMask is hLen. + // seedMask = MGF(maskedDB, hLen) + maskGenerationFunction1(encodedMsg, (short) (encodedMsgOff + hLen), + (short) (encodedMsgLen - hLen), hLen, tmpArray, (short) 0); + + // Get the seed by doing XOR of (maskedSeed ^ seedMask). + // seed = (maskedSeed ^ seedMask) + for (short i = 0; i < hLen; i++) { + // Store the seed in encodeMsg itself. + encodedMsg[(short) (encodedMsgOff + i)] ^= tmpArray[i]; + } + + // Now get the dbMask by calling MGF(seed , (emLen-hLen)). + // dbMask = MGF(seed , (emLen-hLen)). + maskGenerationFunction1(encodedMsg, (short) encodedMsgOff, hLen, + (short) (encodedMsgLen - hLen), tmpArray, (short) 0); + + // Get the DB value. DB = (maskedDB ^ dbMask) + // DB = Hash(P)||00||01||Msg, where P is encoding parameters. (P = NULL) + for (short i = 0; i < (short) (encodedMsgLen - hLen); i++) { + // Store the DB inside encodeMsg itself. + encodedMsg[(short) (encodedMsgOff + i + hLen)] ^= tmpArray[i]; + } + + // Verify Hash. + md = MessageDigest.OneShot.open(hash); + Util.arrayFillNonAtomic(tmpArray, (short) 0, (short) 256, (byte) 0); + md.doFinal(tmpArray, (short) 0, (short) 0, tmpArray, (short) 0); + if (0 != Util.arrayCompare(encodedMsg, (short) (encodedMsgOff + hLen), + tmpArray, (short) 0, hLen)) { + // Verification failed. + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } + + // Find the Message block in DB. + // DB = Hash(P)||00||01||Msg, where P is encoding parameters. (P = NULL) + // The message will be located at the end of the Data block (DB). + // The DB block is first constructed by keeping the message at the end and + // to the message 0x01 byte is prepended. The hash of the + // encoding parameters is calculated and then copied from the + // starting of the block and a variable length of 0's are + // appended to the end of the hash till the 0x01 byte. + short start = 0; + for (short i = (short) (encodedMsgOff + 2 * hLen); i < (short) (encodedMsgOff + encodedMsgLen); i++) { + if (i == (short) ((encodedMsgOff + encodedMsgLen) - 1)) { + // Bad Padding. + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } + if (encodedMsg[i] != 0) { + start = i; + break; + } + } + // Copy the message + Util.arrayCopyNonAtomic(encodedMsg, (short) (start + 1), msg, offset, + (short) (encodedMsgLen - ((start - encodedMsgOff) + 1))); + return (short) (encodedMsgLen - ((start - encodedMsgOff) + 1)); + + } finally { + if (md != null) + md.close(); + Util.arrayFillNonAtomic(tmpArray, (short) 0, + KMJCOPSimProvider.TMP_ARRAY_SIZE, (byte) 0); + } + } +} \ No newline at end of file From 9f6252d6810e5eb16f809125fa3b912dafad2db5 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Mon, 2 Nov 2020 17:27:13 +0000 Subject: [PATCH 08/42] 1. Renamed JCOP Provider to SGTMProvider 2. Added Backup and restore functionality. --- .../keymaster/KMAttestationCertImpl.java | 0 .../keymaster/KMBackupRestoreAgent.java | 8 +++ .../keymaster/KMBackupStoreApplet.java | 63 +++++++++++++++++++ .../KMEcdsa256NoDigestSignature.java | 16 ++--- .../javacard/keymaster/KMInstance.java | 0 .../javacard/keymaster/KMOperationImpl.java | 16 ++--- .../keymaster/KMRsa2048NoDigestSignature.java | 4 +- .../javacard/keymaster/KMRsaOAEPEncoding.java | 4 +- .../javacard/keymaster/KMSEProviderImpl.java | 2 +- .../javacard/keymaster/KMSGTMProvider.java} | 26 +++++--- 10 files changed, 109 insertions(+), 30 deletions(-) rename Applet/Applet/{JCOPSimProvider => SGTMProvider}/com/android/javacard/keymaster/KMAttestationCertImpl.java (100%) create mode 100644 Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java create mode 100644 Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java rename Applet/Applet/{JCOPSimProvider => SGTMProvider}/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java (86%) rename Applet/Applet/{JCOPSimProvider => SGTMProvider}/com/android/javacard/keymaster/KMInstance.java (100%) rename Applet/Applet/{JCOPSimProvider => SGTMProvider}/com/android/javacard/keymaster/KMOperationImpl.java (92%) rename Applet/Applet/{JCOPSimProvider => SGTMProvider}/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java (95%) rename Applet/Applet/{JCOPSimProvider => SGTMProvider}/com/android/javacard/keymaster/KMRsaOAEPEncoding.java (98%) rename Applet/Applet/{JCOPSimProvider => SGTMProvider}/com/android/javacard/keymaster/KMSEProviderImpl.java (73%) rename Applet/Applet/{JCOPSimProvider/com/android/javacard/keymaster/KMJCOPSimProvider.java => SGTMProvider/com/android/javacard/keymaster/KMSGTMProvider.java} (97%) diff --git a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java similarity index 100% rename from Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java rename to Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java diff --git a/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java b/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java new file mode 100644 index 00000000..0c483334 --- /dev/null +++ b/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java @@ -0,0 +1,8 @@ +package com.android.javacard.keymaster; + +import javacard.framework.Shareable; + +public interface KMBackupRestoreAgent extends Shareable { + void backup(byte[] buf, short start, short len); + short restore(byte[] buf, short start); +} diff --git a/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java b/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java new file mode 100644 index 00000000..5f28c014 --- /dev/null +++ b/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java @@ -0,0 +1,63 @@ +package com.android.javacard.keymaster; + +import javacard.framework.AID; +import javacard.framework.APDU; +import javacard.framework.Applet; +import javacard.framework.JCSystem; +import javacard.framework.Shareable; +import javacard.framework.Util; + +public class KMBackupStoreApplet extends Applet implements KMBackupRestoreAgent { + private static final short DATA_TABLE_MEM_SIZE = 2048; + private static final byte[] aidArr = new byte[]{ (byte)0xA0, 0x00, 0x00, 0x00, 0x62}; + + private byte[] dataTable; + private short dataTableSize; + + private KMBackupStoreApplet() { + dataTable = new byte[DATA_TABLE_MEM_SIZE]; + } + + public static void install(byte bArray[], short bOffset, byte bLength) { + new KMBackupStoreApplet().register(); + } + + @Override + public boolean select() { + return true; + } + + @Override + public void process(APDU apdu) { + + } + + @Override + public void backup(byte[] buf, short start, short len) { + // Store the data + if (len > 0) { + JCSystem.beginTransaction(); + dataTableSize = len; + Util.arrayCopy(buf, start, dataTable, (short) 0, len); + JCSystem.commitTransaction(); + } + } + + @Override + public short restore(byte[] buf, short start) { + // Restore the data + Util.arrayCopy(dataTable, (short) 0, buf, start, dataTableSize); + return dataTableSize; + } + + @Override + public Shareable getShareableInterfaceObject(AID aid, byte param){ + byte[] aidBytes = new byte[10]; + byte len = aid.getBytes(aidBytes, (short)0); + if(Util.arrayCompare(aidArr,(short)0,aidBytes,(short)0,len) == 0){ + return this; + } + return null; + } + +} diff --git a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java b/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java similarity index 86% rename from Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java rename to Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java index 56644b7f..84c95df3 100644 --- a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java +++ b/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java @@ -75,16 +75,16 @@ public short sign(byte[] bytes, short i, short i1, byte[] bytes1, short i2) CryptoException.throwIt(CryptoException.ILLEGAL_USE); // add zeros to the left if (i1 < MAX_NO_DIGEST_MSG_LEN) { - Util.arrayFillNonAtomic(KMJCOPSimProvider.getInstance().tmpArray, + Util.arrayFillNonAtomic(KMSGTMProvider.getInstance().tmpArray, (short) 0, (short) MAX_NO_DIGEST_MSG_LEN, (byte) 0); } Util.arrayCopyNonAtomic(bytes, i, - KMJCOPSimProvider.getInstance().tmpArray, + KMSGTMProvider.getInstance().tmpArray, (short) (MAX_NO_DIGEST_MSG_LEN - i1), i1); - return inst.signPreComputedHash(KMJCOPSimProvider.getInstance().tmpArray, + return inst.signPreComputedHash(KMSGTMProvider.getInstance().tmpArray, (short) 0, (short) MAX_NO_DIGEST_MSG_LEN, bytes1, i2); } finally { - KMJCOPSimProvider.getInstance().clean(); + KMSGTMProvider.getInstance().clean(); } } @@ -102,17 +102,17 @@ public boolean verify(byte[] bytes, short i, short i1, byte[] bytes1, CryptoException.throwIt(CryptoException.ILLEGAL_USE); // add zeros to the left if (i1 < MAX_NO_DIGEST_MSG_LEN) { - Util.arrayFillNonAtomic(KMJCOPSimProvider.getInstance().tmpArray, + Util.arrayFillNonAtomic(KMSGTMProvider.getInstance().tmpArray, (short) 0, (short) MAX_NO_DIGEST_MSG_LEN, (byte) 0); } Util.arrayCopyNonAtomic(bytes, i, - KMJCOPSimProvider.getInstance().tmpArray, + KMSGTMProvider.getInstance().tmpArray, (short) (MAX_NO_DIGEST_MSG_LEN - i1), i1); return inst.verifyPreComputedHash( - KMJCOPSimProvider.getInstance().tmpArray, (short) 0, + KMSGTMProvider.getInstance().tmpArray, (short) 0, (short) MAX_NO_DIGEST_MSG_LEN, bytes1, i2, i3); } finally { - KMJCOPSimProvider.getInstance().clean(); + KMSGTMProvider.getInstance().clean(); } } diff --git a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMInstance.java b/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMInstance.java similarity index 100% rename from Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMInstance.java rename to Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMInstance.java diff --git a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMOperationImpl.java b/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMOperationImpl.java similarity index 92% rename from Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMOperationImpl.java rename to Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMOperationImpl.java index 1183c6eb..203746d2 100644 --- a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMOperationImpl.java +++ b/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMOperationImpl.java @@ -103,7 +103,7 @@ public short update(byte[] inputDataBuf, short inputDataStart, @Override public short finish(byte[] inputDataBuf, short inputDataStart, short inputDataLen, byte[] outputDataBuf, short outputDataStart) { - byte[] tmpArray = KMJCOPSimProvider.getInstance().tmpArray; + byte[] tmpArray = KMSGTMProvider.getInstance().tmpArray; short len = 0; try { if (cipherAlg == KMType.AES && blockMode == KMType.GCM) { @@ -175,8 +175,8 @@ public short finish(byte[] inputDataBuf, short inputDataStart, } } } finally { - KMJCOPSimProvider.getInstance().clean(); - KMJCOPSimProvider.getInstance().releaseCipherInstance(cipher); + KMSGTMProvider.getInstance().clean(); + KMSGTMProvider.getInstance().releaseCipherInstance(cipher); resetCipher(); } return len; @@ -190,7 +190,7 @@ public short sign(byte[] inputDataBuf, short inputDataStart, len = signature.sign(inputDataBuf, inputDataStart, inputDataLength, signBuf, signStart); } finally { - KMJCOPSimProvider.getInstance().releaseSignatureInstance(signature); + KMSGTMProvider.getInstance().releaseSignatureInstance(signature); signature = null; } return len; @@ -204,7 +204,7 @@ public boolean verify(byte[] inputDataBuf, short inputDataStart, ret = signature.verify(inputDataBuf, inputDataStart, inputDataLength, signBuf, signStart, signLength); } finally { - KMJCOPSimProvider.getInstance().releaseSignatureInstance(signature); + KMSGTMProvider.getInstance().releaseSignatureInstance(signature); signature = null; } return ret; @@ -214,14 +214,14 @@ public boolean verify(byte[] inputDataBuf, short inputDataStart, public void abort() { // do nothing if (cipher != null) { - KMJCOPSimProvider.getInstance().releaseCipherInstance(cipher); + KMSGTMProvider.getInstance().releaseCipherInstance(cipher); resetCipher(); } if (signature != null) { - KMJCOPSimProvider.getInstance().releaseSignatureInstance(signature); + KMSGTMProvider.getInstance().releaseSignatureInstance(signature); signature = null; } - KMJCOPSimProvider.getInstance().releaseOperationInstance(this); + KMSGTMProvider.getInstance().releaseOperationInstance(this); } @Override diff --git a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java b/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java similarity index 95% rename from Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java rename to Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java index 242c5eab..70654540 100644 --- a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java +++ b/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java @@ -68,8 +68,8 @@ public void update(byte[] bytes, short i, short i1) throws CryptoException { @Override public short sign(byte[] bytes, short i, short i1, byte[] bytes1, short i2) throws CryptoException { - padData(bytes, i, i1, KMJCOPSimProvider.getInstance().tmpArray, (short) 0); - return inst.doFinal(KMJCOPSimProvider.getInstance().tmpArray, (short) 0, + padData(bytes, i, i1, KMSGTMProvider.getInstance().tmpArray, (short) 0); + return inst.doFinal(KMSGTMProvider.getInstance().tmpArray, (short) 0, (short) 256, bytes1, i2); } diff --git a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMRsaOAEPEncoding.java b/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMRsaOAEPEncoding.java similarity index 98% rename from Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMRsaOAEPEncoding.java rename to Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMRsaOAEPEncoding.java index 4fb88e68..1d5e56e6 100644 --- a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMRsaOAEPEncoding.java +++ b/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMRsaOAEPEncoding.java @@ -165,7 +165,7 @@ private void I2OS(short i, byte[] out, short offset) { private short rsaOAEPDecode(byte[] encodedMsg, short encodedMsgOff, short encodedMsgLen, byte[] msg, short offset) { MessageDigest.OneShot md = null; - byte[] tmpArray = KMJCOPSimProvider.getInstance().tmpArray; + byte[] tmpArray = KMSGTMProvider.getInstance().tmpArray; try { short hLen = getDigestLength(); @@ -238,7 +238,7 @@ private short rsaOAEPDecode(byte[] encodedMsg, short encodedMsgOff, if (md != null) md.close(); Util.arrayFillNonAtomic(tmpArray, (short) 0, - KMJCOPSimProvider.TMP_ARRAY_SIZE, (byte) 0); + KMSGTMProvider.TMP_ARRAY_SIZE, (byte) 0); } } } \ No newline at end of file diff --git a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMSEProviderImpl.java b/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMSEProviderImpl.java similarity index 73% rename from Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMSEProviderImpl.java rename to Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMSEProviderImpl.java index 9abdc548..5bcfaa5c 100644 --- a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMSEProviderImpl.java +++ b/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMSEProviderImpl.java @@ -3,6 +3,6 @@ public class KMSEProviderImpl { public static KMSEProvider instance(){ - return KMJCOPSimProvider.getInstance(); + return KMSGTMProvider.getInstance(); } } diff --git a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMJCOPSimProvider.java b/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMSGTMProvider.java similarity index 97% rename from Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMJCOPSimProvider.java rename to Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMSGTMProvider.java index e6f6c56b..3808244a 100644 --- a/Applet/Applet/JCOPSimProvider/com/android/javacard/keymaster/KMJCOPSimProvider.java +++ b/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMSGTMProvider.java @@ -15,6 +15,7 @@ */ package com.android.javacard.keymaster; +import javacard.framework.AID; import javacard.framework.JCSystem; import javacard.framework.Util; import javacard.security.AESKey; @@ -34,7 +35,7 @@ import javacardx.crypto.AEADCipher; import javacardx.crypto.Cipher; -public class KMJCOPSimProvider implements KMSEProvider { +public class KMSGTMProvider implements KMSEProvider { // static final variables // -------------------------------------------------------------- // P-256 Curve Parameters @@ -102,6 +103,8 @@ public class KMJCOPSimProvider implements KMSEProvider { public static final byte KEYSIZE_128_OFFSET = 0x00; public static final byte KEYSIZE_256_OFFSET = 0x01; public static final short TMP_ARRAY_SIZE = 256; + private static final byte[] aidArr = new byte[] { + (byte)0xA0, 0x00, 0x00, 0x00, 0x63}; final byte[] CIPHER_ALGS = { Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, @@ -153,15 +156,15 @@ public class KMJCOPSimProvider implements KMSEProvider { // Entropy private RandomData rng; - private static KMJCOPSimProvider jcopProvider = null; + private static KMSGTMProvider sgtmProvider = null; - public static KMJCOPSimProvider getInstance() { - if (jcopProvider == null) - jcopProvider = new KMJCOPSimProvider(); - return jcopProvider; + public static KMSGTMProvider getInstance() { + if (sgtmProvider == null) + sgtmProvider = new KMSGTMProvider(); + return sgtmProvider; } - private KMJCOPSimProvider() { + private KMSGTMProvider() { // Re-usable AES,DES and HMAC keys in persisted memory. aesKeys = new AESKey[2]; aesKeys[KEYSIZE_128_OFFSET] = (AESKey) KeyBuilder.buildKey( @@ -1129,12 +1132,17 @@ public boolean isBackupRestoreSupported() { @Override public void backup(byte[] buf, short start, short len) { - + AID aid = JCSystem.lookupAID(aidArr,(short)0,(byte)aidArr.length); + KMBackupRestoreAgent backupStore = (KMBackupRestoreAgent) JCSystem.getAppletShareableInterfaceObject(aid,(byte)0); + backupStore.backup(buf, (short)start, len); } @Override public short restore(byte[] buf, short start) { - return 0; + AID aid = JCSystem.lookupAID(aidArr,(short)0,(byte)aidArr.length); + KMBackupRestoreAgent backupStore = (KMBackupRestoreAgent) JCSystem.getAppletShareableInterfaceObject(aid,(byte)0); + short len = backupStore.restore(buf,(short)start); + return len; } @Override From 230c43372f4933be3fc81d6a73f446d4b680c198 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Tue, 3 Nov 2020 14:51:03 +0000 Subject: [PATCH 09/42] Renamed SGTMProvider to AndroidSEProvider --- .../javacard/keymaster/AndroidSEProvider.java} | 10 +++++----- .../keymaster/KMAttestationCertImpl.java | 0 .../javacard/keymaster/KMBackupRestoreAgent.java | 0 .../javacard/keymaster/KMBackupStoreApplet.java | 0 .../keymaster/KMEcdsa256NoDigestSignature.java | 16 ++++++++-------- .../android/javacard/keymaster/KMInstance.java | 0 .../javacard/keymaster/KMOperationImpl.java | 16 ++++++++-------- .../keymaster/KMRsa2048NoDigestSignature.java | 4 ++-- .../javacard/keymaster/KMRsaOAEPEncoding.java | 4 ++-- .../javacard/keymaster/KMSEProviderImpl.java | 2 +- 10 files changed, 26 insertions(+), 26 deletions(-) rename Applet/Applet/{SGTMProvider/com/android/javacard/keymaster/KMSGTMProvider.java => AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java} (99%) rename Applet/Applet/{SGTMProvider => AndroidSEProvider}/com/android/javacard/keymaster/KMAttestationCertImpl.java (100%) rename Applet/Applet/{SGTMProvider => AndroidSEProvider}/com/android/javacard/keymaster/KMBackupRestoreAgent.java (100%) rename Applet/Applet/{SGTMProvider => AndroidSEProvider}/com/android/javacard/keymaster/KMBackupStoreApplet.java (100%) rename Applet/Applet/{SGTMProvider => AndroidSEProvider}/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java (86%) rename Applet/Applet/{SGTMProvider => AndroidSEProvider}/com/android/javacard/keymaster/KMInstance.java (100%) rename Applet/Applet/{SGTMProvider => AndroidSEProvider}/com/android/javacard/keymaster/KMOperationImpl.java (92%) rename Applet/Applet/{SGTMProvider => AndroidSEProvider}/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java (95%) rename Applet/Applet/{SGTMProvider => AndroidSEProvider}/com/android/javacard/keymaster/KMRsaOAEPEncoding.java (98%) rename Applet/Applet/{SGTMProvider => AndroidSEProvider}/com/android/javacard/keymaster/KMSEProviderImpl.java (73%) diff --git a/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMSGTMProvider.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java similarity index 99% rename from Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMSGTMProvider.java rename to Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java index 3808244a..cab5ead4 100644 --- a/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMSGTMProvider.java +++ b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java @@ -35,7 +35,7 @@ import javacardx.crypto.AEADCipher; import javacardx.crypto.Cipher; -public class KMSGTMProvider implements KMSEProvider { +public class AndroidSEProvider implements KMSEProvider { // static final variables // -------------------------------------------------------------- // P-256 Curve Parameters @@ -156,15 +156,15 @@ public class KMSGTMProvider implements KMSEProvider { // Entropy private RandomData rng; - private static KMSGTMProvider sgtmProvider = null; + private static AndroidSEProvider sgtmProvider = null; - public static KMSGTMProvider getInstance() { + public static AndroidSEProvider getInstance() { if (sgtmProvider == null) - sgtmProvider = new KMSGTMProvider(); + sgtmProvider = new AndroidSEProvider(); return sgtmProvider; } - private KMSGTMProvider() { + private AndroidSEProvider() { // Re-usable AES,DES and HMAC keys in persisted memory. aesKeys = new AESKey[2]; aesKeys[KEYSIZE_128_OFFSET] = (AESKey) KeyBuilder.buildKey( diff --git a/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java similarity index 100% rename from Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java rename to Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java diff --git a/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java similarity index 100% rename from Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java rename to Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java diff --git a/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java similarity index 100% rename from Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java rename to Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java diff --git a/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java similarity index 86% rename from Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java rename to Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java index 84c95df3..31abede5 100644 --- a/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java +++ b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java @@ -75,16 +75,16 @@ public short sign(byte[] bytes, short i, short i1, byte[] bytes1, short i2) CryptoException.throwIt(CryptoException.ILLEGAL_USE); // add zeros to the left if (i1 < MAX_NO_DIGEST_MSG_LEN) { - Util.arrayFillNonAtomic(KMSGTMProvider.getInstance().tmpArray, + Util.arrayFillNonAtomic(AndroidSEProvider.getInstance().tmpArray, (short) 0, (short) MAX_NO_DIGEST_MSG_LEN, (byte) 0); } Util.arrayCopyNonAtomic(bytes, i, - KMSGTMProvider.getInstance().tmpArray, + AndroidSEProvider.getInstance().tmpArray, (short) (MAX_NO_DIGEST_MSG_LEN - i1), i1); - return inst.signPreComputedHash(KMSGTMProvider.getInstance().tmpArray, + return inst.signPreComputedHash(AndroidSEProvider.getInstance().tmpArray, (short) 0, (short) MAX_NO_DIGEST_MSG_LEN, bytes1, i2); } finally { - KMSGTMProvider.getInstance().clean(); + AndroidSEProvider.getInstance().clean(); } } @@ -102,17 +102,17 @@ public boolean verify(byte[] bytes, short i, short i1, byte[] bytes1, CryptoException.throwIt(CryptoException.ILLEGAL_USE); // add zeros to the left if (i1 < MAX_NO_DIGEST_MSG_LEN) { - Util.arrayFillNonAtomic(KMSGTMProvider.getInstance().tmpArray, + Util.arrayFillNonAtomic(AndroidSEProvider.getInstance().tmpArray, (short) 0, (short) MAX_NO_DIGEST_MSG_LEN, (byte) 0); } Util.arrayCopyNonAtomic(bytes, i, - KMSGTMProvider.getInstance().tmpArray, + AndroidSEProvider.getInstance().tmpArray, (short) (MAX_NO_DIGEST_MSG_LEN - i1), i1); return inst.verifyPreComputedHash( - KMSGTMProvider.getInstance().tmpArray, (short) 0, + AndroidSEProvider.getInstance().tmpArray, (short) 0, (short) MAX_NO_DIGEST_MSG_LEN, bytes1, i2, i3); } finally { - KMSGTMProvider.getInstance().clean(); + AndroidSEProvider.getInstance().clean(); } } diff --git a/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMInstance.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMInstance.java similarity index 100% rename from Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMInstance.java rename to Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMInstance.java diff --git a/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMOperationImpl.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMOperationImpl.java similarity index 92% rename from Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMOperationImpl.java rename to Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMOperationImpl.java index 203746d2..2469dd0c 100644 --- a/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMOperationImpl.java +++ b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMOperationImpl.java @@ -103,7 +103,7 @@ public short update(byte[] inputDataBuf, short inputDataStart, @Override public short finish(byte[] inputDataBuf, short inputDataStart, short inputDataLen, byte[] outputDataBuf, short outputDataStart) { - byte[] tmpArray = KMSGTMProvider.getInstance().tmpArray; + byte[] tmpArray = AndroidSEProvider.getInstance().tmpArray; short len = 0; try { if (cipherAlg == KMType.AES && blockMode == KMType.GCM) { @@ -175,8 +175,8 @@ public short finish(byte[] inputDataBuf, short inputDataStart, } } } finally { - KMSGTMProvider.getInstance().clean(); - KMSGTMProvider.getInstance().releaseCipherInstance(cipher); + AndroidSEProvider.getInstance().clean(); + AndroidSEProvider.getInstance().releaseCipherInstance(cipher); resetCipher(); } return len; @@ -190,7 +190,7 @@ public short sign(byte[] inputDataBuf, short inputDataStart, len = signature.sign(inputDataBuf, inputDataStart, inputDataLength, signBuf, signStart); } finally { - KMSGTMProvider.getInstance().releaseSignatureInstance(signature); + AndroidSEProvider.getInstance().releaseSignatureInstance(signature); signature = null; } return len; @@ -204,7 +204,7 @@ public boolean verify(byte[] inputDataBuf, short inputDataStart, ret = signature.verify(inputDataBuf, inputDataStart, inputDataLength, signBuf, signStart, signLength); } finally { - KMSGTMProvider.getInstance().releaseSignatureInstance(signature); + AndroidSEProvider.getInstance().releaseSignatureInstance(signature); signature = null; } return ret; @@ -214,14 +214,14 @@ public boolean verify(byte[] inputDataBuf, short inputDataStart, public void abort() { // do nothing if (cipher != null) { - KMSGTMProvider.getInstance().releaseCipherInstance(cipher); + AndroidSEProvider.getInstance().releaseCipherInstance(cipher); resetCipher(); } if (signature != null) { - KMSGTMProvider.getInstance().releaseSignatureInstance(signature); + AndroidSEProvider.getInstance().releaseSignatureInstance(signature); signature = null; } - KMSGTMProvider.getInstance().releaseOperationInstance(this); + AndroidSEProvider.getInstance().releaseOperationInstance(this); } @Override diff --git a/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java similarity index 95% rename from Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java rename to Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java index 70654540..eb799dfe 100644 --- a/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java +++ b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java @@ -68,8 +68,8 @@ public void update(byte[] bytes, short i, short i1) throws CryptoException { @Override public short sign(byte[] bytes, short i, short i1, byte[] bytes1, short i2) throws CryptoException { - padData(bytes, i, i1, KMSGTMProvider.getInstance().tmpArray, (short) 0); - return inst.doFinal(KMSGTMProvider.getInstance().tmpArray, (short) 0, + padData(bytes, i, i1, AndroidSEProvider.getInstance().tmpArray, (short) 0); + return inst.doFinal(AndroidSEProvider.getInstance().tmpArray, (short) 0, (short) 256, bytes1, i2); } diff --git a/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMRsaOAEPEncoding.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMRsaOAEPEncoding.java similarity index 98% rename from Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMRsaOAEPEncoding.java rename to Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMRsaOAEPEncoding.java index 1d5e56e6..159f62d0 100644 --- a/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMRsaOAEPEncoding.java +++ b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMRsaOAEPEncoding.java @@ -165,7 +165,7 @@ private void I2OS(short i, byte[] out, short offset) { private short rsaOAEPDecode(byte[] encodedMsg, short encodedMsgOff, short encodedMsgLen, byte[] msg, short offset) { MessageDigest.OneShot md = null; - byte[] tmpArray = KMSGTMProvider.getInstance().tmpArray; + byte[] tmpArray = AndroidSEProvider.getInstance().tmpArray; try { short hLen = getDigestLength(); @@ -238,7 +238,7 @@ private short rsaOAEPDecode(byte[] encodedMsg, short encodedMsgOff, if (md != null) md.close(); Util.arrayFillNonAtomic(tmpArray, (short) 0, - KMSGTMProvider.TMP_ARRAY_SIZE, (byte) 0); + AndroidSEProvider.TMP_ARRAY_SIZE, (byte) 0); } } } \ No newline at end of file diff --git a/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMSEProviderImpl.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMSEProviderImpl.java similarity index 73% rename from Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMSEProviderImpl.java rename to Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMSEProviderImpl.java index 5bcfaa5c..d9ff00eb 100644 --- a/Applet/Applet/SGTMProvider/com/android/javacard/keymaster/KMSEProviderImpl.java +++ b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMSEProviderImpl.java @@ -3,6 +3,6 @@ public class KMSEProviderImpl { public static KMSEProvider instance(){ - return KMSGTMProvider.getInstance(); + return AndroidSEProvider.getInstance(); } } From 7125820a014681d765e980812d65c8f8dd7b8273 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Sun, 8 Nov 2020 22:49:44 +0000 Subject: [PATCH 10/42] provisioning changes --- .../javacard/keymaster/AndroidSEProvider.java | 77 ++++++- .../keymaster/KMBackupRestoreAgent.java | 3 + .../keymaster/KMBackupStoreApplet.java | 48 ++++- .../keymaster/KMBackupRestoreAgent.java | 3 + .../keymaster/KMBackupStoreApplet.java | 48 ++++- .../javacard/keymaster/KMJcardSimulator.java | 70 ++++++- .../android/javacard/keymaster/KMEncoder.java | 10 + .../javacard/keymaster/KMKeymasterApplet.java | 197 +++++++++++++----- .../javacard/keymaster/KMRepository.java | 84 ++++++-- .../javacard/keymaster/KMSEProvider.java | 40 ++++ 10 files changed, 481 insertions(+), 99 deletions(-) diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java index cab5ead4..a0a31614 100644 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java +++ b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java @@ -16,6 +16,8 @@ package com.android.javacard.keymaster; import javacard.framework.AID; +import javacard.framework.ISO7816; +import javacard.framework.ISOException; import javacard.framework.JCSystem; import javacard.framework.Util; import javacard.security.AESKey; @@ -103,6 +105,8 @@ public class AndroidSEProvider implements KMSEProvider { public static final byte KEYSIZE_128_OFFSET = 0x00; public static final byte KEYSIZE_256_OFFSET = 0x01; public static final short TMP_ARRAY_SIZE = 256; + public static final short NUM_OF_CERTS = 1; + public static final short CERT_CHAIN_MAX_SIZE = 2050;//First 2 bytes for length. private static final byte[] aidArr = new byte[] { (byte)0xA0, 0x00, 0x00, 0x00, 0x63}; @@ -155,6 +159,8 @@ public class AndroidSEProvider implements KMSEProvider { // Entropy private RandomData rng; + //For storing root certificate and intermediate certificates. + private byte[] certificateChain; private static AndroidSEProvider sgtmProvider = null; @@ -199,6 +205,8 @@ private AndroidSEProvider() { // Random number generator initialisation. rng = RandomData.getInstance(RandomData.ALG_KEYGENERATION); + //Allocate buffer for certificate chain. + certificateChain = new byte[CERT_CHAIN_MAX_SIZE]; } public void clean() { @@ -1132,17 +1140,43 @@ public boolean isBackupRestoreSupported() { @Override public void backup(byte[] buf, short start, short len) { - AID aid = JCSystem.lookupAID(aidArr,(short)0,(byte)aidArr.length); - KMBackupRestoreAgent backupStore = (KMBackupRestoreAgent) JCSystem.getAppletShareableInterfaceObject(aid,(byte)0); - backupStore.backup(buf, (short)start, len); + short certChainLen = Util.getShort(certificateChain, (short) 0); + certChainLen += 2; //including the length of certifcate. + AID aid = JCSystem.lookupAID(aidArr, (short) 0, (byte) aidArr.length); + if (null == aid) + ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED); + KMBackupRestoreAgent backupStore = (KMBackupRestoreAgent) JCSystem + .getAppletShareableInterfaceObject(aid, (byte) 0); + backupStore.backupProviderData(certificateChain, (short)0, certChainLen); + backupStore.backup(buf, (short) start, len); } @Override public short restore(byte[] buf, short start) { + AID aid = JCSystem.lookupAID(aidArr, (short) 0, (byte) aidArr.length); + if (null == aid) + ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED); + KMBackupRestoreAgent backupStore = (KMBackupRestoreAgent) JCSystem + .getAppletShareableInterfaceObject(aid, (byte) 0); + short len = backupStore.restore(buf, (short) start); + short heapOff = KMRepository.instance().alloc(CERT_CHAIN_MAX_SIZE); + short certChainLen = backupStore.restoreProviderData(KMRepository + .instance().getHeap(), heapOff); + JCSystem.beginTransaction(); + Util.arrayCopy(KMRepository.instance().getHeap(), heapOff, + certificateChain, (short) 0, certChainLen); + JCSystem.commitTransaction(); + + return len; + } + + @Override + public boolean isBackupAvailable() { AID aid = JCSystem.lookupAID(aidArr,(short)0,(byte)aidArr.length); + if(null == aid) + ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED); KMBackupRestoreAgent backupStore = (KMBackupRestoreAgent) JCSystem.getAppletShareableInterfaceObject(aid,(byte)0); - short len = backupStore.restore(buf,(short)start); - return len; + return backupStore.isBackupAvailable(); } @Override @@ -1155,4 +1189,37 @@ public short cmacKdf(byte[] keyMaterial, short keyMaterialStart, return key.getKey(keyBuf, keyStart); } + @Override + public void persistCertificateChain(byte[] buf, short offset, short len) { + // _____________________________________________________ + // | 2 Bytes | 1 Byte | 3 Bytes | Cert1 | 3 Bytes | Cert2|... + // |_________|________|_________|_______|_________|______| + // First two bytes holds the length of the total buffer. + // CBOR format: + // Next single byte holds the array header. + // Next 3 bytes holds the Byte array header with the cert1 length. + // Next 3 bytes holds the Byte array header with the cert2 length. + JCSystem.beginTransaction(); + Util.setShort(certificateChain, (short)0, len); + Util.arrayCopyNonAtomic(buf, offset, certificateChain, (short)2, len); + JCSystem.commitTransaction(); + } + + @Override + public short readCertificateChain(byte[] buf, short offset) { + short len = Util.getShort(certificateChain, (short)0); + Util.arrayCopyNonAtomic(certificateChain, (short)2, buf, offset, len); + return len; + } + + @Override + public short getCertificateChainLength() { + return Util.getShort(certificateChain, (short)0); + } + + @Override + public short getNumberOfCerts() { + return NUM_OF_CERTS; + } + } diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java index 0c483334..764d4a3e 100644 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java +++ b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java @@ -5,4 +5,7 @@ public interface KMBackupRestoreAgent extends Shareable { void backup(byte[] buf, short start, short len); short restore(byte[] buf, short start); + void backupProviderData(byte[] buf, short start, short len); + short restoreProviderData(byte[] buf, short start); + boolean isBackupAvailable(); } diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java index 5f28c014..4e851e5c 100644 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java +++ b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java @@ -8,14 +8,18 @@ import javacard.framework.Util; public class KMBackupStoreApplet extends Applet implements KMBackupRestoreAgent { - private static final short DATA_TABLE_MEM_SIZE = 2048; + private static final short PROVIDER_MEM_SIZE = 2050; + private static final short KM_APPLET_MEM_SIZE = 2050; + private static final short PROVIDER_OFFSET = 0; + private static final short KM_APPLET_DATA_OFFSET = PROVIDER_MEM_SIZE; private static final byte[] aidArr = new byte[]{ (byte)0xA0, 0x00, 0x00, 0x00, 0x62}; private byte[] dataTable; - private short dataTableSize; + boolean backupAvailable; private KMBackupStoreApplet() { - dataTable = new byte[DATA_TABLE_MEM_SIZE]; + dataTable = new byte[KM_APPLET_MEM_SIZE + PROVIDER_MEM_SIZE]; + backupAvailable = false; } public static void install(byte bArray[], short bOffset, byte bLength) { @@ -37,17 +41,22 @@ public void backup(byte[] buf, short start, short len) { // Store the data if (len > 0) { JCSystem.beginTransaction(); - dataTableSize = len; - Util.arrayCopy(buf, start, dataTable, (short) 0, len); + // dataTableSize = len; + Util.setShort(dataTable, KM_APPLET_DATA_OFFSET, len); + Util.arrayCopy(buf, start, dataTable, + (short) (KM_APPLET_DATA_OFFSET + 2), len); JCSystem.commitTransaction(); } + backupAvailable = true; } @Override public short restore(byte[] buf, short start) { // Restore the data - Util.arrayCopy(dataTable, (short) 0, buf, start, dataTableSize); - return dataTableSize; + short len = Util.getShort(dataTable, KM_APPLET_DATA_OFFSET); + Util.arrayCopyNonAtomic(dataTable, (short) (KM_APPLET_DATA_OFFSET + 2), buf, start, + len); + return len; } @Override @@ -60,4 +69,29 @@ public Shareable getShareableInterfaceObject(AID aid, byte param){ return null; } + @Override + public boolean isBackupAvailable() { + return backupAvailable; + } + + @Override + public void backupProviderData(byte[] buf, short start, short len) { + // Store the data + if (len > 0) { + JCSystem.beginTransaction(); + Util.arrayCopy(buf, start, dataTable, PROVIDER_OFFSET, len); + JCSystem.commitTransaction(); + } + backupAvailable = true; + } + + @Override + public short restoreProviderData(byte[] buf, short start) { + // Restore the data + short len = Util.getShort(dataTable, PROVIDER_OFFSET); + len += 2;// including length. + Util.arrayCopyNonAtomic(dataTable, PROVIDER_OFFSET, buf, start, len); + return len; + } + } diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java index 0c483334..764d4a3e 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java +++ b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java @@ -5,4 +5,7 @@ public interface KMBackupRestoreAgent extends Shareable { void backup(byte[] buf, short start, short len); short restore(byte[] buf, short start); + void backupProviderData(byte[] buf, short start, short len); + short restoreProviderData(byte[] buf, short start); + boolean isBackupAvailable(); } diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java index 5f28c014..4e851e5c 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java +++ b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java @@ -8,14 +8,18 @@ import javacard.framework.Util; public class KMBackupStoreApplet extends Applet implements KMBackupRestoreAgent { - private static final short DATA_TABLE_MEM_SIZE = 2048; + private static final short PROVIDER_MEM_SIZE = 2050; + private static final short KM_APPLET_MEM_SIZE = 2050; + private static final short PROVIDER_OFFSET = 0; + private static final short KM_APPLET_DATA_OFFSET = PROVIDER_MEM_SIZE; private static final byte[] aidArr = new byte[]{ (byte)0xA0, 0x00, 0x00, 0x00, 0x62}; private byte[] dataTable; - private short dataTableSize; + boolean backupAvailable; private KMBackupStoreApplet() { - dataTable = new byte[DATA_TABLE_MEM_SIZE]; + dataTable = new byte[KM_APPLET_MEM_SIZE + PROVIDER_MEM_SIZE]; + backupAvailable = false; } public static void install(byte bArray[], short bOffset, byte bLength) { @@ -37,17 +41,22 @@ public void backup(byte[] buf, short start, short len) { // Store the data if (len > 0) { JCSystem.beginTransaction(); - dataTableSize = len; - Util.arrayCopy(buf, start, dataTable, (short) 0, len); + // dataTableSize = len; + Util.setShort(dataTable, KM_APPLET_DATA_OFFSET, len); + Util.arrayCopy(buf, start, dataTable, + (short) (KM_APPLET_DATA_OFFSET + 2), len); JCSystem.commitTransaction(); } + backupAvailable = true; } @Override public short restore(byte[] buf, short start) { // Restore the data - Util.arrayCopy(dataTable, (short) 0, buf, start, dataTableSize); - return dataTableSize; + short len = Util.getShort(dataTable, KM_APPLET_DATA_OFFSET); + Util.arrayCopyNonAtomic(dataTable, (short) (KM_APPLET_DATA_OFFSET + 2), buf, start, + len); + return len; } @Override @@ -60,4 +69,29 @@ public Shareable getShareableInterfaceObject(AID aid, byte param){ return null; } + @Override + public boolean isBackupAvailable() { + return backupAvailable; + } + + @Override + public void backupProviderData(byte[] buf, short start, short len) { + // Store the data + if (len > 0) { + JCSystem.beginTransaction(); + Util.arrayCopy(buf, start, dataTable, PROVIDER_OFFSET, len); + JCSystem.commitTransaction(); + } + backupAvailable = true; + } + + @Override + public short restoreProviderData(byte[] buf, short start) { + // Restore the data + short len = Util.getShort(dataTable, PROVIDER_OFFSET); + len += 2;// including length. + Util.arrayCopyNonAtomic(dataTable, PROVIDER_OFFSET, buf, start, len); + return len; + } + } diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java index 0ed1430a..1cd33280 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java +++ b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java @@ -26,6 +26,7 @@ import java.security.spec.MGF1ParameterSpec; import java.security.spec.RSAPrivateKeySpec; import java.security.spec.RSAPublicKeySpec; + import javacard.framework.AID; import javacard.framework.ISO7816; import javacard.framework.ISOException; @@ -46,6 +47,7 @@ import javacard.security.Signature; import javacardx.crypto.AEADCipher; import javacardx.crypto.Cipher; + import javax.crypto.AEADBadTagException; import javax.crypto.BadPaddingException; import javax.crypto.IllegalBlockSizeException; @@ -69,7 +71,9 @@ public class KMJcardSimulator implements KMSEProvider { public static final short ENTROPY_POOL_SIZE = 16; // simulator does not support 256 bit aes keys public static final byte[] aesICV = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; private static final int AES_GCM_KEY_SIZE = 16; + private static final short CERT_CHAIN_MAX_SIZE = 2050;//First 2 bytes for length. private static final byte[] aidArr = new byte[]{ (byte)0xA0, 0x00, 0x00, 0x00, 0x63}; + public static final short NUM_OF_CERTS = 1; public static boolean jcardSim = false; @@ -81,6 +85,7 @@ public class KMJcardSimulator implements KMSEProvider { private static Cipher aesRngCipher; private static byte[] entropyPool; private static byte[] rndNum; + private byte[] certificateChain; // Implements Oracle Simulator based restricted crypto provider public KMJcardSimulator() { @@ -99,7 +104,8 @@ public KMJcardSimulator() { } aesRngKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false); // various ciphers - + //Allocate buffer for certificate chain. + certificateChain = new byte[CERT_CHAIN_MAX_SIZE]; } @@ -1250,23 +1256,65 @@ public KMAttestationCert getAttestationCert(boolean rsaCert) { @Override public void backup(byte[] buf, short start, short len) { - byte[] data = new byte[len]; - AID aid = JCSystem.lookupAID(aidArr,(short)0,(byte)aidArr.length); - KMBackupRestoreAgent backupStore = (KMBackupRestoreAgent) JCSystem.getAppletShareableInterfaceObject(aid,(byte)0); - Util.arrayCopyNonAtomic(buf,start,data,(short)0,len); - backupStore.backup(data,(short)0,len); + short certChainLen = Util.getShort(certificateChain, (short) 0); + certChainLen += 2; // including the length of certifcate. + short arrayLen = (certChainLen > len) ? certChainLen : len; + byte[] data = new byte[arrayLen]; + AID aid = JCSystem.lookupAID(aidArr, (short) 0, (byte) aidArr.length); + KMBackupRestoreAgent backupStore = (KMBackupRestoreAgent) JCSystem + .getAppletShareableInterfaceObject(aid, (byte) 0); + Util.arrayCopyNonAtomic(certificateChain, (short) 0, data, (short) 0, + certChainLen); + backupStore.backupProviderData(data, (short) 0, certChainLen); + Util.arrayCopyNonAtomic(buf, start, data, (short) 0, len); + backupStore.backup(data, (short) 0, len); } @Override public short restore(byte[] buf, short start) { - byte[] data = new byte[2200]; - AID aid = JCSystem.lookupAID(aidArr,(short)0,(byte)aidArr.length); - KMBackupRestoreAgent backupStore = (KMBackupRestoreAgent) JCSystem.getAppletShareableInterfaceObject(aid,(byte)0); - short len = backupStore.restore(data,(short)0); - Util.arrayCopyNonAtomic(data,(short)0,buf,start,len); + byte[] data = new byte[4250]; + AID aid = JCSystem.lookupAID(aidArr, (short) 0, (byte) aidArr.length); + KMBackupRestoreAgent backupStore = (KMBackupRestoreAgent) JCSystem + .getAppletShareableInterfaceObject(aid, (byte) 0); + short len = backupStore.restore(data, (short) 0); + Util.arrayCopyNonAtomic(data, (short) 0, buf, start, (short) len); + start = len; + len = backupStore.restoreProviderData(data, (short) 0); + JCSystem.beginTransaction(); + Util.arrayCopy(data, (short) 0, certificateChain, (short) 0, (short) len); + JCSystem.commitTransaction(); + return start; + } + + @Override + public boolean isBackupAvailable() { + return false; + } + + @Override + public void persistCertificateChain(byte[] buf, short offset, short len) { + JCSystem.beginTransaction(); + Util.setShort(certificateChain, (short)0, len); + Util.arrayCopyNonAtomic(buf, offset, certificateChain, (short)2, len); + JCSystem.commitTransaction(); + } + + public short readCertificateChain(byte[] buf, short offset) { + short len = Util.getShort(certificateChain, (short)0); + Util.arrayCopyNonAtomic(certificateChain, (short)2, buf, offset, len); return len; } + @Override + public short getCertificateChainLength() { + return Util.getShort(certificateChain, (short)0); + } + + @Override + public short getNumberOfCerts() { + return NUM_OF_CERTS; + } + /* private static void print (String lab, byte[] b, short s, short l){ byte[] i = new byte[l]; diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMEncoder.java b/Applet/Applet/src/com/android/javacard/keymaster/KMEncoder.java index c03e7201..8aa1dd92 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMEncoder.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMEncoder.java @@ -81,6 +81,16 @@ public short encode(short object, byte[] buffer, short startOff) { return (short)(this.startOff - startOff); } + // array{KMError.OK,Array{KMByteBlobs}} + public void encodeCertChain(byte[] buffer, short offset, short length) { + this.buffer = buffer; + this.startOff = offset; + this.length = length; + + writeMajorTypeWithLength(ARRAY_TYPE, (short) 2); // Array of 2 elements + writeByte(UINT_TYPE); // Error.OK + } + //array{KMError.OK,Array{KMByteBlobs}} public short encodeCert(byte[] certBuffer, short bufferStart, short certStart, short certLength) { this.buffer = certBuffer; diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 0c8b9cb9..24a699cb 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -16,6 +16,8 @@ package com.android.javacard.keymaster; +import java.nio.BufferOverflowException; + import javacard.framework.APDU; import javacard.framework.Applet; import javacard.framework.AppletEvent; @@ -89,12 +91,15 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe private static final byte INS_UPDATE_OPERATION_CMD = 0x20; private static final byte INS_FINISH_OPERATION_CMD = 0x21; private static final byte INS_ABORT_OPERATION_CMD = 0x22; - private static final byte INS_PROVISION_CMD = 0x23; + private static final byte INS_PROVISION_ATTEST_IDS_ROOT_KEY_CMD = 0x23; private static final byte INS_SET_BOOT_PARAMS_CMD = 0x24; private static final byte INS_DEVICE_LOCKED_CMD = 0x25; private static final byte INS_EARLY_BOOT_ENDED_CMD = 0x26; private static final byte INS_BACKUP_CMD = 0x27; private static final byte INS_RESTORE_CMD = 0x28; + private static final byte INS_PROVISION_SHARED_SECRET_CMD = 0x29; + private static final byte INS_PROVISION_CERT_CHAIN_CMD = 0x2A; + private static final byte INS_GET_CERT_CHAIN_CMD = 0x2B; // Data Dictionary items public static final byte DATA_ARRAY_SIZE = 30; @@ -176,17 +181,16 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe private static byte[] buffer; private static short bufferLength; private static short bufferStartOffset; - private static boolean provisionDone; - private static boolean setBootParamsDone; private static short[] tmpVariables; private static short[] data; + private static boolean provisionAttestIdsDone = false; + private static boolean provisionCertChainDone = false; + private static boolean provisionSharedHmacKeyDone = false; private static final short MAX_CERT_SIZE = 2048; /** Registers this applet. */ protected KMKeymasterApplet() { seProvider = KMSEProviderImpl.instance(); - provisionDone = false; - setBootParamsDone = false; byte[] buf = JCSystem.makeTransientByteArray((short) 32, JCSystem.CLEAR_ON_DESELECT); keymasterState = KMKeymasterApplet.INSTALL_STATE; data = JCSystem.makeTransientShortArray((short) DATA_ARRAY_SIZE, JCSystem.CLEAR_ON_RESET); @@ -196,9 +200,6 @@ protected KMKeymasterApplet() { seProvider.getTrueRandomNumber(buf, (short) 0, KMRepository.MASTER_KEY_SIZE); repository.initMasterKey(buf, (short)0, KMRepository.MASTER_KEY_SIZE); seProvider.newRandomNumber(buf, (short) 0, KMRepository.SHARED_SECRET_KEY_SIZE); - // Currently hmac nonce is generated once when installing the applet. - seProvider.newRandomNumber(buf, (short) 0, KMRepository.HMAC_SEED_NONCE_SIZE); - repository.initHmacNonce(buf, (short) 0, KMRepository.HMAC_SEED_NONCE_SIZE); KMType.initialize(); encoder = new KMEncoder(); decoder = new KMDecoder(); @@ -294,14 +295,33 @@ public void process(APDU apdu) { } // Validate if INS is provision command if applet is in FIRST_SELECT_STATE. if (keymasterState == KMKeymasterApplet.FIRST_SELECT_STATE) { - if ((apduIns != INS_PROVISION_CMD) && (apduIns != INS_SET_BOOT_PARAMS_CMD)) { - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); - } - if (apduIns == INS_PROVISION_CMD && provisionDone) { - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); - } - if (apduIns == INS_SET_BOOT_PARAMS_CMD && setBootParamsDone) { - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + // If the Applet is in the FIRST_SELECT_STATE, then either Provision + // Command or Restore Command is allowed. + // If there is no backup available, then only provision command is + // allowed. + // If backup available, then only restore command is allowed. + if (seProvider.isBackupAvailable()) { + if ((apduIns != INS_RESTORE_CMD)) { + ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + } + } else { + if ((apduIns != INS_PROVISION_ATTEST_IDS_ROOT_KEY_CMD) + && (apduIns != INS_PROVISION_CERT_CHAIN_CMD) + && (apduIns != INS_PROVISION_SHARED_SECRET_CMD)) { + ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + } + + if (provisionAttestIdsDone + && (apduIns == INS_PROVISION_ATTEST_IDS_ROOT_KEY_CMD)) { + ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + } + if (provisionCertChainDone && (apduIns == INS_PROVISION_CERT_CHAIN_CMD)) { + ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + } + if (provisionSharedHmacKeyDone + && (apduIns == INS_PROVISION_SHARED_SECRET_CMD)) { + ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + } } } // Process the apdu @@ -365,8 +385,14 @@ public void process(APDU apdu) { case INS_ABORT_OPERATION_CMD: processAbortOperationCmd(apdu); break; - case INS_PROVISION_CMD: - processProvisionCmd(apdu); + case INS_PROVISION_ATTEST_IDS_ROOT_KEY_CMD: + processProvisionAttestIdsAndRootKey(apdu); + break; + case INS_PROVISION_CERT_CHAIN_CMD: + processProvisionCertChainCmd(apdu); + break; + case INS_PROVISION_SHARED_SECRET_CMD: + processProvisionSharedSecretCmd(apdu); break; case INS_SET_BOOT_PARAMS_CMD: processSetBootParamsCmd(apdu); @@ -377,6 +403,9 @@ public void process(APDU apdu) { case INS_EARLY_BOOT_ENDED_CMD: processEarlyBootEndedCmd(apdu); break; + case INS_GET_CERT_CHAIN_CMD: + processGetCertChainCmd(apdu); + break; case INS_BACKUP_CMD: processBackupCmd(apdu); break; @@ -406,6 +435,7 @@ private void processRestoreCmd(APDU apdu) { short len = seProvider.restore(KMByteBlob.cast(buf).getBuffer(), KMByteBlob.cast(buf).getStartOff()); repository.restoreData(buf); + keymasterState = ACTIVE_STATE; sendError(apdu, KMError.OK); } @@ -536,7 +566,72 @@ private void processAddRngEntropyCmd(APDU apdu) { seProvider.addRngEntropy(blob.getBuffer(), blob.getStartOff(), blob.length()); } - private void processProvisionCmd(APDU apdu) { + private void processGetCertChainCmd(APDU apdu) { + // Make the response + tmpVariables[0] = seProvider.getCertificateChainLength(); + // Add arrayHeader and KMError.OK + tmpVariables[0] += 2; + tmpVariables[1] = KMByteBlob.instance(tmpVariables[0]); + buffer = KMByteBlob.cast(tmpVariables[1]).getBuffer(); + bufferStartOffset = KMByteBlob.cast(tmpVariables[1]).getStartOff(); + bufferLength = KMByteBlob.cast(tmpVariables[1]).length(); + // read the cert chain from non-volatile memory. Cert chain is already in + // CBOR format. + seProvider.readCertificateChain(buffer, (short) (bufferStartOffset + 2)); + // Encode cert chain. + encoder.encodeCertChain(buffer, bufferStartOffset, bufferLength); + sendOutgoing(apdu); + } + + private void handleStateTransition() { + if (keymasterState == KMKeymasterApplet.FIRST_SELECT_STATE) { + if (provisionAttestIdsDone && provisionCertChainDone + && provisionSharedHmacKeyDone) { + keymasterState = KMKeymasterApplet.ACTIVE_STATE; + } + } + } + + private void processProvisionSharedSecretCmd(APDU apdu) { + receiveIncoming(apdu); + // Arguments + short blob = KMByteBlob.exp(); + // Decode the argument. + short args = decoder.decode(blob, buffer, bufferStartOffset, bufferLength); + + if (KMByteBlob.cast(args).length() != KMRepository.SHARED_SECRET_KEY_SIZE) { + KMException.throwIt(KMError.INVALID_ARGUMENT); + } + // Persist shared Hmac. + repository.initHmacSharedSecretKey(KMByteBlob.cast(args).getBuffer(), + KMByteBlob.cast(args).getStartOff(), KMByteBlob.cast(args).length()); + + provisionSharedHmacKeyDone = true; + handleStateTransition(); + sendError(apdu, KMError.OK); + } + + private void processProvisionCertChainCmd(APDU apdu) { + receiveIncoming(apdu); + + tmpVariables[0] = seProvider.getNumberOfCerts(); + // Arguments + short blob = KMByteBlob.exp(); + short certChainProto = KMArray.instance(tmpVariables[0]); + for (short i = 0; i < tmpVariables[0]; i++) { + KMArray.cast(certChainProto).add((short) i, blob); + } + // Decode the argument to make sure that input is in proper CBOR format. + decoder.decode(certChainProto, buffer, bufferStartOffset, bufferLength); + + // Persist certificate chain in CBOR format. + seProvider.persistCertificateChain(buffer, bufferStartOffset, bufferLength); + provisionCertChainDone = true; + handleStateTransition(); + sendError(apdu, KMError.OK); + } + + private void processProvisionAttestIdsAndRootKey(APDU apdu) { receiveIncoming(apdu); // Re-purpose the apdu buffer as scratch pad. byte[] scratchPad = apdu.getBuffer(); @@ -544,14 +639,13 @@ private void processProvisionCmd(APDU apdu) { short keyparams = KMKeyParameters.exp(); short keyFormat = KMEnum.instance(KMType.KEY_FORMAT); short blob = KMByteBlob.exp(); - short argsProto = KMArray.instance((short) 7); + short argsProto = KMArray.instance((short) 6); KMArray.cast(argsProto).add((short) 0, keyparams); KMArray.cast(argsProto).add((short) 1, keyFormat); KMArray.cast(argsProto).add((short) 2, blob); KMArray.cast(argsProto).add((short) 3, blob); // Cert - DER encoded issuer KMArray.cast(argsProto).add((short) 4, blob); // Cert - Expiry Time KMArray.cast(argsProto).add((short) 5, blob); // Cert - Auth Key Id - KMArray.cast(argsProto).add((short) 6, blob); // Shared Hmac Key Secret // Decode the argument short args = decoder.decode(argsProto, buffer, bufferStartOffset, bufferLength); @@ -653,23 +747,9 @@ private void processProvisionCmd(APDU apdu) { saveAttId(KMType.ATTESTATION_ID_MEID); saveAttId(KMType.ATTESTATION_ID_SERIAL); - // Persist Hmac Shared Key Secret - tmpVariables[0] = KMArray.cast(args).get((short) 6); - if (KMByteBlob.cast(tmpVariables[0]).length() != KMRepository.SHARED_SECRET_KEY_SIZE) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - repository.initHmacSharedSecretKey( - KMByteBlob.cast(tmpVariables[0]).getBuffer(), - KMByteBlob.cast(tmpVariables[0]).getStartOff(), - KMByteBlob.cast(tmpVariables[0]).length()); - // Change the state to ACTIVE - if (keymasterState == KMKeymasterApplet.FIRST_SELECT_STATE) { - provisionDone = true; - if (setBootParamsDone) { - keymasterState = KMKeymasterApplet.ACTIVE_STATE; - } - } + provisionAttestIdsDone = true; + handleStateTransition(); sendError(apdu, KMError.OK); } @@ -746,10 +826,32 @@ private void processGetKeyCharacteristicsCmd(APDU apdu) { private void processGetHmacSharingParamCmd(APDU apdu) { // No Arguments + // Generate Hmac nonce only if it is not generated after reboot. + // Hmac nonce should be idempotent for the device boot session. + tmpVariables[0] = repository.alloc(KMRepository.HMAC_SEED_NONCE_SIZE); + Util.arrayFillNonAtomic(repository.getHeap(), tmpVariables[0], + KMRepository.HMAC_SEED_NONCE_SIZE, (byte) 0); + tmpVariables[1] = repository.readData(KMRepository.HMAC_NONCE); + boolean lengthMismatch = (KMRepository.HMAC_SEED_NONCE_SIZE != KMByteBlob + .cast(tmpVariables[1]).length()); + if (lengthMismatch + || (0 == Util.arrayCompare( + KMByteBlob.cast(tmpVariables[1]).getBuffer(), + KMByteBlob.cast(tmpVariables[1]).getStartOff(), + repository.getHeap(), tmpVariables[0], + KMRepository.HMAC_SEED_NONCE_SIZE))) { + // Hmac is cleared, so generate a new Hmac nonce. + seProvider.newRandomNumber(repository.getHeap(), (short) tmpVariables[0], + KMRepository.HMAC_SEED_NONCE_SIZE); + repository.initHmacNonce(repository.getHeap(), (short) tmpVariables[0], + KMRepository.HMAC_SEED_NONCE_SIZE); + } // Create HMAC Sharing Parameters tmpVariables[2] = KMHmacSharingParameters.instance(); - KMHmacSharingParameters.cast(tmpVariables[2]).setNonce(repository.getHmacNonce()); - KMHmacSharingParameters.cast(tmpVariables[2]).setSeed(KMByteBlob.instance((short) 0)); + KMHmacSharingParameters.cast(tmpVariables[2]).setNonce( + repository.getHmacNonce()); + KMHmacSharingParameters.cast(tmpVariables[2]).setSeed( + KMByteBlob.instance((short) 0)); // prepare the response tmpVariables[3] = KMArray.instance((short) 2); KMArray.cast(tmpVariables[3]).add((short) 0, KMInteger.uint_16(KMError.OK)); @@ -3247,6 +3349,11 @@ private void updateKeyParameters(byte[] ptrArr, short len) { } // TODO Add Signature verification. + // This command is executed after every reboot of Android OS. + // TODO After every reboot the first command to be executed should be + // processSetBootParams, but there is no signal/notification triggered + // inside the applet when the android device reboots. So this check is not + // implemented. private void processSetBootParamsCmd(APDU apdu) { receiveIncoming(apdu); // Argument 1 OS Version @@ -3347,14 +3454,10 @@ private void processSetBootParamsCmd(APDU apdu) { enumVal = KMEnum.cast(tmpVariables[5]).getVal(); // repository.deviceLockedFlag = (enumVal == KMType.DEVICE_LOCKED_TRUE); repository.setDeviceLock(enumVal == KMType.DEVICE_LOCKED_TRUE); - if (keymasterState == KMKeymasterApplet.FIRST_SELECT_STATE) { - setBootParamsDone = true; - if (provisionDone) { - keymasterState = KMKeymasterApplet.ACTIVE_STATE; - } - } - // end transaction - // JCSystem.commitTransaction(); + + //Clear the Computed SharedHmac and Hmac nonce from persistent memory. + repository.clearComputedHmac(); + repository.clearHmacNonce(); } private static void processGenerateKey(APDU apdu) { diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java index 04ad5f6f..6a123948 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java @@ -82,7 +82,7 @@ public class KMRepository { public static final short BOOT_STATE_SIZE = 1; public static final short MAX_BLOB_STORAGE = 8; public static final short AUTH_TAG_LENGTH = 12; - public static final short AUTH_TAG_ENTRY_SIZE = 14; + public static final short AUTH_TAG_ENTRY_SIZE = 15; public static final short MAX_OPS = 4; public static final byte BOOT_KEY_MAX_SIZE = 32; public static final byte BOOT_HASH_MAX_SIZE = 32; @@ -229,7 +229,15 @@ public void initComputedHmac(byte[] key, short start, short len) { public void initHmacNonce(byte[] nonce, short offset, short len) { if (len != HMAC_SEED_NONCE_SIZE) { KMException.throwIt(KMError.INVALID_INPUT_LENGTH);} writeDataEntry(HMAC_NONCE,nonce,offset,len); - } + } + + public void clearHmacNonce() { + clearDataEntry(HMAC_NONCE); + } + + public void clearComputedHmac() { + clearDataEntry(COMPUTED_HMAC_KEY); + } public void onUninstall() { // Javacard Runtime environment cleans up the data. @@ -297,7 +305,7 @@ private void clearDataEntry(short id){ if (dataLen != 0) { short dataPtr = Util.getShort(dataTable,(short)(id+DATA_INDEX_ENTRY_OFFSET)); Util.arrayFillNonAtomic(dataTable, dataPtr,dataLen,(byte)0); - Util.arrayFillNonAtomic(dataTable, id,DATA_INDEX_ENTRY_SIZE,(byte)0); + //Util.arrayFillNonAtomic(dataTable, id,DATA_INDEX_ENTRY_SIZE,(byte)0); } JCSystem.commitTransaction(); } @@ -355,21 +363,46 @@ public short getComputedHmacKey() { return readData(COMPUTED_HMAC_KEY); } + private byte readAuthTagState(byte[] buf, short offset) { + return buf[offset]; + } + + private void writeAuthTagState(byte[] buf, short offset, byte state) { + buf[offset] = state; + } + public void persistAuthTag(short authTag) { - if(KMByteBlob.cast(authTag).length() != AUTH_TAG_LENGTH)KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + if (KMByteBlob.cast(authTag).length() != AUTH_TAG_LENGTH) + KMException.throwIt(KMError.INVALID_INPUT_LENGTH); short authTagEntry = alloc(AUTH_TAG_ENTRY_SIZE); + short offset = alloc(AUTH_TAG_ENTRY_SIZE); + writeAuthTagState( + KMByteBlob.cast(authTagEntry).getBuffer(), + KMByteBlob.cast(authTagEntry).getStartOff(), + (byte) 1); Util.arrayCopyNonAtomic( - KMByteBlob.cast(authTag).getBuffer(), - KMByteBlob.cast(authTag).getStartOff(), - getHeap(),authTagEntry, AUTH_TAG_LENGTH); - Util.setShort(getHeap(),(short)(authTagEntry+AUTH_TAG_LENGTH),(short)0); + KMByteBlob.cast(authTag).getBuffer(), + KMByteBlob.cast(authTag).getStartOff(), + getHeap(), authTagEntry, AUTH_TAG_LENGTH); + Util.setShort(getHeap(), (short) (authTagEntry + AUTH_TAG_LENGTH +1), + (short) 0); short index = 0; while (index < MAX_BLOB_STORAGE) { - if(dataLength((short)(index+AUTH_TAG_1)) == 0){ - writeDataEntry((short)(index+AUTH_TAG_1), - KMByteBlob.cast(authTagEntry).getBuffer(), - KMByteBlob.cast(authTagEntry).getStartOff(), - AUTH_TAG_ENTRY_SIZE); + if (dataLength((short) (index + AUTH_TAG_1)) != 0) { + readDataEntry((short) (index + AUTH_TAG_1), getHeap(), offset); + if (0 == readAuthTagState(getHeap(), offset)) { + writeDataEntry((short) (index + AUTH_TAG_1), + KMByteBlob.cast(authTagEntry).getBuffer(), + KMByteBlob.cast(authTagEntry).getStartOff(), + AUTH_TAG_ENTRY_SIZE); + break; + } + } else { + writeDataEntry((short) (index + AUTH_TAG_1), + KMByteBlob.cast(authTagEntry).getBuffer(), + KMByteBlob.cast(authTagEntry).getStartOff(), + AUTH_TAG_ENTRY_SIZE); + break; } index++; } @@ -397,15 +430,16 @@ public void removeAllAuthTags() { private short findTag(short authTag) { if(KMByteBlob.cast(authTag).length() != AUTH_TAG_LENGTH)KMException.throwIt(KMError.INVALID_INPUT_LENGTH); short index = 0; - short authTagEntry; short found; + short offset = alloc(AUTH_TAG_ENTRY_SIZE); while (index < MAX_BLOB_STORAGE) { if (dataLength((short)(index+AUTH_TAG_1)) != 0) { - authTagEntry = readData((short)(index+AUTH_TAG_1)); + readDataEntry((short)(index+AUTH_TAG_1), + getHeap(), offset); found = Util.arrayCompare( - KMByteBlob.cast(authTagEntry).getBuffer(), - KMByteBlob.cast(authTagEntry).getStartOff(), + getHeap(), + (short)(offset+1), KMByteBlob.cast(authTag).getBuffer(), KMByteBlob.cast(authTag).getStartOff(), AUTH_TAG_LENGTH); @@ -422,18 +456,23 @@ public short getRateLimitedKeyCount(short authTag) { if (tag != KMType.INVALID_VALUE) { blob = readData(tag); return Util.getShort(KMByteBlob.cast(blob).getBuffer(), - (short)(KMByteBlob.cast(blob).getStartOff()+AUTH_TAG_LENGTH)); + (short)(KMByteBlob.cast(blob).getStartOff()+AUTH_TAG_LENGTH+1)); } return KMType.INVALID_VALUE; } public void setRateLimitedKeyCount(short authTag, short val) { short tag = findTag(authTag); - short blob; if (tag != KMType.INVALID_VALUE) { - blob = alloc((short)2); - Util.setShort(getHeap(),blob,val); - writeDataEntry(tag,getHeap(), blob,(short)2); + short dataPtr = readData(tag); + Util.setShort( + KMByteBlob.cast(dataPtr).getBuffer(), + (short)(KMByteBlob.cast(dataPtr).getStartOff()+AUTH_TAG_LENGTH+1), + val); + writeDataEntry(tag, + KMByteBlob.cast(dataPtr).getBuffer(), + KMByteBlob.cast(dataPtr).getStartOff(), + KMByteBlob.cast(dataPtr).length()); } } @@ -602,6 +641,7 @@ public void setVerifiedBootKey(byte[] buf, short start, short len){ writeDataEntry(BOOT_VERIFIED_BOOT_KEY,buf,start,len); } + public void setVerifiedBootHash(byte[] buf, short start, short len){ if(len > BOOT_HASH_MAX_SIZE) KMException.throwIt(KMError.INVALID_INPUT_LENGTH); writeDataEntry(BOOT_VERIFIED_BOOT_HASH,buf,start,len); diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java b/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java index ff8c6c92..508f9d06 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java @@ -461,4 +461,44 @@ KMOperation initAsymmetricOperation( * @return the length of the data buffer in bytes. */ short restore(byte[] buf, short start); + + /** + * This operation returns true if backup is available, otherwise false + * if backup is not available. + * + * @return true if backup is available, false if no backup. + */ + boolean isBackupAvailable(); + + /** + * This operation persists the certificate chain in the persistent memory. + * + * @param buf buffer containing certificate chain. + * @param offset is the start of the buffer. + * @param len is the length of the buffer. + */ + void persistCertificateChain(byte[] buf, short offset, short len); + + /** + * The operation reads the certificate chain from persistent memory. + * + * @param buf is the start of data buffer. + * @param offset is the start of the data. + * @return the length of the data buffer in bytes. + */ + short readCertificateChain(byte[] buf, short offset); + + /** + * This function returns the cert chain length. + * + * @return length of the certificate chain. + */ + short getCertificateChainLength(); + + /** + * This function returns the number certificates in the cert chain. + * + * @return the number of certificates in cert chain. + */ + short getNumberOfCerts(); } From 153562bdd12d50fc6cee9a5292ebaf46b9f15943 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Mon, 9 Nov 2020 22:10:02 +0000 Subject: [PATCH 11/42] Divided single provision command into sub functions 1. Provision Attestation IDs and Root key. 2. Provision Root certificate 3. Provision Shared secret. --- .../4.1/JavacardKeymaster4Device.cpp | 116 +++++++++++++++--- HAL/keymaster/Android.bp | 4 +- 2 files changed, 101 insertions(+), 19 deletions(-) diff --git a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp index c2775de6..501880a8 100644 --- a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp +++ b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp @@ -82,10 +82,15 @@ enum class Instruction { INS_UPDATE_OPERATION_CMD = 0x20, INS_FINISH_OPERATION_CMD = 0x21, INS_ABORT_OPERATION_CMD = 0x22, - INS_PROVISION_CMD = 0x23, + INS_PROVISION_ATTEST_IDS_ROOT_KEY_CMD = 0x23, INS_SET_BOOT_PARAMS_CMD = 0x24, INS_DEVICE_LOCKED_CMD = 0x25, INS_EARLY_BOOT_ENDED_CMD = 0x26, + INS_BACKUP_CMD = 0x27, + INS_RESTORE_CMD = 0x28, + INS_PROVISION_SHARED_SECRET_CMD = 0x29, + INS_PROVISION_CERT_CHAIN_CMD = 0x2A, + INS_GET_CERT_CHAIN_CMD = 0x2B }; static inline std::unique_ptr& getTransportFactoryInstance() { @@ -316,7 +321,8 @@ keyFormat, std::vector& wrappedKeyDescription) { return ErrorCode::OK; } -ErrorCode constructApduMessage(Instruction& ins, std::vector& inputData, std::vector& apduOut) { +ErrorCode constructApduMessage(Instruction& ins, std::vector& inputData, std::vector& apduOut, bool +extendedOutput=false) { apduOut.push_back(static_cast(APDU_CLS)); //CLS apduOut.push_back(static_cast(ins)); //INS apduOut.push_back(static_cast(APDU_P1)); //P1 @@ -341,6 +347,8 @@ ErrorCode constructApduMessage(Instruction& ins, std::vector& inputData apduOut.insert(apduOut.end(), inputData.begin(), inputData.end()); //Expected length of output apduOut.push_back(static_cast(0x00));//Accepting complete length of output at a time + if(extendedOutput) + apduOut.push_back(static_cast(0x00)); } else { return (ErrorCode::INSUFFICIENT_BUFFER_SPACE); @@ -396,24 +404,26 @@ Return setBootParams() { KM_VERIFIED_BOOT_UNVERIFIED, 0/*deviceLocked*/); } -ErrorCode sendData(Instruction ins, std::vector& inData, std::vector& response) { +ErrorCode sendData(Instruction ins, std::vector& inData, std::vector& response, bool +extendedOutput=false) { ErrorCode ret = ErrorCode::UNKNOWN_ERROR; std::vector apdu; if(!android::base::GetBoolProperty(KM_JAVACARD_PROVISIONED_PROPERTY, false)) { - if(ErrorCode::OK != (ret = setBootParams())) { - LOG(ERROR) << "Failed to set boot params"; - return ret; - } if(ErrorCode::OK != (ret = initiateProvision())) { LOG(ERROR) << "Failed to provision the device"; return ret; } + + if(ErrorCode::OK != (ret = setBootParams())) { + LOG(ERROR) << "Failed to set boot params"; + return ret; + } android::base::SetProperty(KM_JAVACARD_PROVISIONED_PROPERTY, "true"); } - ret = constructApduMessage(ins, inData, apdu); + ret = constructApduMessage(ins, inData, apdu, extendedOutput); if(ret != ErrorCode::OK) return ret; if(!getTransportFactoryInstance()->sendData(apdu.data(), apdu.size(), response)) { @@ -434,7 +444,7 @@ ErrorCode JavacardKeymaster4Device::provision(const hidl_vec& keyP std::vector apdu; hidl_vec keyBlob; ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; - Instruction ins = Instruction::INS_PROVISION_CMD; + Instruction ins = Instruction::INS_PROVISION_ATTEST_IDS_ROOT_KEY_CMD; std::vector response; CborConverter cborConverter; X509 *x509 = NULL; @@ -471,7 +481,6 @@ ErrorCode JavacardKeymaster4Device::provision(const hidl_vec& keyP array.add(subject); array.add(notAfter); array.add(authorityKeyIdentifier); - array.add(masterKey); std::vector cborData = array.encode(); if(ErrorCode::OK != (errorCode = constructApduMessage(ins, cborData, apdu))) @@ -490,6 +499,70 @@ ErrorCode JavacardKeymaster4Device::provision(const hidl_vec& keyP std::tie(item, errorCode) = cborConverter.decodeData(std::vector(response.begin(), response.end()-2), true); } + + if(ErrorCode::OK != errorCode) + return errorCode; + + //Provision master key + ins = Instruction::INS_PROVISION_SHARED_SECRET_CMD; + array = cppbor::Array(); + array.add(masterKey); + cborData = array.encode(); + apdu.clear(); + response.clear(); + + if(ErrorCode::OK != (errorCode = constructApduMessage(ins, cborData, apdu))) + return errorCode; + + if(!getTransportFactoryInstance()->sendData(apdu.data(), apdu.size(), response)) { + return (ErrorCode::SECURE_HW_COMMUNICATION_FAILED); + } + + if((response.size() < 2) || (getStatus(response) != APDU_RESP_STATUS_OK)) { + return (ErrorCode::UNKNOWN_ERROR); + } + + if((response.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter.decodeData(std::vector(response.begin(), response.end()-2), + true); + } + + if(ErrorCode::OK != errorCode) + return errorCode; + + //Provsion root certificate + ins = Instruction::INS_PROVISION_CERT_CHAIN_CMD; + std::vector certData; + array = cppbor::Array(); + subArray = cppbor::Array(); + /* Read the Root certificate */ + if(!readDataFromFile(ROOT_RSA_CERT, certData)) { + LOG(ERROR) << " Failed to read the Root certificate"; + return (ErrorCode::UNKNOWN_ERROR); + } + array.add(certData); + cborData = array.encode(); + apdu.clear(); + response.clear(); + + if(ErrorCode::OK != (errorCode = constructApduMessage(ins, cborData, apdu))) + return errorCode; + + if(!getTransportFactoryInstance()->sendData(apdu.data(), apdu.size(), response)) { + return (ErrorCode::SECURE_HW_COMMUNICATION_FAILED); + } + + if((response.size() < 2) || (getStatus(response) != APDU_RESP_STATUS_OK)) { + return (ErrorCode::UNKNOWN_ERROR); + } + + if((response.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter.decodeData(std::vector(response.begin(), response.end()-2), + true); + } + return errorCode; } @@ -933,14 +1006,23 @@ Return JavacardKeymaster4Device::attestKey(const hidl_vec& keyToA if(!cborConverter_.getMultiBinaryArray(item, 1, temp)) { errorCode = ErrorCode::UNKNOWN_ERROR; } else { - if(readDataFromFile(ROOT_RSA_CERT, rootCert)) { - temp.push_back(std::move(rootCert)); - certChain.resize(temp.size()); - for(int i = 0; i < temp.size(); i++) { - certChain[i] = temp[i]; + cborData.clear(); + cborOutData.clear(); + errorCode = sendData(Instruction::INS_GET_CERT_CHAIN_CMD, cborData, cborOutData, true); + if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), + true); + if (item != nullptr) { + if(!cborConverter_.getMultiBinaryArray(item, 1, temp)) { + errorCode = ErrorCode::UNKNOWN_ERROR; + } else { + certChain.resize(temp.size()); + for(int i = 0; i < temp.size(); i++) { + certChain[i] = temp[i]; + } + } } - } else { - LOG(ERROR) << "No root certificate found"; } } } diff --git a/HAL/keymaster/Android.bp b/HAL/keymaster/Android.bp index ef67cb6e..9f42df54 100644 --- a/HAL/keymaster/Android.bp +++ b/HAL/keymaster/Android.bp @@ -42,7 +42,7 @@ cc_binary { "libsoftkeymasterdevice", "libkeymaster_messages", "libkeymaster_portable", - "libcppbor_external", + "libcppbor", "android.hardware.keymaster@4.1", "android.hardware.keymaster@4.0", "libjc_transport", @@ -73,7 +73,7 @@ cc_library { "libsoftkeymasterdevice", "libkeymaster_messages", "libkeymaster_portable", - "libcppbor_external", + "libcppbor", "android.hardware.keymaster@4.1", "android.hardware.keymaster@4.0", "libjc_transport", From f50decefbc3f1a7f77dd97d11012a7eb4129ae7a Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Mon, 9 Nov 2020 22:14:14 +0000 Subject: [PATCH 12/42] Fixed issues while provisioning --- .../android/javacard/keymaster/KMEncoder.java | 2 +- .../javacard/keymaster/KMKeymasterApplet.java | 23 +++++++++++++------ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMEncoder.java b/Applet/Applet/src/com/android/javacard/keymaster/KMEncoder.java index 8aa1dd92..79c246ec 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMEncoder.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMEncoder.java @@ -85,7 +85,7 @@ public short encode(short object, byte[] buffer, short startOff) { public void encodeCertChain(byte[] buffer, short offset, short length) { this.buffer = buffer; this.startOff = offset; - this.length = length; + this.length = (short)(offset+3); writeMajorTypeWithLength(ARRAY_TYPE, (short) 2); // Array of 2 elements writeByte(UINT_TYPE); // Error.OK diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 24a699cb..e553fb7e 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -290,7 +290,7 @@ public void process(APDU apdu) { ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } // Validate whether INS can be supported - if (!(apduIns >= INS_GENERATE_KEY_CMD && apduIns <= INS_RESTORE_CMD)) { + if (!(apduIns >= INS_GENERATE_KEY_CMD && apduIns <= INS_GET_CERT_CHAIN_CMD)) { ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); } // Validate if INS is provision command if applet is in FIRST_SELECT_STATE. @@ -596,15 +596,21 @@ private void processProvisionSharedSecretCmd(APDU apdu) { receiveIncoming(apdu); // Arguments short blob = KMByteBlob.exp(); + short argsProto = KMArray.instance((short) 1); + KMArray.cast(argsProto).add((short) 0, blob); // Decode the argument. - short args = decoder.decode(blob, buffer, bufferStartOffset, bufferLength); + short args = decoder.decode(argsProto, buffer, bufferStartOffset, bufferLength); - if (KMByteBlob.cast(args).length() != KMRepository.SHARED_SECRET_KEY_SIZE) { + tmpVariables[0] = KMArray.cast(args).get((short) 0); + if (tmpVariables[0] != KMType.INVALID_VALUE && + KMByteBlob.cast(tmpVariables[0]).length() != KMRepository.SHARED_SECRET_KEY_SIZE) { KMException.throwIt(KMError.INVALID_ARGUMENT); } // Persist shared Hmac. - repository.initHmacSharedSecretKey(KMByteBlob.cast(args).getBuffer(), - KMByteBlob.cast(args).getStartOff(), KMByteBlob.cast(args).length()); + repository.initHmacSharedSecretKey( + KMByteBlob.cast(tmpVariables[0]).getBuffer(), + KMByteBlob.cast(tmpVariables[0]).getStartOff(), + KMByteBlob.cast(tmpVariables[0]).length()); provisionSharedHmacKeyDone = true; handleStateTransition(); @@ -828,12 +834,15 @@ private void processGetHmacSharingParamCmd(APDU apdu) { // No Arguments // Generate Hmac nonce only if it is not generated after reboot. // Hmac nonce should be idempotent for the device boot session. + boolean lengthMismatch = false; tmpVariables[0] = repository.alloc(KMRepository.HMAC_SEED_NONCE_SIZE); Util.arrayFillNonAtomic(repository.getHeap(), tmpVariables[0], KMRepository.HMAC_SEED_NONCE_SIZE, (byte) 0); tmpVariables[1] = repository.readData(KMRepository.HMAC_NONCE); - boolean lengthMismatch = (KMRepository.HMAC_SEED_NONCE_SIZE != KMByteBlob - .cast(tmpVariables[1]).length()); + + if (tmpVariables[1] == 0) + lengthMismatch = true; + if (lengthMismatch || (0 == Util.arrayCompare( KMByteBlob.cast(tmpVariables[1]).getBuffer(), From 8bfd9844e6b47fbd5d23ed3bc19c9da7d4611de6 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Thu, 12 Nov 2020 16:33:51 +0000 Subject: [PATCH 13/42] 1. Provision certificate chain with out using extra RAM. 2. Made changes to support only EC signing key instead of RSA key. 3. Clear HMAC nonce and generate it in setBootParams. --- .../javacard/keymaster/AndroidSEProvider.java | 40 +++-- .../keymaster/KMAttestationCertImpl.java | 87 ++++------ .../javacard/keymaster/KMRsaOAEPEncoding.java | 2 +- .../keymaster/KMAttestationCertImpl.java | 87 ++++------ .../javacard/keymaster/KMJcardSimulator.java | 57 +++++-- .../javacard/keymaster/KMAttestationCert.java | 5 +- .../javacard/keymaster/KMKeymasterApplet.java | 158 +++++++++--------- .../javacard/keymaster/KMRepository.java | 67 +++----- .../javacard/keymaster/KMSEProvider.java | 44 ++--- 9 files changed, 266 insertions(+), 281 deletions(-) diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java index a0a31614..3cb719a2 100644 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java +++ b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java @@ -736,19 +736,16 @@ public short rsaDecipherOAEP256(byte[] secret, short secretStart, outputDataBuf, (short) outputDataStart); } - @Override - public short rsaSignPKCS1256(byte[] secret, short secretStart, - short secretLength, byte[] modBuffer, short modOff, short modLength, - byte[] inputDataBuf, short inputDataStart, short inputDataLength, - byte[] outputDataBuf, short outputDataStart) { + public short ecSign256(byte[] secret, short secretStart, short secretLength, + byte[] inputDataBuf, short inputDataStart, short inputDataLength, + byte[] outputDataBuf, short outputDataStart) { Signature.OneShot signer = null; try { - RSAPrivateKey key = (RSAPrivateKey) rsaKeyPair.getPrivate(); - key.setExponent(secret, secretStart, secretLength); - key.setModulus(modBuffer, modOff, modLength); + ECPrivateKey key = (ECPrivateKey) ecKeyPair.getPrivate(); + key.setS(secret, secretStart, secretLength); signer = Signature.OneShot.open(MessageDigest.ALG_SHA_256, - Signature.SIG_CIPHER_RSA, Cipher.PAD_PKCS1); + Signature.SIG_CIPHER_ECDSA, Cipher.PAD_NULL); signer.init(key, Signature.MODE_SIGN); return signer.sign(inputDataBuf, inputDataStart, inputDataLength, outputDataBuf, outputDataStart); @@ -1135,7 +1132,7 @@ public short aesCCMSign(byte[] bufIn, short bufInStart, short buffInLength, @Override public boolean isBackupRestoreSupported() { - return false; + return true; } @Override @@ -1174,7 +1171,7 @@ public short restore(byte[] buf, short start) { public boolean isBackupAvailable() { AID aid = JCSystem.lookupAID(aidArr,(short)0,(byte)aidArr.length); if(null == aid) - ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED); + return false; KMBackupRestoreAgent backupStore = (KMBackupRestoreAgent) JCSystem.getAppletShareableInterfaceObject(aid,(byte)0); return backupStore.isBackupAvailable(); } @@ -1189,6 +1186,27 @@ public short cmacKdf(byte[] keyMaterial, short keyMaterialStart, return key.getKey(keyBuf, keyStart); } + //This function supports multi-part request data. + public void persistPartialCertificateChain(byte[] buf, short offset, short len, short totalLen) { + // _____________________________________________________ + // | 2 Bytes | 1 Byte | 3 Bytes | Cert1 | 3 Bytes | Cert2|... + // |_________|________|_________|_______|_________|______| + // First two bytes holds the length of the total buffer. + // CBOR format: + // Next single byte holds the array header. + // Next 3 bytes holds the Byte array header with the cert1 length. + // Next 3 bytes holds the Byte array header with the cert2 length. + short persistedLen = Util.getShort(certificateChain, (short) 0); + if (persistedLen > totalLen) { + KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + } + JCSystem.beginTransaction(); + Util.setShort(certificateChain, (short) 0, (short) (len + persistedLen)); + Util.arrayCopyNonAtomic(buf, offset, certificateChain, + (short) (persistedLen+2), len); + JCSystem.commitTransaction(); + } + @Override public void persistCertificateChain(byte[] buf, short offset, short len) { // _____________________________________________________ diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java index 34a3b695..1d6ea2d9 100644 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -33,24 +33,22 @@ public class KMAttestationCertImpl implements KMAttestationCert { // Authority Key Identifier Extn - 2.5.29.35 private static final byte[] authKeyIdExtn = {0x06, 0x03, 0X55, 0X1D, 0X23}; - // Signature algorithm identifier - always sha256WithRSAEncryption - 1.2.840.113549.1.1.11 - // SEQUENCE of alg OBJ ID and parameters = NULL. + private static final short ECDSA_MAX_SIG_LEN = 72; + //Signature algorithm identifier - always ecdsaWithSha256 - 1.2.840.10045.4.3.2 + //SEQUENCE of alg OBJ ID and parameters = NULL. private static final byte[] X509SignAlgIdentifier = { 0x30, - 0x0D, + 0x0A, 0x06, - 0x09, + 0x08, 0x2A, (byte) 0x86, 0x48, - (byte) 0x86, - (byte) 0xF7, - 0x0D, - 0x01, - 0x01, - 0x0B, - 0x05, - 0x00 + (byte) 0xCE, + (byte) 0x3D, + 0x04, + 0x03, + 0x02 }; // Validity is not fixed field // Subject is a fixed field with only CN= Android Keystore Key - same for all the keys @@ -100,7 +98,6 @@ public class KMAttestationCertImpl implements KMAttestationCert { private static short authKey; private static short issuer; private static short signPriv; - private static short signMod; private KMAttestationCertImpl() {} @@ -143,7 +140,6 @@ private static void init() { deviceLocked = 0; authKey = 0; signPriv = 0; - signMod = 0; } @Override @@ -875,30 +871,6 @@ private static void decrementStackPtr(short cnt) { if (start > stackPtr) KMException.throwIt(KMError.UNKNOWN_ERROR); } - public static short sign( - KMSEProvider seProv, - byte[] privBuf, - short privStart, - short privLength, - byte[] modBuf, - short modStart, - short modLength) { - // short ret = signer.sign(stack,tbsOffset,tbsLength,stack,signatureOffset); - // print(getBuffer(),getCertStart(),getCertLength()); - return seProv.rsaSignPKCS1256( - privBuf, - privStart, - privLength, - modBuf, - modStart, - modLength, - stack, - tbsOffset, - tbsLength, - stack, - signatureOffset); - } - @Override public KMAttestationCert buffer(byte[] buf, short bufStart, short maxLen) { stack = buf; @@ -909,9 +881,8 @@ public KMAttestationCert buffer(byte[] buf, short bufStart, short maxLen) { } @Override - public KMAttestationCert signingKey(short privKey, short modulus) { + public KMAttestationCert signingKey(short privKey) { signPriv = privKey; - signMod = modulus; return this; } @@ -933,10 +904,9 @@ public short getCertLength() { @Override public void build() { short last = stackPtr; - decrementStackPtr((short) 256); + decrementStackPtr((short) ECDSA_MAX_SIG_LEN); signatureOffset = stackPtr; pushBitStringHeader((byte) 0, (short) (last - stackPtr)); - // signatureOffset = pushSignature(null, (short) 0, (short) 256); pushAlgorithmId(X509SignAlgIdentifier); tbsLength = stackPtr; pushTbsCert(rsaCert); @@ -944,20 +914,25 @@ public void build() { tbsLength = (short) (tbsLength - tbsOffset); pushSequenceHeader((short) (last - stackPtr)); certStart = stackPtr; - KMSEProviderImpl.instance() - .rsaSignPKCS1256( - KMByteBlob.cast(signPriv).getBuffer(), - KMByteBlob.cast(signPriv).getStartOff(), - KMByteBlob.cast(signPriv).length(), - KMByteBlob.cast(signMod).getBuffer(), - KMByteBlob.cast(signMod).getStartOff(), - KMByteBlob.cast(signMod).length(), - stack, - tbsOffset, - tbsLength, - stack, - signatureOffset); - // print(stack, stackPtr, (short)(last - stackPtr)); + short sigLen = KMSEProviderImpl.instance() + .ecSign256( + KMByteBlob.cast(signPriv).getBuffer(), + KMByteBlob.cast(signPriv).getStartOff(), + KMByteBlob.cast(signPriv).length(), + stack, + tbsOffset, + tbsLength, + stack, + signatureOffset); + if(sigLen != ECDSA_MAX_SIG_LEN) { + // Update the lengths appropriately. + stackPtr = (short)(signatureOffset - 1); + pushLength((short)(sigLen + 1)); + stackPtr = tbsOffset; + last -= (short)(ECDSA_MAX_SIG_LEN - sigLen); + pushLength((short)(last - stackPtr)); + length -= (short)(ECDSA_MAX_SIG_LEN - sigLen); + } } /* private static void print(byte[] buf, short start, short length){ diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMRsaOAEPEncoding.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMRsaOAEPEncoding.java index 159f62d0..aa35793f 100644 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMRsaOAEPEncoding.java +++ b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMRsaOAEPEncoding.java @@ -170,7 +170,7 @@ private short rsaOAEPDecode(byte[] encodedMsg, short encodedMsgOff, try { short hLen = getDigestLength(); - if (encodedMsgLen < (2 * hLen + 1)) { + if (encodedMsgLen < (short)(2 * hLen + 1)) { CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } // encodedMsg will be in the format of maskedSeed||maskedDB. diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java index 34a3b695..1d6ea2d9 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -33,24 +33,22 @@ public class KMAttestationCertImpl implements KMAttestationCert { // Authority Key Identifier Extn - 2.5.29.35 private static final byte[] authKeyIdExtn = {0x06, 0x03, 0X55, 0X1D, 0X23}; - // Signature algorithm identifier - always sha256WithRSAEncryption - 1.2.840.113549.1.1.11 - // SEQUENCE of alg OBJ ID and parameters = NULL. + private static final short ECDSA_MAX_SIG_LEN = 72; + //Signature algorithm identifier - always ecdsaWithSha256 - 1.2.840.10045.4.3.2 + //SEQUENCE of alg OBJ ID and parameters = NULL. private static final byte[] X509SignAlgIdentifier = { 0x30, - 0x0D, + 0x0A, 0x06, - 0x09, + 0x08, 0x2A, (byte) 0x86, 0x48, - (byte) 0x86, - (byte) 0xF7, - 0x0D, - 0x01, - 0x01, - 0x0B, - 0x05, - 0x00 + (byte) 0xCE, + (byte) 0x3D, + 0x04, + 0x03, + 0x02 }; // Validity is not fixed field // Subject is a fixed field with only CN= Android Keystore Key - same for all the keys @@ -100,7 +98,6 @@ public class KMAttestationCertImpl implements KMAttestationCert { private static short authKey; private static short issuer; private static short signPriv; - private static short signMod; private KMAttestationCertImpl() {} @@ -143,7 +140,6 @@ private static void init() { deviceLocked = 0; authKey = 0; signPriv = 0; - signMod = 0; } @Override @@ -875,30 +871,6 @@ private static void decrementStackPtr(short cnt) { if (start > stackPtr) KMException.throwIt(KMError.UNKNOWN_ERROR); } - public static short sign( - KMSEProvider seProv, - byte[] privBuf, - short privStart, - short privLength, - byte[] modBuf, - short modStart, - short modLength) { - // short ret = signer.sign(stack,tbsOffset,tbsLength,stack,signatureOffset); - // print(getBuffer(),getCertStart(),getCertLength()); - return seProv.rsaSignPKCS1256( - privBuf, - privStart, - privLength, - modBuf, - modStart, - modLength, - stack, - tbsOffset, - tbsLength, - stack, - signatureOffset); - } - @Override public KMAttestationCert buffer(byte[] buf, short bufStart, short maxLen) { stack = buf; @@ -909,9 +881,8 @@ public KMAttestationCert buffer(byte[] buf, short bufStart, short maxLen) { } @Override - public KMAttestationCert signingKey(short privKey, short modulus) { + public KMAttestationCert signingKey(short privKey) { signPriv = privKey; - signMod = modulus; return this; } @@ -933,10 +904,9 @@ public short getCertLength() { @Override public void build() { short last = stackPtr; - decrementStackPtr((short) 256); + decrementStackPtr((short) ECDSA_MAX_SIG_LEN); signatureOffset = stackPtr; pushBitStringHeader((byte) 0, (short) (last - stackPtr)); - // signatureOffset = pushSignature(null, (short) 0, (short) 256); pushAlgorithmId(X509SignAlgIdentifier); tbsLength = stackPtr; pushTbsCert(rsaCert); @@ -944,20 +914,25 @@ public void build() { tbsLength = (short) (tbsLength - tbsOffset); pushSequenceHeader((short) (last - stackPtr)); certStart = stackPtr; - KMSEProviderImpl.instance() - .rsaSignPKCS1256( - KMByteBlob.cast(signPriv).getBuffer(), - KMByteBlob.cast(signPriv).getStartOff(), - KMByteBlob.cast(signPriv).length(), - KMByteBlob.cast(signMod).getBuffer(), - KMByteBlob.cast(signMod).getStartOff(), - KMByteBlob.cast(signMod).length(), - stack, - tbsOffset, - tbsLength, - stack, - signatureOffset); - // print(stack, stackPtr, (short)(last - stackPtr)); + short sigLen = KMSEProviderImpl.instance() + .ecSign256( + KMByteBlob.cast(signPriv).getBuffer(), + KMByteBlob.cast(signPriv).getStartOff(), + KMByteBlob.cast(signPriv).length(), + stack, + tbsOffset, + tbsLength, + stack, + signatureOffset); + if(sigLen != ECDSA_MAX_SIG_LEN) { + // Update the lengths appropriately. + stackPtr = (short)(signatureOffset - 1); + pushLength((short)(sigLen + 1)); + stackPtr = tbsOffset; + last -= (short)(ECDSA_MAX_SIG_LEN - sigLen); + pushLength((short)(last - stackPtr)); + length -= (short)(ECDSA_MAX_SIG_LEN - sigLen); + } } /* private static void print(byte[] buf, short start, short length){ diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java index 1cd33280..f3f2747d 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java +++ b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java @@ -41,6 +41,7 @@ import javacard.security.Key; import javacard.security.KeyBuilder; import javacard.security.KeyPair; +import javacard.security.MessageDigest; import javacard.security.RSAPrivateKey; import javacard.security.RSAPublicKey; import javacard.security.RandomData; @@ -572,17 +573,6 @@ public short rsaDecipherOAEP256(byte[] secret, short secretStart, short secretLe inputDataBuf, inputDataStart, inputDataLength, outputDataBuf, outputDataStart); } - @Override - public short rsaSignPKCS1256(byte[] secret, short secretStart, short secretLength, - byte[] modBuffer, short modOff, short modLength, - byte[] inputDataBuf, short inputDataStart, short inputDataLength, - byte[] outputDataBuf, short outputDataStart) { - Signature signer = createRsaSigner( - KMType.SHA2_256, KMType.RSA_PKCS1_1_5_SIGN, secret,secretStart,secretLength, modBuffer,modOff,modLength); - return signer.sign( - inputDataBuf, inputDataStart, inputDataLength, outputDataBuf, outputDataStart); - } - @Override public KMOperation initSymmetricOperation(byte purpose, byte alg, byte digest, byte padding, byte blockMode, byte[] keyBuf, short keyStart, short keyLength, @@ -1315,6 +1305,51 @@ public short getNumberOfCerts() { return NUM_OF_CERTS; } + + @Override + public short ecSign256(byte[] secret, short secretStart, short secretLength, + byte[] inputDataBuf, short inputDataStart, short inputDataLength, + byte[] outputDataBuf, short outputDataStart) { + Signature.OneShot signer = null; + try { + ECPrivateKey key = (ECPrivateKey) KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PRIVATE, KeyBuilder.LENGTH_EC_FP_256, false); + key.setS(secret, secretStart, secretLength); + + signer = Signature.OneShot.open(MessageDigest.ALG_SHA_256, + Signature.SIG_CIPHER_ECDSA, Cipher.PAD_NULL); + signer.init(key, Signature.MODE_SIGN); + return signer.sign(inputDataBuf, inputDataStart, inputDataLength, + outputDataBuf, outputDataStart); + } finally { + if (signer != null) + signer.close(); + } + + } + + + @Override + public void persistPartialCertificateChain(byte[] buf, short offset, + short len, short totalLen) { + // _____________________________________________________ + // | 2 Bytes | 1 Byte | 3 Bytes | Cert1 | 3 Bytes | Cert2|... + // |_________|________|_________|_______|_________|______| + // First two bytes holds the length of the total buffer. + // CBOR format: + // Next single byte holds the array header. + // Next 3 bytes holds the Byte array header with the cert1 length. + // Next 3 bytes holds the Byte array header with the cert2 length. + short persistedLen = Util.getShort(certificateChain, (short) 0); + if (persistedLen > totalLen) { + KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + } + JCSystem.beginTransaction(); + Util.setShort(certificateChain, (short) 0, (short) (len + persistedLen)); + Util.arrayCopyNonAtomic(buf, offset, certificateChain, + (short) (persistedLen+2), len); + JCSystem.commitTransaction(); + } + /* private static void print (String lab, byte[] b, short s, short l){ byte[] i = new byte[l]; diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java b/Applet/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java index 07c68357..cb9e4e15 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java @@ -121,11 +121,10 @@ public interface KMAttestationCert { /** * Set signing key to be used to sign the cert. * - * @param privateKey Ths is rsa 2048 bit private key. - * @param modulus Ths is rsa 2048 bit modulus. + * @param privateKey This is ECPrivateKey with curve P-256. * @return instance of KMAttestationCert */ - KMAttestationCert signingKey(short privateKey, short modulus); + KMAttestationCert signingKey(short privateKey); /** * Get the start of the certificate diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index e553fb7e..024746e1 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -16,8 +16,6 @@ package com.android.javacard.keymaster; -import java.nio.BufferOverflowException; - import javacard.framework.APDU; import javacard.framework.Applet; import javacard.framework.AppletEvent; @@ -183,9 +181,8 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe private static short bufferStartOffset; private static short[] tmpVariables; private static short[] data; - private static boolean provisionAttestIdsDone = false; - private static boolean provisionCertChainDone = false; - private static boolean provisionSharedHmacKeyDone = false; + //Once provision is done this value becomes 0x07. + private byte provisionDone = 0x00; private static final short MAX_CERT_SIZE = 2048; /** Registers this applet. */ @@ -310,16 +307,16 @@ public void process(APDU apdu) { && (apduIns != INS_PROVISION_SHARED_SECRET_CMD)) { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } - - if (provisionAttestIdsDone + if (((provisionDone & 0x01) == 0x01) && (apduIns == INS_PROVISION_ATTEST_IDS_ROOT_KEY_CMD)) { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } - if (provisionCertChainDone && (apduIns == INS_PROVISION_CERT_CHAIN_CMD)) { + if (((provisionDone & 0x02) == 0x02) + && (apduIns == INS_PROVISION_SHARED_SECRET_CMD)) { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } - if (provisionSharedHmacKeyDone - && (apduIns == INS_PROVISION_SHARED_SECRET_CMD)) { + if (((provisionDone & 0x04) == 0x04) + && (apduIns == INS_PROVISION_CERT_CHAIN_CMD)) { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } } @@ -429,7 +426,7 @@ public void process(APDU apdu) { private void processRestoreCmd(APDU apdu) { // No arguments - if (seProvider.isBackupRestoreSupported()) sendError(apdu, KMError.UNIMPLEMENTED); + if (!seProvider.isBackupRestoreSupported()) sendError(apdu, KMError.UNIMPLEMENTED); byte[] data = repository.getDataTable(); short buf = KMByteBlob.instance((short) data.length); short len = @@ -441,7 +438,7 @@ private void processRestoreCmd(APDU apdu) { private void processBackupCmd(APDU apdu) { // No arguments - if (seProvider.isBackupRestoreSupported()) sendError(apdu, KMError.UNIMPLEMENTED); + if (!seProvider.isBackupRestoreSupported()) sendError(apdu, KMError.UNIMPLEMENTED); byte[] data = repository.getDataTable(); seProvider.backup(data, (short) 0, (short) data.length); sendError(apdu, KMError.OK); @@ -585,8 +582,7 @@ private void processGetCertChainCmd(APDU apdu) { private void handleStateTransition() { if (keymasterState == KMKeymasterApplet.FIRST_SELECT_STATE) { - if (provisionAttestIdsDone && provisionCertChainDone - && provisionSharedHmacKeyDone) { + if (provisionDone == 0x07) { keymasterState = KMKeymasterApplet.ACTIVE_STATE; } } @@ -612,27 +608,62 @@ private void processProvisionSharedSecretCmd(APDU apdu) { KMByteBlob.cast(tmpVariables[0]).getStartOff(), KMByteBlob.cast(tmpVariables[0]).length()); - provisionSharedHmacKeyDone = true; + provisionDone |= 0x02; handleStateTransition(); sendError(apdu, KMError.OK); } private void processProvisionCertChainCmd(APDU apdu) { - receiveIncoming(apdu); - - tmpVariables[0] = seProvider.getNumberOfCerts(); - // Arguments - short blob = KMByteBlob.exp(); - short certChainProto = KMArray.instance(tmpVariables[0]); - for (short i = 0; i < tmpVariables[0]; i++) { - KMArray.cast(certChainProto).add((short) i, blob); + byte[] srcBuffer = apdu.getBuffer(); + short recvLen = apdu.setIncomingAndReceive(); + short srcOffset = apdu.getOffsetCdata(); + bufferLength = apdu.getIncomingLength(); + short index = bufferStartOffset; + // Receive data + if (bufferLength > MAX_IO_LENGTH) { + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } - // Decode the argument to make sure that input is in proper CBOR format. - decoder.decode(certChainProto, buffer, bufferStartOffset, bufferLength); - - // Persist certificate chain in CBOR format. - seProvider.persistCertificateChain(buffer, bufferStartOffset, bufferLength); - provisionCertChainDone = true; + short certStart = (short) (srcOffset + 1); + byte count = (byte)seProvider.getNumberOfCerts(); + while (recvLen > 0 && ((short) (index - bufferStartOffset) < bufferLength)) { + // Checking conditions - validate CBOR data. + // 1. Check that Array header contains expected number of certificates + // chain. + // 2. Check array count matches with number of array elements. + // 3. Check that each certificate length matches its actual size. + if (index == bufferStartOffset) { + // Check if the Major type is 8 + count |= 0x80; + if ((count ^ srcBuffer[srcOffset]) != (short)0) + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + } + while (certStart < (short) (srcOffset + recvLen)) { + // Check if the Major type is 4 + if ((srcBuffer[certStart] & 0xE0) != 0x40) + ISOException.throwIt(ISO7816.SW_DATA_INVALID); + // read the length of the certificate. + if ((srcBuffer[certStart] & 0x1F) != (byte) 0x18 + && (srcBuffer[certStart] & 0x1F) != (byte) 0x19) { + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + } + if ((srcBuffer[certStart] & 0x1F) == (byte) 0x18) { + tmpVariables[1] = srcBuffer[(short) (certStart + 1)]; + // cert data + certStart += 2; + } else { // 0x19 + tmpVariables[1] = Util.getShort(srcBuffer, (short) (certStart + 1)); + // cert data + certStart += 3; + } + certStart += tmpVariables[1]; + } + certStart = (short)(certStart - recvLen); + seProvider.persistPartialCertificateChain(srcBuffer, srcOffset, recvLen, + bufferLength); + index += recvLen; + recvLen = apdu.receiveBytes(srcOffset); + } + provisionDone |= 0x04; handleStateTransition(); sendError(apdu, KMError.OK); } @@ -666,9 +697,9 @@ private void processProvisionAttestIdsAndRootKey(APDU apdu) { } data[ORIGIN] = KMType.IMPORTED; - // get algorithm - only RSA keys expected + // get algorithm - only EC keys expected tmpVariables[0] = KMEnumTag.getValue(KMType.ALGORITHM, data[KEY_PARAMETERS]); - if (tmpVariables[0] != KMType.RSA) { + if (tmpVariables[0] != KMType.EC) { KMException.throwIt(KMError.INVALID_ARGUMENT); } // get digest - only SHA256 supported @@ -682,18 +713,7 @@ private void processProvisionAttestIdsAndRootKey(APDU apdu) { } else { KMException.throwIt(KMError.INVALID_ARGUMENT); } - // get padding - only PKCS1 supported - tmpVariables[0] = - KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PADDING, data[KEY_PARAMETERS]); - if (tmpVariables[0] != KMType.INVALID_VALUE) { - if (KMEnumArrayTag.cast(tmpVariables[0]).length() != 1) - KMException.throwIt(KMError.INVALID_ARGUMENT); - tmpVariables[0] = KMEnumArrayTag.cast(tmpVariables[0]).get((short) 0); - if (tmpVariables[0] != KMType.RSA_PKCS1_1_5_SIGN) - KMException.throwIt(KMError.INCOMPATIBLE_PADDING_MODE); - } else { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } + //Purpose should be ATTEST_KEY tmpVariables[0] = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PURPOSE, data[KEY_PARAMETERS]); if (tmpVariables[0] != KMType.INVALID_VALUE) { @@ -704,23 +724,11 @@ private void processProvisionAttestIdsAndRootKey(APDU apdu) { } else { KMException.throwIt(KMError.INVALID_ARGUMENT); } - tmpVariables[0] = - KMKeyParameters.findTag(KMType.UINT_TAG, KMType.KEYSIZE, data[KEY_PARAMETERS]); - if (tmpVariables[0] != KMType.INVALID_VALUE) { - tmpVariables[0] = KMIntegerTag.cast(tmpVariables[0]).getValue(); - if (KMInteger.cast(tmpVariables[0]).getSignificantShort() != 0 - || KMInteger.cast(tmpVariables[0]).getShort() != (short) 2048) { - KMException.throwIt(KMError.UNSUPPORTED_KEY_SIZE); - } - } else { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - - // Import Rsa Key - initializes data[PUB_KEY] and data[SECRET] - importRSAKey(scratchPad); + // Import EC Key - initializes data[SECRET] data[PUB_KEY] + importECKeys(scratchPad); // persist key - repository.persistAttestationKey(data[PUB_KEY], data[SECRET]); + repository.persistAttestationKey(data[SECRET]); // save issuer - DER Encoded tmpVariables[0] = KMArray.cast(args).get((short) 3); @@ -754,7 +762,7 @@ private void processProvisionAttestIdsAndRootKey(APDU apdu) { saveAttId(KMType.ATTESTATION_ID_SERIAL); // Change the state to ACTIVE - provisionAttestIdsDone = true; + provisionDone |= 0x01; handleStateTransition(); sendError(apdu, KMError.OK); } @@ -832,29 +840,6 @@ private void processGetKeyCharacteristicsCmd(APDU apdu) { private void processGetHmacSharingParamCmd(APDU apdu) { // No Arguments - // Generate Hmac nonce only if it is not generated after reboot. - // Hmac nonce should be idempotent for the device boot session. - boolean lengthMismatch = false; - tmpVariables[0] = repository.alloc(KMRepository.HMAC_SEED_NONCE_SIZE); - Util.arrayFillNonAtomic(repository.getHeap(), tmpVariables[0], - KMRepository.HMAC_SEED_NONCE_SIZE, (byte) 0); - tmpVariables[1] = repository.readData(KMRepository.HMAC_NONCE); - - if (tmpVariables[1] == 0) - lengthMismatch = true; - - if (lengthMismatch - || (0 == Util.arrayCompare( - KMByteBlob.cast(tmpVariables[1]).getBuffer(), - KMByteBlob.cast(tmpVariables[1]).getStartOff(), - repository.getHeap(), tmpVariables[0], - KMRepository.HMAC_SEED_NONCE_SIZE))) { - // Hmac is cleared, so generate a new Hmac nonce. - seProvider.newRandomNumber(repository.getHeap(), (short) tmpVariables[0], - KMRepository.HMAC_SEED_NONCE_SIZE); - repository.initHmacNonce(repository.getHeap(), (short) tmpVariables[0], - KMRepository.HMAC_SEED_NONCE_SIZE); - } // Create HMAC Sharing Parameters tmpVariables[2] = KMHmacSharingParameters.instance(); KMHmacSharingParameters.cast(tmpVariables[2]).setNonce( @@ -1375,7 +1360,7 @@ private void processAttestKeyCmd(APDU apdu) { cert.deviceLocked(repository.getDeviceLock()); cert.issuer(repository.getIssuer()); cert.publicKey(data[PUB_KEY]); - cert.signingKey(repository.getAttKeyExponent(), repository.getAttKeyModulus()); + cert.signingKey(repository.getAttKey()); cert.verifiedBootHash(repository.getVerifiedBootHash()); cert.verifiedBootKey(repository.getVerifiedBootKey()); @@ -3365,6 +3350,7 @@ private void updateKeyParameters(byte[] ptrArr, short len) { // implemented. private void processSetBootParamsCmd(APDU apdu) { receiveIncoming(apdu); + byte[] scratchPad = apdu.getBuffer(); // Argument 1 OS Version // short osVersionExp = KMIntegerTag.exp(KMType.UINT_TAG); tmpVariables[0] = KMInteger.exp(); @@ -3467,6 +3453,12 @@ private void processSetBootParamsCmd(APDU apdu) { //Clear the Computed SharedHmac and Hmac nonce from persistent memory. repository.clearComputedHmac(); repository.clearHmacNonce(); + + // Hmac is cleared, so generate a new Hmac nonce. + seProvider.newRandomNumber(scratchPad, (short) 0, + KMRepository.HMAC_SEED_NONCE_SIZE); + repository.initHmacNonce(scratchPad, (short) 0, + KMRepository.HMAC_SEED_NONCE_SIZE); } private static void processGenerateKey(APDU apdu) { diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java index 6a123948..168b6a2b 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java @@ -27,7 +27,7 @@ */ public class KMRepository { // Data table configuration - public static final short DATA_INDEX_SIZE = 32; + public static final short DATA_INDEX_SIZE = 31; public static final short DATA_INDEX_ENTRY_SIZE = 4; public static final short DATA_MEM_SIZE = 2048; public static final short HEAP_SIZE = 10000; @@ -47,32 +47,29 @@ public class KMRepository { public static final byte ATT_ID_MEID = 5; public static final byte ATT_ID_MANUFACTURER = 6; public static final byte ATT_ID_MODEL = 7; - public static final byte ATT_EXPONENT = 12; - public static final byte ATT_MODULUS = 13; - public static final byte CERT_AUTH_KEY_ID = 14; - public static final byte CERT_ISSUER = 15; - public static final byte CERT_EXPIRY_TIME = 16; - public static final byte BOOT_OS_VERSION = 17; - public static final byte BOOT_OS_PATCH = 18; - public static final byte BOOT_VERIFIED_BOOT_KEY = 19; - public static final byte BOOT_VERIFIED_BOOT_HASH = 20; - public static final byte BOOT_VERIFIED_BOOT_STATE = 21; - public static final byte BOOT_DEVICE_LOCKED_STATUS = 22; - public static final byte BOOT_DEVICE_LOCKED_TIME = 23; - public static final byte AUTH_TAG_1 = 24; - public static final byte AUTH_TAG_2 = 25; - public static final byte AUTH_TAG_3 = 26; - public static final byte AUTH_TAG_4 = 27; - public static final byte AUTH_TAG_5 = 28; - public static final byte AUTH_TAG_6 = 29; - public static final byte AUTH_TAG_7 = 30; - public static final byte AUTH_TAG_8 = 31; + public static final byte ATT_EC_KEY = 12; + public static final byte CERT_AUTH_KEY_ID = 13; + public static final byte CERT_ISSUER = 14; + public static final byte CERT_EXPIRY_TIME = 15; + public static final byte BOOT_OS_VERSION = 16; + public static final byte BOOT_OS_PATCH = 17; + public static final byte BOOT_VERIFIED_BOOT_KEY = 18; + public static final byte BOOT_VERIFIED_BOOT_HASH = 19; + public static final byte BOOT_VERIFIED_BOOT_STATE = 20; + public static final byte BOOT_DEVICE_LOCKED_STATUS = 21; + public static final byte BOOT_DEVICE_LOCKED_TIME = 22; + public static final byte AUTH_TAG_1 = 23; + public static final byte AUTH_TAG_2 = 24; + public static final byte AUTH_TAG_3 = 25; + public static final byte AUTH_TAG_4 = 26; + public static final byte AUTH_TAG_5 = 27; + public static final byte AUTH_TAG_6 = 28; + public static final byte AUTH_TAG_7 = 29; + public static final byte AUTH_TAG_8 = 30; // Data Item sizes public static final short MASTER_KEY_SIZE = 16; public static final short SHARED_SECRET_KEY_SIZE = 32; - public static final short ATT_KEY_MOD_SIZE = 256; - public static final short ATT_KEY_EXP_SIZE = 256; public static final short HMAC_SEED_NONCE_SIZE = 32; public static final short COMPUTED_HMAC_KEY_SIZE = 32; public static final short OS_VERSION_SIZE = 4; @@ -477,25 +474,15 @@ public void setRateLimitedKeyCount(short authTag, short val) { } - public void persistAttestationKey(short mod, short exp) { - if(KMByteBlob.cast(mod).length() != ATT_KEY_MOD_SIZE || - KMByteBlob.cast(exp).length() != ATT_KEY_EXP_SIZE) KMException.throwIt(KMError.UNSUPPORTED_KEY_SIZE); - writeDataEntry(ATT_MODULUS, - KMByteBlob.cast(mod).getBuffer(), - KMByteBlob.cast(mod).getStartOff(), - KMByteBlob.cast(mod).length()); - writeDataEntry(ATT_EXPONENT, - KMByteBlob.cast(exp).getBuffer(), - KMByteBlob.cast(exp).getStartOff(), - KMByteBlob.cast(exp).length()); + public void persistAttestationKey(short secret) { + writeDataEntry(ATT_EC_KEY, + KMByteBlob.cast(secret).getBuffer(), + KMByteBlob.cast(secret).getStartOff(), + KMByteBlob.cast(secret).length()); } - public short getAttKeyModulus() { - return readData(ATT_MODULUS); - } - - public short getAttKeyExponent() { - return readData(ATT_EXPONENT); + public short getAttKey() { + return readData(ATT_EC_KEY); } public void persistAttId(byte id, byte[] buf, short start, short len){ diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java b/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java index 508f9d06..2a5f96f8 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java @@ -326,15 +326,11 @@ short rsaDecipherOAEP256( short outputDataStart); /** - * This is a oneshot operation that decrypts the data using RSA algorithm with oaep256 padding. - * The public exponent is always 0x010001. + * This is a oneshot operation that signs the data using EC private key. * - * @param privExp is the private exponent (2048 bit) buffer. - * @param privExpStart is the start of the private exponent buffer. - * @param privExpLength is the length of the private exponent buffer in bytes. - * @param modBuffer is the modulus (2048 bit) buffer. - * @param modOff is the start of the modulus buffer. - * @param modLength is the length of the modulus buffer in bytes. + * @param secret is the private key of P-256 curve. + * @param secretStart is the start of the private key buffer. + * @param secretLength is the length of the private buffer in bytes. * @param inputDataBuf is the buffer of the input data. * @param inputDataStart is the start of the input data buffer. * @param inputDataLength is the length of the inpur data buffer in bytes. @@ -342,18 +338,15 @@ short rsaDecipherOAEP256( * @param outputDataStart is the start of the output data buffer. * @return length of the decrypted data. */ - short rsaSignPKCS1256( - byte[] privExp, - short privExpStart, - short privExpLength, - byte[] modBuffer, - short modOff, - short modLength, - byte[] inputDataBuf, - short inputDataStart, - short inputDataLength, - byte[] outputDataBuf, - short outputDataStart); + public short ecSign256( + byte[] secret, + short secretStart, + short secretLength, + byte[] inputDataBuf, + short inputDataStart, + short inputDataLength, + byte[] outputDataBuf, + short outputDataStart); /** * This creates a persistent operation for signing, verify, encryption and decryption using HMAC, @@ -479,6 +472,17 @@ KMOperation initAsymmetricOperation( */ void persistCertificateChain(byte[] buf, short offset, short len); + /** + * This operation persists the certificate chain in the persistent memory + * in multiple requets. + * + * @param buf buffer containing certificate chain. + * @param offset is the start of the buffer. + * @param len is the length of the buffer. + * @param totalLen is the total length of cert chain. + */ + public void persistPartialCertificateChain(byte[] buf, short offset, short len, short totalLen); + /** * The operation reads the certificate chain from persistent memory. * From 0a3e7d52dd85ce4c14767acfb07d2fe99d983146 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Mon, 16 Nov 2020 16:00:22 +0000 Subject: [PATCH 14/42] Provision functionality split into 6 separate functions --- .../javacard/keymaster/AndroidSEProvider.java | 5 + .../javacard/keymaster/KMJcardSimulator.java | 29 +-- .../javacard/keymaster/KMKeymasterApplet.java | 225 ++++++++++++------ .../javacard/keymaster/KMSEProvider.java | 7 + 4 files changed, 183 insertions(+), 83 deletions(-) diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java index 3cb719a2..1bb487b1 100644 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java +++ b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java @@ -1240,4 +1240,9 @@ public short getNumberOfCerts() { return NUM_OF_CERTS; } + @Override + public boolean isBootSignalEventSupported() { + return false; + } + } diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java index f3f2747d..4a5aa041 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java +++ b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java @@ -1310,21 +1310,16 @@ public short getNumberOfCerts() { public short ecSign256(byte[] secret, short secretStart, short secretLength, byte[] inputDataBuf, short inputDataStart, short inputDataLength, byte[] outputDataBuf, short outputDataStart) { - Signature.OneShot signer = null; - try { - ECPrivateKey key = (ECPrivateKey) KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PRIVATE, KeyBuilder.LENGTH_EC_FP_256, false); - key.setS(secret, secretStart, secretLength); - - signer = Signature.OneShot.open(MessageDigest.ALG_SHA_256, - Signature.SIG_CIPHER_ECDSA, Cipher.PAD_NULL); - signer.init(key, Signature.MODE_SIGN); - return signer.sign(inputDataBuf, inputDataStart, inputDataLength, - outputDataBuf, outputDataStart); - } finally { - if (signer != null) - signer.close(); - } + ECPrivateKey key = (ECPrivateKey) KeyBuilder.buildKey( + KeyBuilder.TYPE_EC_FP_PRIVATE, KeyBuilder.LENGTH_EC_FP_256, false); + key.setS(secret, secretStart, secretLength); + + Signature signer = Signature + .getInstance(Signature.ALG_ECDSA_SHA_256, false); + signer.init(key, Signature.MODE_SIGN); + return signer.sign(inputDataBuf, inputDataStart, inputDataLength, + outputDataBuf, outputDataStart); } @@ -1350,6 +1345,12 @@ public void persistPartialCertificateChain(byte[] buf, short offset, JCSystem.commitTransaction(); } + + @Override + public boolean isBootSignalEventSupported() { + return false; + } + /* private static void print (String lab, byte[] b, short s, short l){ byte[] i = new byte[l]; diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 024746e1..17d3f0a9 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -66,9 +66,11 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe private static final byte ILLEGAL_STATE = 0x00; private static final byte INSTALL_STATE = 0x01; private static final byte FIRST_SELECT_STATE = 0x02; - private static final byte ACTIVE_STATE = 0x03; - private static final byte INACTIVE_STATE = 0x04; - private static final byte UNINSTALLED_STATE = 0x05; + private static final byte PROVISION_SIGN_KEY_CERT_DONE = 0x03; + private static final byte BOOT_STATE = 0x04; + private static final byte ACTIVE_STATE = 0x05; + private static final byte INACTIVE_STATE = 0x06; + private static final byte UNINSTALLED_STATE = 0x07; // Commands private static final byte INS_GENERATE_KEY_CMD = 0x10; private static final byte INS_IMPORT_KEY_CMD = 0x11; @@ -89,15 +91,27 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe private static final byte INS_UPDATE_OPERATION_CMD = 0x20; private static final byte INS_FINISH_OPERATION_CMD = 0x21; private static final byte INS_ABORT_OPERATION_CMD = 0x22; - private static final byte INS_PROVISION_ATTEST_IDS_ROOT_KEY_CMD = 0x23; + private static final byte INS_PROVISION_ROOT_KEY_CMD = 0x23; private static final byte INS_SET_BOOT_PARAMS_CMD = 0x24; private static final byte INS_DEVICE_LOCKED_CMD = 0x25; private static final byte INS_EARLY_BOOT_ENDED_CMD = 0x26; private static final byte INS_BACKUP_CMD = 0x27; private static final byte INS_RESTORE_CMD = 0x28; - private static final byte INS_PROVISION_SHARED_SECRET_CMD = 0x29; - private static final byte INS_PROVISION_CERT_CHAIN_CMD = 0x2A; - private static final byte INS_GET_CERT_CHAIN_CMD = 0x2B; + private static final byte INS_PROVISION_CERT_CHAIN_CMD = 0x29; + private static final byte INS_PROVISION_CERT_PARAMS_CMD = 0x2A; + private static final byte INS_PROVISION_ATTEST_IDS = 0x2B; + private static final byte INS_PROVISION_SHARED_SECRET_CMD = 0x2C; + private static final byte INS_COMMIT_ATTESTIDS_SHARED_SECRET_CMD = 0x2D; + private static final byte INS_GET_PROVISION_STATE_CMD = 0x2E; + private static final byte INS_GET_CERT_CHAIN_CMD = 0x2F; + //Provision states + private static final byte NOT_PROVISIONED = 0x00; + private static final byte PROVISIONED_SIGN_KEY = 0x01; + private static final byte PROVISIONED_SIGN_CERT_CHAIN = 0x02; + private static final byte PROVISIONED_SIGN_CERT_PARAMS = 0x04; + private static final byte PROVISIONED_ATTEST_IDS = 0x08; + private static final byte PROVISIONED_SHARED_SECRET = 0x10; + private static final byte APPLET_PROVISIONED = 0x20; // Data Dictionary items public static final byte DATA_ARRAY_SIZE = 30; @@ -181,8 +195,7 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe private static short bufferStartOffset; private static short[] tmpVariables; private static short[] data; - //Once provision is done this value becomes 0x07. - private byte provisionDone = 0x00; + private byte provisionState = NOT_PROVISIONED; private static final short MAX_CERT_SIZE = 2048; /** Registers this applet. */ @@ -226,11 +239,6 @@ public boolean select() { keymasterState = KMKeymasterApplet.FIRST_SELECT_STATE; } else if (keymasterState == KMKeymasterApplet.INACTIVE_STATE) { keymasterState = KMKeymasterApplet.ACTIVE_STATE; - } else if (keymasterState == KMKeymasterApplet.ACTIVE_STATE || - keymasterState == KMKeymasterApplet.FIRST_SELECT_STATE) { - return true; - } else { - return false; } return true; } @@ -261,10 +269,11 @@ public void uninstall() { @Override public void process(APDU apdu) { repository.onProcess(); - // getRepository(); // Verify whether applet is in correct state. if ((keymasterState != KMKeymasterApplet.ACTIVE_STATE) - && (keymasterState != KMKeymasterApplet.FIRST_SELECT_STATE)) { + && (keymasterState != KMKeymasterApplet.FIRST_SELECT_STATE) + && (keymasterState != KMKeymasterApplet.PROVISION_SIGN_KEY_CERT_DONE) + && (keymasterState != KMKeymasterApplet.BOOT_STATE)) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } // If this is select applet apdu which is selecting this applet then return @@ -293,7 +302,7 @@ public void process(APDU apdu) { // Validate if INS is provision command if applet is in FIRST_SELECT_STATE. if (keymasterState == KMKeymasterApplet.FIRST_SELECT_STATE) { // If the Applet is in the FIRST_SELECT_STATE, then either Provision - // Command or Restore Command is allowed. + // Commands or Restore Command is allowed. // If there is no backup available, then only provision command is // allowed. // If backup available, then only restore command is allowed. @@ -302,24 +311,38 @@ public void process(APDU apdu) { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } } else { - if ((apduIns != INS_PROVISION_ATTEST_IDS_ROOT_KEY_CMD) - && (apduIns != INS_PROVISION_CERT_CHAIN_CMD) - && (apduIns != INS_PROVISION_SHARED_SECRET_CMD)) { + if ((apduIns != INS_PROVISION_ROOT_KEY_CMD) + && (apduIns != INS_PROVISION_CERT_CHAIN_CMD) + && (apduIns != INS_PROVISION_CERT_PARAMS_CMD) + && (apduIns != INS_GET_PROVISION_STATE_CMD)) { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } - if (((provisionDone & 0x01) == 0x01) - && (apduIns == INS_PROVISION_ATTEST_IDS_ROOT_KEY_CMD)) { + if (((provisionState & PROVISIONED_SIGN_KEY) == PROVISIONED_SIGN_KEY) + && (apduIns == INS_PROVISION_ROOT_KEY_CMD)) { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } - if (((provisionDone & 0x02) == 0x02) - && (apduIns == INS_PROVISION_SHARED_SECRET_CMD)) { + if (((provisionState & PROVISIONED_SIGN_CERT_CHAIN) == PROVISIONED_SIGN_CERT_CHAIN) + && (apduIns == INS_PROVISION_CERT_CHAIN_CMD)) { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } - if (((provisionDone & 0x04) == 0x04) - && (apduIns == INS_PROVISION_CERT_CHAIN_CMD)) { + if (((provisionState & PROVISIONED_SIGN_CERT_PARAMS) == PROVISIONED_SIGN_CERT_PARAMS) + && (apduIns == INS_PROVISION_CERT_PARAMS_CMD)) { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } } + } else if (keymasterState == KMKeymasterApplet.PROVISION_SIGN_KEY_CERT_DONE) { + if ((apduIns != INS_PROVISION_ATTEST_IDS) + && (apduIns != INS_PROVISION_SHARED_SECRET_CMD) + && (apduIns != INS_COMMIT_ATTESTIDS_SHARED_SECRET_CMD) + && (apduIns != INS_GET_PROVISION_STATE_CMD)) { + ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + } + } else if (keymasterState == KMKeymasterApplet.BOOT_STATE) { + if (seProvider.isBootSignalEventSupported() + && (apduIns != INS_SET_BOOT_PARAMS_CMD) + && (apduIns != INS_GET_PROVISION_STATE_CMD)) { + ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + } } // Process the apdu try { @@ -382,15 +405,27 @@ public void process(APDU apdu) { case INS_ABORT_OPERATION_CMD: processAbortOperationCmd(apdu); break; - case INS_PROVISION_ATTEST_IDS_ROOT_KEY_CMD: - processProvisionAttestIdsAndRootKey(apdu); + case INS_PROVISION_ROOT_KEY_CMD: + processProvisionRootKey(apdu); break; case INS_PROVISION_CERT_CHAIN_CMD: processProvisionCertChainCmd(apdu); break; + case INS_PROVISION_CERT_PARAMS_CMD: + processProvisionCertParams(apdu); + break; case INS_PROVISION_SHARED_SECRET_CMD: processProvisionSharedSecretCmd(apdu); break; + case INS_PROVISION_ATTEST_IDS: + processProvisionAttestIdsCmd(apdu); + break; + case INS_COMMIT_ATTESTIDS_SHARED_SECRET_CMD: + processCommitAttestIDSharedSecret(apdu); + break; + case INS_GET_PROVISION_STATE_CMD: + processGetProvisionState(apdu); + break; case INS_SET_BOOT_PARAMS_CMD: processSetBootParamsCmd(apdu); break; @@ -582,33 +617,51 @@ private void processGetCertChainCmd(APDU apdu) { private void handleStateTransition() { if (keymasterState == KMKeymasterApplet.FIRST_SELECT_STATE) { - if (provisionDone == 0x07) { - keymasterState = KMKeymasterApplet.ACTIVE_STATE; + if (provisionState == 0x07) { + keymasterState = KMKeymasterApplet.PROVISION_SIGN_KEY_CERT_DONE; } + } else if (keymasterState == KMKeymasterApplet.PROVISION_SIGN_KEY_CERT_DONE) { + if (provisionState == 0x3F) { + keymasterState = KMKeymasterApplet.BOOT_STATE; + } + } else if (keymasterState == KMKeymasterApplet.BOOT_STATE) { + keymasterState = KMKeymasterApplet.ACTIVE_STATE; } } - private void processProvisionSharedSecretCmd(APDU apdu) { + private void processProvisionCertParams(APDU apdu) { receiveIncoming(apdu); // Arguments short blob = KMByteBlob.exp(); - short argsProto = KMArray.instance((short) 1); - KMArray.cast(argsProto).add((short) 0, blob); + short argsProto = KMArray.instance((short) 3); + KMArray.cast(argsProto).add((short) 0, blob); // Cert - DER encoded issuer + KMArray.cast(argsProto).add((short) 1, blob); // Cert - Expiry Time + KMArray.cast(argsProto).add((short) 2, blob); // Cert - Auth Key Id // Decode the argument. short args = decoder.decode(argsProto, buffer, bufferStartOffset, bufferLength); + // save issuer - DER Encoded tmpVariables[0] = KMArray.cast(args).get((short) 0); - if (tmpVariables[0] != KMType.INVALID_VALUE && - KMByteBlob.cast(tmpVariables[0]).length() != KMRepository.SHARED_SECRET_KEY_SIZE) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - // Persist shared Hmac. - repository.initHmacSharedSecretKey( + repository.setIssuer( + KMByteBlob.cast(tmpVariables[0]).getBuffer(), + KMByteBlob.cast(tmpVariables[0]).getStartOff(), + KMByteBlob.cast(tmpVariables[0]).length()); + + // save expiry time - UTC or General Time - YYMMDDhhmmssZ or YYYYMMDDhhmmssZ. + tmpVariables[0] = KMArray.cast(args).get((short) 1); + repository.setCertExpiryTime( KMByteBlob.cast(tmpVariables[0]).getBuffer(), KMByteBlob.cast(tmpVariables[0]).getStartOff(), KMByteBlob.cast(tmpVariables[0]).length()); - provisionDone |= 0x02; + // Auth Key Id - from cert associated with imported attestation key. + tmpVariables[0] = KMArray.cast(args).get((short) 2); + repository.setAuthKeyId( + KMByteBlob.cast(tmpVariables[0]).getBuffer(), + KMByteBlob.cast(tmpVariables[0]).getStartOff(), + KMByteBlob.cast(tmpVariables[0]).length()); + + provisionState |= KMKeymasterApplet.PROVISIONED_SIGN_CERT_PARAMS; handleStateTransition(); sendError(apdu, KMError.OK); } @@ -626,7 +679,7 @@ private void processProvisionCertChainCmd(APDU apdu) { short certStart = (short) (srcOffset + 1); byte count = (byte)seProvider.getNumberOfCerts(); while (recvLen > 0 && ((short) (index - bufferStartOffset) < bufferLength)) { - // Checking conditions - validate CBOR data. + // Checking conditions // 1. Check that Array header contains expected number of certificates // chain. // 2. Check array count matches with number of array elements. @@ -660,15 +713,17 @@ private void processProvisionCertChainCmd(APDU apdu) { certStart = (short)(certStart - recvLen); seProvider.persistPartialCertificateChain(srcBuffer, srcOffset, recvLen, bufferLength); + //Util.arrayCopyNonAtomic(srcBuffer, srcOffset, buffer, index, recvLen); index += recvLen; recvLen = apdu.receiveBytes(srcOffset); } - provisionDone |= 0x04; + //provisionDone |= 0x04; + provisionState |= KMKeymasterApplet.PROVISIONED_SIGN_CERT_CHAIN; handleStateTransition(); sendError(apdu, KMError.OK); } - private void processProvisionAttestIdsAndRootKey(APDU apdu) { + private void processProvisionRootKey(APDU apdu) { receiveIncoming(apdu); // Re-purpose the apdu buffer as scratch pad. byte[] scratchPad = apdu.getBuffer(); @@ -676,13 +731,10 @@ private void processProvisionAttestIdsAndRootKey(APDU apdu) { short keyparams = KMKeyParameters.exp(); short keyFormat = KMEnum.instance(KMType.KEY_FORMAT); short blob = KMByteBlob.exp(); - short argsProto = KMArray.instance((short) 6); + short argsProto = KMArray.instance((short) 3); KMArray.cast(argsProto).add((short) 0, keyparams); KMArray.cast(argsProto).add((short) 1, keyFormat); KMArray.cast(argsProto).add((short) 2, blob); - KMArray.cast(argsProto).add((short) 3, blob); // Cert - DER encoded issuer - KMArray.cast(argsProto).add((short) 4, blob); // Cert - Expiry Time - KMArray.cast(argsProto).add((short) 5, blob); // Cert - Auth Key Id // Decode the argument short args = decoder.decode(argsProto, buffer, bufferStartOffset, bufferLength); @@ -730,27 +782,20 @@ private void processProvisionAttestIdsAndRootKey(APDU apdu) { // persist key repository.persistAttestationKey(data[SECRET]); - // save issuer - DER Encoded - tmpVariables[0] = KMArray.cast(args).get((short) 3); - repository.setIssuer( - KMByteBlob.cast(tmpVariables[0]).getBuffer(), - KMByteBlob.cast(tmpVariables[0]).getStartOff(), - KMByteBlob.cast(tmpVariables[0]).length()); - - // save expiry time - UTC or General Time - YYMMDDhhmmssZ or YYYYMMDDhhmmssZ. - tmpVariables[0] = KMArray.cast(args).get((short) 4); - repository.setCertExpiryTime( - KMByteBlob.cast(tmpVariables[0]).getBuffer(), - KMByteBlob.cast(tmpVariables[0]).getStartOff(), - KMByteBlob.cast(tmpVariables[0]).length()); - - // Auth Key Id - from cert associated with imported attestation key. - tmpVariables[0] = KMArray.cast(args).get((short) 5); - repository.setAuthKeyId( - KMByteBlob.cast(tmpVariables[0]).getBuffer(), - KMByteBlob.cast(tmpVariables[0]).getStartOff(), - KMByteBlob.cast(tmpVariables[0]).length()); + provisionState |= KMKeymasterApplet.PROVISIONED_SIGN_KEY; + handleStateTransition(); + sendError(apdu, KMError.OK); + } + private void processProvisionAttestIdsCmd(APDU apdu) { + receiveIncoming(apdu); + //Arguments + short keyparams = KMKeyParameters.exp(); + short argsProto = KMArray.instance((short) 1); + KMArray.cast(argsProto).add((short) 0, keyparams); + // Decode the argument. + short args = decoder.decode(argsProto, buffer, bufferStartOffset, bufferLength); + data[KEY_PARAMETERS] = KMArray.cast(args).get((short) 0); // persist attestation Ids - if any is missing then exception occurs saveAttId(KMType.ATTESTATION_ID_BRAND); saveAttId(KMType.ATTESTATION_ID_DEVICE); @@ -761,12 +806,53 @@ private void processProvisionAttestIdsAndRootKey(APDU apdu) { saveAttId(KMType.ATTESTATION_ID_MEID); saveAttId(KMType.ATTESTATION_ID_SERIAL); - // Change the state to ACTIVE - provisionDone |= 0x01; + provisionState |= KMKeymasterApplet.PROVISIONED_ATTEST_IDS; + sendError(apdu, KMError.OK); + } + + private void processProvisionSharedSecretCmd(APDU apdu) { + receiveIncoming(apdu); + // Arguments + short blob = KMByteBlob.exp(); + short argsProto = KMArray.instance((short) 1); + KMArray.cast(argsProto).add((short) 0, blob); + // Decode the argument. + short args = decoder.decode(argsProto, buffer, bufferStartOffset, bufferLength); + + tmpVariables[0] = KMArray.cast(args).get((short) 0); + if (tmpVariables[0] != KMType.INVALID_VALUE && + KMByteBlob.cast(tmpVariables[0]).length() != KMRepository.SHARED_SECRET_KEY_SIZE) { + KMException.throwIt(KMError.INVALID_ARGUMENT); + } + // Persist shared Hmac. + repository.initHmacSharedSecretKey( + KMByteBlob.cast(tmpVariables[0]).getBuffer(), + KMByteBlob.cast(tmpVariables[0]).getStartOff(), + KMByteBlob.cast(tmpVariables[0]).length()); + + provisionState |= KMKeymasterApplet.PROVISIONED_SHARED_SECRET; + sendError(apdu, KMError.OK); + } + + private void processCommitAttestIDSharedSecret(APDU apdu) { + //Check if shared secret is persisted. If not persisted throw error. + short keyBlob = repository.getSharedKey(); + if (KMByteBlob.cast(keyBlob).length() == 0) { + KMException.throwIt(KMError.KEY_NOT_YET_VALID); + } + provisionState |= KMKeymasterApplet.APPLET_PROVISIONED; handleStateTransition(); sendError(apdu, KMError.OK); } + private void processGetProvisionState(APDU apdu) { + tmpVariables[0] = KMArray.instance((short) 2); + KMArray.cast(tmpVariables[0]).add((short) 0, KMInteger.uint_16(KMError.OK)); + KMArray.cast(tmpVariables[0]).add((short) 1, KMInteger.uint_16(provisionState)); + bufferLength = encoder.encode(tmpVariables[0], buffer, bufferStartOffset); + sendOutgoing(apdu); + } + private void saveAttId(short attTag) { tmpVariables[0] = KMKeyParameters.findTag(KMType.BYTES_TAG, attTag, data[KEY_PARAMETERS]); if (tmpVariables[0] != KMType.INVALID_VALUE) { @@ -3459,6 +3545,7 @@ private void processSetBootParamsCmd(APDU apdu) { KMRepository.HMAC_SEED_NONCE_SIZE); repository.initHmacNonce(scratchPad, (short) 0, KMRepository.HMAC_SEED_NONCE_SIZE); + handleStateTransition(); } private static void processGenerateKey(APDU apdu) { diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java b/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java index 2a5f96f8..1adf798e 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java @@ -505,4 +505,11 @@ KMOperation initAsymmetricOperation( * @return the number of certificates in cert chain. */ short getNumberOfCerts(); + + /** + * This function tells if boot signal event is supported or not. + * + * @return true if supported, false otherwise. + */ + boolean isBootSignalEventSupported(); } From 64a13b90f1fa7c55df4bc343d8415cb9cd36d00c Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Wed, 18 Nov 2020 15:00:55 +0000 Subject: [PATCH 15/42] Active state should not allow provision commands --- .../javacard/keymaster/AndroidSEProvider.java | 8 ++++---- .../javacard/keymaster/KMKeymasterApplet.java | 16 ++++++++++++++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java index 1bb487b1..e170280e 100644 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java +++ b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java @@ -162,12 +162,12 @@ public class AndroidSEProvider implements KMSEProvider { //For storing root certificate and intermediate certificates. private byte[] certificateChain; - private static AndroidSEProvider sgtmProvider = null; + private static AndroidSEProvider androidSEProvider = null; public static AndroidSEProvider getInstance() { - if (sgtmProvider == null) - sgtmProvider = new AndroidSEProvider(); - return sgtmProvider; + if (androidSEProvider == null) + androidSEProvider = new AndroidSEProvider(); + return androidSEProvider; } private AndroidSEProvider() { diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 17d3f0a9..efe5f91a 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -338,11 +338,23 @@ public void process(APDU apdu) { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } } else if (keymasterState == KMKeymasterApplet.BOOT_STATE) { - if (seProvider.isBootSignalEventSupported() - && (apduIns != INS_SET_BOOT_PARAMS_CMD) + if ((apduIns != INS_SET_BOOT_PARAMS_CMD) && (apduIns != INS_GET_PROVISION_STATE_CMD)) { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } + } else {//ACTIVE_STATE + if ((apduIns == INS_PROVISION_ROOT_KEY_CMD) + || (apduIns == INS_PROVISION_CERT_CHAIN_CMD) + || (apduIns == INS_PROVISION_CERT_PARAMS_CMD) + || (apduIns == INS_PROVISION_ATTEST_IDS) + || (apduIns == INS_PROVISION_SHARED_SECRET_CMD) + || (apduIns == INS_COMMIT_ATTESTIDS_SHARED_SECRET_CMD)) { + ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + } + if (seProvider.isBootSignalEventSupported() + && (apduIns == INS_SET_BOOT_PARAMS_CMD)) { + ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + } } // Process the apdu try { From 6204fcd8facedb95e2f02cfb2047ba9f9f704f80 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Thu, 19 Nov 2020 18:45:36 +0000 Subject: [PATCH 16/42] Incorporated first level review comments in KMKeymasterApplet class 1. Renamed the state names and provision status names of the Applet. 2. Moved the validation logic of cert chain to decoder. 3. Replace nest if else with switch. --- .../android/javacard/keymaster/KMDecoder.java | 34 ++ .../javacard/keymaster/KMKeymasterApplet.java | 494 +++++++++--------- 2 files changed, 276 insertions(+), 252 deletions(-) diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMDecoder.java b/Applet/Applet/src/com/android/javacard/keymaster/KMDecoder.java index a1ced7cd..6a12379c 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMDecoder.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMDecoder.java @@ -21,6 +21,7 @@ import javacard.framework.Util; public class KMDecoder { + public static final short CONTEXT_LEN = 6; // major types private static final short UINT_TYPE = 0x00; private static final short BYTES_TYPE = 0x40; @@ -407,4 +408,37 @@ private void incrementStartOff(short inc) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } } + + // Context holds below values + // 1. number of certificates. + // 2. number of certificates read. + // 3. Relative offset from where next certificate will start. + public void incrementalReceiveAndValidateCertificateChain(byte[] context, + short contextStart, short contextLen, byte[] buf, short bufOffset, + short bufLen) { + short payLoadLength; + short index = 0; + this.buffer = buf; + this.startOff = bufOffset; + this.length = (short) (bufOffset + bufLen); + // Increment the startOff to the cert data starting location. + startOff += Util.getShort(context, (short) (contextStart + 4)); + if (0 == Util.getShort(context, contextStart)) { + payLoadLength = readMajorTypeWithPayloadLength(ARRAY_TYPE); + if (0 == payLoadLength) + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + Util.setShort(context, contextStart, payLoadLength); + } + while (startOff < length) { + if (Util.getShort(context, contextStart) <= Util.getShort(context, + (short) (contextStart + 2))) { + ISOException.throwIt(ISO7816.SW_DATA_INVALID); + } + payLoadLength = readMajorTypeWithPayloadLength(BYTES_TYPE); + Util.setShort(context, (short) (contextStart + 2), ++index); + startOff += payLoadLength; + } + Util.setShort(context, (short) (contextStart + 4), + (short) (startOff - length)); + } } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index efe5f91a..df85418c 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -64,10 +64,10 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe // Possible states of the applet. private static final byte ILLEGAL_STATE = 0x00; - private static final byte INSTALL_STATE = 0x01; + private static final byte INIT_STATE = 0x01; private static final byte FIRST_SELECT_STATE = 0x02; - private static final byte PROVISION_SIGN_KEY_CERT_DONE = 0x03; - private static final byte BOOT_STATE = 0x04; + private static final byte PROVISIONED_AKEY_ACERT_STATE = 0x03; + private static final byte PROVISIONED_AKEY_ACERT_AID_SS_STATE = 0x04; private static final byte ACTIVE_STATE = 0x05; private static final byte INACTIVE_STATE = 0x06; private static final byte UNINSTALLED_STATE = 0x07; @@ -91,27 +91,28 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe private static final byte INS_UPDATE_OPERATION_CMD = 0x20; private static final byte INS_FINISH_OPERATION_CMD = 0x21; private static final byte INS_ABORT_OPERATION_CMD = 0x22; - private static final byte INS_PROVISION_ROOT_KEY_CMD = 0x23; - private static final byte INS_SET_BOOT_PARAMS_CMD = 0x24; - private static final byte INS_DEVICE_LOCKED_CMD = 0x25; - private static final byte INS_EARLY_BOOT_ENDED_CMD = 0x26; - private static final byte INS_BACKUP_CMD = 0x27; - private static final byte INS_RESTORE_CMD = 0x28; - private static final byte INS_PROVISION_CERT_CHAIN_CMD = 0x29; - private static final byte INS_PROVISION_CERT_PARAMS_CMD = 0x2A; - private static final byte INS_PROVISION_ATTEST_IDS = 0x2B; - private static final byte INS_PROVISION_SHARED_SECRET_CMD = 0x2C; - private static final byte INS_COMMIT_ATTESTIDS_SHARED_SECRET_CMD = 0x2D; - private static final byte INS_GET_PROVISION_STATE_CMD = 0x2E; - private static final byte INS_GET_CERT_CHAIN_CMD = 0x2F; - //Provision states + private static final byte INS_SET_BOOT_PARAMS_CMD = 0x23; + private static final byte INS_DEVICE_LOCKED_CMD = 0x24; + private static final byte INS_EARLY_BOOT_ENDED_CMD = 0x25; + private static final byte INS_BACKUP_CMD = 0x26; + private static final byte INS_RESTORE_CMD = 0x27; + private static final byte INS_GET_CERT_CHAIN_CMD = 0x28; + //Instructions for Provision Commands. + private static final byte INS_PROVISION_ATTESTATION_KEY_CMD = 0x3C; + private static final byte INS_PROVISION_ATTESTATION_CERT_CHAIN_CMD = 0x3D; + private static final byte INS_PROVISION_ATTESTATION_CERT_PARAMS_CMD = 0x3E; + private static final byte INS_PROVISION_ATTEST_IDS_CMD = 0x3F; + private static final byte INS_PROVISION_SHARED_SECRET_CMD = 0x40; + private static final byte INS_COMMIT_ATTESTIDS_SHARED_SECRET_CMD = 0x41; + private static final byte INS_GET_PROVISION_STATUS_CMD = 0x42; + //Provision reporting status private static final byte NOT_PROVISIONED = 0x00; - private static final byte PROVISIONED_SIGN_KEY = 0x01; - private static final byte PROVISIONED_SIGN_CERT_CHAIN = 0x02; - private static final byte PROVISIONED_SIGN_CERT_PARAMS = 0x04; - private static final byte PROVISIONED_ATTEST_IDS = 0x08; - private static final byte PROVISIONED_SHARED_SECRET = 0x10; - private static final byte APPLET_PROVISIONED = 0x20; + private static final byte PROVISION_STATUS_SIGN_KEY = 0x01; + private static final byte PROVISION_STATUS_SIGN_CERT_CHAIN = 0x02; + private static final byte PROVISION_STATUS_SIGN_CERT_PARAMS = 0x04; + private static final byte PROVISION_STATUS_ATTEST_IDS = 0x08; + private static final byte PROVISION_STATUS_SHARED_SECRET = 0x10; + private static final byte PROVISION_STATUS_APPLET_PROVISIONED = 0x20; // Data Dictionary items public static final byte DATA_ARRAY_SIZE = 30; @@ -195,20 +196,20 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe private static short bufferStartOffset; private static short[] tmpVariables; private static short[] data; - private byte provisionState = NOT_PROVISIONED; + private byte provisionStatus = NOT_PROVISIONED; private static final short MAX_CERT_SIZE = 2048; /** Registers this applet. */ protected KMKeymasterApplet() { seProvider = KMSEProviderImpl.instance(); byte[] buf = JCSystem.makeTransientByteArray((short) 32, JCSystem.CLEAR_ON_DESELECT); - keymasterState = KMKeymasterApplet.INSTALL_STATE; + keymasterState = KMKeymasterApplet.INIT_STATE; data = JCSystem.makeTransientShortArray((short) DATA_ARRAY_SIZE, JCSystem.CLEAR_ON_RESET); repository = new KMRepository(); tmpVariables = JCSystem.makeTransientShortArray((short) TMP_VARIABLE_ARRAY_SIZE, JCSystem.CLEAR_ON_RESET); seProvider.getTrueRandomNumber(buf, (short) 0, KMRepository.MASTER_KEY_SIZE); - repository.initMasterKey(buf, (short)0, KMRepository.MASTER_KEY_SIZE); + repository.initMasterKey(buf, (short) 0, KMRepository.MASTER_KEY_SIZE); seProvider.newRandomNumber(buf, (short) 0, KMRepository.SHARED_SECRET_KEY_SIZE); KMType.initialize(); encoder = new KMEncoder(); @@ -235,7 +236,7 @@ public static void install(byte[] bArray, short bOffset, byte bLength) { @Override public boolean select() { repository.onSelect(); - if (keymasterState == KMKeymasterApplet.INSTALL_STATE) { + if (keymasterState == KMKeymasterApplet.INIT_STATE) { keymasterState = KMKeymasterApplet.FIRST_SELECT_STATE; } else if (keymasterState == KMKeymasterApplet.INACTIVE_STATE) { keymasterState = KMKeymasterApplet.ACTIVE_STATE; @@ -270,10 +271,10 @@ public void uninstall() { public void process(APDU apdu) { repository.onProcess(); // Verify whether applet is in correct state. - if ((keymasterState != KMKeymasterApplet.ACTIVE_STATE) - && (keymasterState != KMKeymasterApplet.FIRST_SELECT_STATE) - && (keymasterState != KMKeymasterApplet.PROVISION_SIGN_KEY_CERT_DONE) - && (keymasterState != KMKeymasterApplet.BOOT_STATE)) { + if ((keymasterState == KMKeymasterApplet.INIT_STATE) + || (keymasterState == KMKeymasterApplet.INACTIVE_STATE) + || (keymasterState == KMKeymasterApplet.ILLEGAL_STATE) + || (keymasterState == KMKeymasterApplet.UNINSTALLED_STATE)) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } // If this is select applet apdu which is selecting this applet then return @@ -292,173 +293,182 @@ public void process(APDU apdu) { // Validate APDU Header. if ((apduClass != CLA_ISO7816_NO_SM_NO_CHAN)) { ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED); - } else if (P1P2 != KMKeymasterApplet.KM_HAL_VERSION) { + } + + if (P1P2 != KMKeymasterApplet.KM_HAL_VERSION) { ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } // Validate whether INS can be supported - if (!(apduIns >= INS_GENERATE_KEY_CMD && apduIns <= INS_GET_CERT_CHAIN_CMD)) { + if (!(apduIns >= INS_GENERATE_KEY_CMD && apduIns <= INS_GET_PROVISION_STATUS_CMD)) { ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); } - // Validate if INS is provision command if applet is in FIRST_SELECT_STATE. - if (keymasterState == KMKeymasterApplet.FIRST_SELECT_STATE) { - // If the Applet is in the FIRST_SELECT_STATE, then either Provision - // Commands or Restore Command is allowed. - // If there is no backup available, then only provision command is - // allowed. - // If backup available, then only restore command is allowed. - if (seProvider.isBackupAvailable()) { - if ((apduIns != INS_RESTORE_CMD)) { - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + // Process the apdu + try { + // Validate if INS is provision command if applet is in + // FIRST_SELECT_STATE. + if (keymasterState == KMKeymasterApplet.FIRST_SELECT_STATE) { + // If the Applet is in the FIRST_SELECT_STATE, then either Provision + // Commands or Restore Command is allowed. + // If there is no backup available, then only provision command is + // allowed. + // If backup available, then only restore command is allowed. + if (seProvider.isBackupAvailable()) { + if ((apduIns != INS_RESTORE_CMD)) { + ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + } + } else { + switch (apduIns) { + case INS_PROVISION_ATTESTATION_KEY_CMD: { + if ((provisionStatus & PROVISION_STATUS_SIGN_KEY) == PROVISION_STATUS_SIGN_KEY) { + ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + } else { + processProvisionAttestationKey(apdu); + } + break; + } + case INS_PROVISION_ATTESTATION_CERT_CHAIN_CMD: { + if ((provisionStatus & PROVISION_STATUS_SIGN_CERT_CHAIN) == PROVISION_STATUS_SIGN_CERT_CHAIN) { + ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + } else { + processProvisionAttestationCertChainCmd(apdu); + } + break; + } + case INS_PROVISION_ATTESTATION_CERT_PARAMS_CMD: { + if ((provisionStatus & PROVISION_STATUS_SIGN_CERT_PARAMS) == PROVISION_STATUS_SIGN_CERT_PARAMS) { + ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + } else { + processProvisionAttestationCertParams(apdu); + } + break; + } + case INS_GET_PROVISION_STATUS_CMD: + processGetProvisionStatusCmd(apdu); + break; + default: + ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + break; + } } - } else { - if ((apduIns != INS_PROVISION_ROOT_KEY_CMD) - && (apduIns != INS_PROVISION_CERT_CHAIN_CMD) - && (apduIns != INS_PROVISION_CERT_PARAMS_CMD) - && (apduIns != INS_GET_PROVISION_STATE_CMD)) { - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + } else if (keymasterState == KMKeymasterApplet.PROVISIONED_AKEY_ACERT_STATE) { + switch (apduIns) { + case INS_PROVISION_ATTEST_IDS_CMD: + processProvisionAttestIdsCmd(apdu); + break; + case INS_PROVISION_SHARED_SECRET_CMD: + processProvisionSharedSecretCmd(apdu); + break; + case INS_COMMIT_ATTESTIDS_SHARED_SECRET_CMD: + processCommitAttestIDSharedSecretCmd(apdu); + break; + case INS_GET_PROVISION_STATUS_CMD: + processGetProvisionStatusCmd(apdu); + break; + default: + ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + break; } - if (((provisionState & PROVISIONED_SIGN_KEY) == PROVISIONED_SIGN_KEY) - && (apduIns == INS_PROVISION_ROOT_KEY_CMD)) { - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + } else if (keymasterState == KMKeymasterApplet.PROVISIONED_AKEY_ACERT_AID_SS_STATE) { + switch (apduIns) { + case INS_SET_BOOT_PARAMS_CMD: + processSetBootParamsCmd(apdu); + break; + case INS_GET_PROVISION_STATUS_CMD: + processGetProvisionStatusCmd(apdu); + break; + default: + ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + break; } - if (((provisionState & PROVISIONED_SIGN_CERT_CHAIN) == PROVISIONED_SIGN_CERT_CHAIN) - && (apduIns == INS_PROVISION_CERT_CHAIN_CMD)) { + } else {// ACTIVE_STATE + if (seProvider.isBootSignalEventSupported() + && (apduIns == INS_SET_BOOT_PARAMS_CMD)) { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } - if (((provisionState & PROVISIONED_SIGN_CERT_PARAMS) == PROVISIONED_SIGN_CERT_PARAMS) - && (apduIns == INS_PROVISION_CERT_PARAMS_CMD)) { - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + // Handle the command + switch (apduIns) { + case INS_SET_BOOT_PARAMS_CMD: + processSetBootParamsCmd(apdu); + break; + case INS_GENERATE_KEY_CMD: + processGenerateKey(apdu); + break; + case INS_IMPORT_KEY_CMD: + processImportKeyCmd(apdu); + break; + case INS_IMPORT_WRAPPED_KEY_CMD: + processImportWrappedKeyCmd(apdu); + break; + case INS_EXPORT_KEY_CMD: + processExportKeyCmd(apdu); + break; + case INS_ATTEST_KEY_CMD: + processAttestKeyCmd(apdu); + break; + case INS_UPGRADE_KEY_CMD: + processUpgradeKeyCmd(apdu); + break; + case INS_DELETE_KEY_CMD: + processDeleteKeyCmd(apdu); + break; + case INS_DELETE_ALL_KEYS_CMD: + processDeleteAllKeysCmd(apdu); + break; + case INS_ADD_RNG_ENTROPY_CMD: + processAddRngEntropyCmd(apdu); + break; + case INS_COMPUTE_SHARED_HMAC_CMD: + processComputeSharedHmacCmd(apdu); + break; + case INS_DESTROY_ATT_IDS_CMD: + processDestroyAttIdsCmd(apdu); + break; + case INS_VERIFY_AUTHORIZATION_CMD: + processVerifyAuthorizationCmd(apdu); + break; + case INS_GET_HMAC_SHARING_PARAM_CMD: + processGetHmacSharingParamCmd(apdu); + break; + case INS_GET_KEY_CHARACTERISTICS_CMD: + processGetKeyCharacteristicsCmd(apdu); + break; + case INS_GET_HW_INFO_CMD: + processGetHwInfoCmd(apdu); + break; + case INS_BEGIN_OPERATION_CMD: + processBeginOperationCmd(apdu); + break; + case INS_UPDATE_OPERATION_CMD: + processUpdateOperationCmd(apdu); + break; + case INS_FINISH_OPERATION_CMD: + processFinishOperationCmd(apdu); + break; + case INS_ABORT_OPERATION_CMD: + processAbortOperationCmd(apdu); + break; + case INS_GET_PROVISION_STATUS_CMD: + processGetProvisionStatusCmd(apdu); + break; + case INS_DEVICE_LOCKED_CMD: + processDeviceLockedCmd(apdu); + break; + case INS_EARLY_BOOT_ENDED_CMD: + processEarlyBootEndedCmd(apdu); + break; + case INS_GET_CERT_CHAIN_CMD: + processGetCertChainCmd(apdu); + break; + case INS_BACKUP_CMD: + processBackupCmd(apdu); + break; + case INS_RESTORE_CMD: + processRestoreCmd(apdu); + break; + default: + ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); } } - } else if (keymasterState == KMKeymasterApplet.PROVISION_SIGN_KEY_CERT_DONE) { - if ((apduIns != INS_PROVISION_ATTEST_IDS) - && (apduIns != INS_PROVISION_SHARED_SECRET_CMD) - && (apduIns != INS_COMMIT_ATTESTIDS_SHARED_SECRET_CMD) - && (apduIns != INS_GET_PROVISION_STATE_CMD)) { - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); - } - } else if (keymasterState == KMKeymasterApplet.BOOT_STATE) { - if ((apduIns != INS_SET_BOOT_PARAMS_CMD) - && (apduIns != INS_GET_PROVISION_STATE_CMD)) { - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); - } - } else {//ACTIVE_STATE - if ((apduIns == INS_PROVISION_ROOT_KEY_CMD) - || (apduIns == INS_PROVISION_CERT_CHAIN_CMD) - || (apduIns == INS_PROVISION_CERT_PARAMS_CMD) - || (apduIns == INS_PROVISION_ATTEST_IDS) - || (apduIns == INS_PROVISION_SHARED_SECRET_CMD) - || (apduIns == INS_COMMIT_ATTESTIDS_SHARED_SECRET_CMD)) { - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); - } - if (seProvider.isBootSignalEventSupported() - && (apduIns == INS_SET_BOOT_PARAMS_CMD)) { - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); - } - } - // Process the apdu - try { - // Handle the command - switch (apduIns) { - case INS_GENERATE_KEY_CMD: - processGenerateKey(apdu); - break; - case INS_IMPORT_KEY_CMD: - processImportKeyCmd(apdu); - break; - case INS_IMPORT_WRAPPED_KEY_CMD: - processImportWrappedKeyCmd(apdu); - break; - case INS_EXPORT_KEY_CMD: - processExportKeyCmd(apdu); - break; - case INS_ATTEST_KEY_CMD: - processAttestKeyCmd(apdu); - break; - case INS_UPGRADE_KEY_CMD: - processUpgradeKeyCmd(apdu); - break; - case INS_DELETE_KEY_CMD: - processDeleteKeyCmd(apdu); - break; - case INS_DELETE_ALL_KEYS_CMD: - processDeleteAllKeysCmd(apdu); - break; - case INS_ADD_RNG_ENTROPY_CMD: - processAddRngEntropyCmd(apdu); - break; - case INS_COMPUTE_SHARED_HMAC_CMD: - processComputeSharedHmacCmd(apdu); - break; - case INS_DESTROY_ATT_IDS_CMD: - processDestroyAttIdsCmd(apdu); - break; - case INS_VERIFY_AUTHORIZATION_CMD: - processVerifyAuthorizationCmd(apdu); - break; - case INS_GET_HMAC_SHARING_PARAM_CMD: - processGetHmacSharingParamCmd(apdu); - break; - case INS_GET_KEY_CHARACTERISTICS_CMD: - processGetKeyCharacteristicsCmd(apdu); - break; - case INS_GET_HW_INFO_CMD: - processGetHwInfoCmd(apdu); - break; - case INS_BEGIN_OPERATION_CMD: - processBeginOperationCmd(apdu); - break; - case INS_UPDATE_OPERATION_CMD: - processUpdateOperationCmd(apdu); - break; - case INS_FINISH_OPERATION_CMD: - processFinishOperationCmd(apdu); - break; - case INS_ABORT_OPERATION_CMD: - processAbortOperationCmd(apdu); - break; - case INS_PROVISION_ROOT_KEY_CMD: - processProvisionRootKey(apdu); - break; - case INS_PROVISION_CERT_CHAIN_CMD: - processProvisionCertChainCmd(apdu); - break; - case INS_PROVISION_CERT_PARAMS_CMD: - processProvisionCertParams(apdu); - break; - case INS_PROVISION_SHARED_SECRET_CMD: - processProvisionSharedSecretCmd(apdu); - break; - case INS_PROVISION_ATTEST_IDS: - processProvisionAttestIdsCmd(apdu); - break; - case INS_COMMIT_ATTESTIDS_SHARED_SECRET_CMD: - processCommitAttestIDSharedSecret(apdu); - break; - case INS_GET_PROVISION_STATE_CMD: - processGetProvisionState(apdu); - break; - case INS_SET_BOOT_PARAMS_CMD: - processSetBootParamsCmd(apdu); - break; - case INS_DEVICE_LOCKED_CMD: - processDeviceLockedCmd(apdu); - break; - case INS_EARLY_BOOT_ENDED_CMD: - processEarlyBootEndedCmd(apdu); - break; - case INS_GET_CERT_CHAIN_CMD: - processGetCertChainCmd(apdu); - break; - case INS_BACKUP_CMD: - processBackupCmd(apdu); - break; - case INS_RESTORE_CMD: - processRestoreCmd(apdu); - break; - default: - ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); - } } catch (KMException exception) { freeOperations(); sendError(apdu, KMException.reason); @@ -629,19 +639,23 @@ private void processGetCertChainCmd(APDU apdu) { private void handleStateTransition() { if (keymasterState == KMKeymasterApplet.FIRST_SELECT_STATE) { - if (provisionState == 0x07) { - keymasterState = KMKeymasterApplet.PROVISION_SIGN_KEY_CERT_DONE; + if (provisionStatus == (PROVISION_STATUS_SIGN_KEY + | PROVISION_STATUS_SIGN_CERT_CHAIN | PROVISION_STATUS_SIGN_CERT_PARAMS)) { + keymasterState = KMKeymasterApplet.PROVISIONED_AKEY_ACERT_STATE; } - } else if (keymasterState == KMKeymasterApplet.PROVISION_SIGN_KEY_CERT_DONE) { - if (provisionState == 0x3F) { - keymasterState = KMKeymasterApplet.BOOT_STATE; + } else if (keymasterState == KMKeymasterApplet.PROVISIONED_AKEY_ACERT_STATE) { + if (provisionStatus == (PROVISION_STATUS_SIGN_KEY + | PROVISION_STATUS_SIGN_CERT_CHAIN + | PROVISION_STATUS_SIGN_CERT_PARAMS | PROVISION_STATUS_ATTEST_IDS + | PROVISION_STATUS_SHARED_SECRET | PROVISION_STATUS_APPLET_PROVISIONED)) { + keymasterState = KMKeymasterApplet.PROVISIONED_AKEY_ACERT_AID_SS_STATE; } - } else if (keymasterState == KMKeymasterApplet.BOOT_STATE) { + } else if (keymasterState == KMKeymasterApplet.PROVISIONED_AKEY_ACERT_AID_SS_STATE) { keymasterState = KMKeymasterApplet.ACTIVE_STATE; } } - private void processProvisionCertParams(APDU apdu) { + private void processProvisionAttestationCertParams(APDU apdu) { receiveIncoming(apdu); // Arguments short blob = KMByteBlob.exp(); @@ -673,69 +687,46 @@ private void processProvisionCertParams(APDU apdu) { KMByteBlob.cast(tmpVariables[0]).getStartOff(), KMByteBlob.cast(tmpVariables[0]).length()); - provisionState |= KMKeymasterApplet.PROVISIONED_SIGN_CERT_PARAMS; + provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_SIGN_CERT_PARAMS; handleStateTransition(); sendError(apdu, KMError.OK); } - private void processProvisionCertChainCmd(APDU apdu) { + private void processProvisionAttestationCertChainCmd(APDU apdu) { byte[] srcBuffer = apdu.getBuffer(); short recvLen = apdu.setIncomingAndReceive(); short srcOffset = apdu.getOffsetCdata(); bufferLength = apdu.getIncomingLength(); - short index = bufferStartOffset; + short bytesRead = 0; // Receive data if (bufferLength > MAX_IO_LENGTH) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } - short certStart = (short) (srcOffset + 1); - byte count = (byte)seProvider.getNumberOfCerts(); - while (recvLen > 0 && ((short) (index - bufferStartOffset) < bufferLength)) { - // Checking conditions - // 1. Check that Array header contains expected number of certificates - // chain. - // 2. Check array count matches with number of array elements. - // 3. Check that each certificate length matches its actual size. - if (index == bufferStartOffset) { - // Check if the Major type is 8 - count |= 0x80; - if ((count ^ srcBuffer[srcOffset]) != (short)0) - ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); - } - while (certStart < (short) (srcOffset + recvLen)) { - // Check if the Major type is 4 - if ((srcBuffer[certStart] & 0xE0) != 0x40) - ISOException.throwIt(ISO7816.SW_DATA_INVALID); - // read the length of the certificate. - if ((srcBuffer[certStart] & 0x1F) != (byte) 0x18 - && (srcBuffer[certStart] & 0x1F) != (byte) 0x19) { - ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); - } - if ((srcBuffer[certStart] & 0x1F) == (byte) 0x18) { - tmpVariables[1] = srcBuffer[(short) (certStart + 1)]; - // cert data - certStart += 2; - } else { // 0x19 - tmpVariables[1] = Util.getShort(srcBuffer, (short) (certStart + 1)); - // cert data - certStart += 3; - } - certStart += tmpVariables[1]; - } - certStart = (short)(certStart - recvLen); - seProvider.persistPartialCertificateChain(srcBuffer, srcOffset, recvLen, + + short context = KMByteBlob.instance(KMDecoder.CONTEXT_LEN); + Util.arrayFillNonAtomic( + KMByteBlob.cast(context).getBuffer(), + KMByteBlob.cast(context).getStartOff(), + KMByteBlob.cast(context).length(), + (byte) 0); + while (recvLen > 0 && ((short) bytesRead <= bufferLength)) { + Util.arrayCopyNonAtomic(srcBuffer, srcOffset, buffer, bufferStartOffset, recvLen); + decoder.incrementalReceiveAndValidateCertificateChain( + KMByteBlob.cast(context).getBuffer(), + KMByteBlob.cast(context).getStartOff(), + KMByteBlob.cast(context).length(), + buffer, bufferStartOffset, recvLen); + seProvider.persistPartialCertificateChain(buffer, bufferStartOffset, recvLen, bufferLength); - //Util.arrayCopyNonAtomic(srcBuffer, srcOffset, buffer, index, recvLen); - index += recvLen; + bytesRead += recvLen; recvLen = apdu.receiveBytes(srcOffset); } - //provisionDone |= 0x04; - provisionState |= KMKeymasterApplet.PROVISIONED_SIGN_CERT_CHAIN; + provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_SIGN_CERT_CHAIN; handleStateTransition(); sendError(apdu, KMError.OK); } - private void processProvisionRootKey(APDU apdu) { + private void processProvisionAttestationKey(APDU apdu) { receiveIncoming(apdu); // Re-purpose the apdu buffer as scratch pad. byte[] scratchPad = apdu.getBuffer(); @@ -794,14 +785,14 @@ private void processProvisionRootKey(APDU apdu) { // persist key repository.persistAttestationKey(data[SECRET]); - provisionState |= KMKeymasterApplet.PROVISIONED_SIGN_KEY; + provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_SIGN_KEY; handleStateTransition(); sendError(apdu, KMError.OK); } private void processProvisionAttestIdsCmd(APDU apdu) { receiveIncoming(apdu); - //Arguments + // Arguments short keyparams = KMKeyParameters.exp(); short argsProto = KMArray.instance((short) 1); KMArray.cast(argsProto).add((short) 0, keyparams); @@ -818,7 +809,7 @@ private void processProvisionAttestIdsCmd(APDU apdu) { saveAttId(KMType.ATTESTATION_ID_MEID); saveAttId(KMType.ATTESTATION_ID_SERIAL); - provisionState |= KMKeymasterApplet.PROVISIONED_ATTEST_IDS; + provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_ATTEST_IDS; sendError(apdu, KMError.OK); } @@ -842,25 +833,25 @@ private void processProvisionSharedSecretCmd(APDU apdu) { KMByteBlob.cast(tmpVariables[0]).getStartOff(), KMByteBlob.cast(tmpVariables[0]).length()); - provisionState |= KMKeymasterApplet.PROVISIONED_SHARED_SECRET; + provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_SHARED_SECRET; sendError(apdu, KMError.OK); } - private void processCommitAttestIDSharedSecret(APDU apdu) { - //Check if shared secret is persisted. If not persisted throw error. + private void processCommitAttestIDSharedSecretCmd(APDU apdu) { + // Check if shared secret is persisted. If not persisted throw error. short keyBlob = repository.getSharedKey(); if (KMByteBlob.cast(keyBlob).length() == 0) { KMException.throwIt(KMError.KEY_NOT_YET_VALID); } - provisionState |= KMKeymasterApplet.APPLET_PROVISIONED; + provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_APPLET_PROVISIONED; handleStateTransition(); sendError(apdu, KMError.OK); } - private void processGetProvisionState(APDU apdu) { + private void processGetProvisionStatusCmd(APDU apdu) { tmpVariables[0] = KMArray.instance((short) 2); KMArray.cast(tmpVariables[0]).add((short) 0, KMInteger.uint_16(KMError.OK)); - KMArray.cast(tmpVariables[0]).add((short) 1, KMInteger.uint_16(provisionState)); + KMArray.cast(tmpVariables[0]).add((short) 1, KMInteger.uint_16(provisionStatus)); bufferLength = encoder.encode(tmpVariables[0], buffer, bufferStartOffset); sendOutgoing(apdu); } @@ -2321,10 +2312,10 @@ private void processUpdateOperationCmd(APDU apdu) { } } // Allocate output buffer as input data is already block aligned - data[OUTPUT_DATA] = KMByteBlob.instance((short)(tmpVariables[0]+additionalExpOutLen)); + data[OUTPUT_DATA] = KMByteBlob.instance((short) (tmpVariables[0]+additionalExpOutLen)); // Otherwise just update the data. - //HAL consumes all the input and maintains a buffered data inside it. So the - //applet sends the inputConsumed length as same as the input length. + // HAL consumes all the input and maintains a buffered data inside it. So the + // applet sends the inputConsumed length as same as the input length. tmpVariables[3] = tmpVariables[0]; try { tmpVariables[0] = @@ -3548,7 +3539,7 @@ private void processSetBootParamsCmd(APDU apdu) { // repository.deviceLockedFlag = (enumVal == KMType.DEVICE_LOCKED_TRUE); repository.setDeviceLock(enumVal == KMType.DEVICE_LOCKED_TRUE); - //Clear the Computed SharedHmac and Hmac nonce from persistent memory. + // Clear the Computed SharedHmac and Hmac nonce from persistent memory. repository.clearComputedHmac(); repository.clearHmacNonce(); @@ -4159,8 +4150,7 @@ private static short deriveKey(byte[] scratchPad) { tmpVariables[2], KMByteBlob.cast(tmpVariables[4]).getBuffer(), KMByteBlob.cast(tmpVariables[4]).getStartOff(), - KMByteBlob.cast(tmpVariables[4 - ]).length(), + KMByteBlob.cast(tmpVariables[4]).length(), scratchPad, (short) 0); if (tmpVariables[3] < 0) { From 56885eec117534fdb7d1a675415078819011eeb4 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Thu, 19 Nov 2020 22:19:21 +0000 Subject: [PATCH 17/42] Changed the instruction command values for provision cmds --- .../javacard/keymaster/KMKeymasterApplet.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index df85418c..f53f0cf8 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -98,13 +98,13 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe private static final byte INS_RESTORE_CMD = 0x27; private static final byte INS_GET_CERT_CHAIN_CMD = 0x28; //Instructions for Provision Commands. - private static final byte INS_PROVISION_ATTESTATION_KEY_CMD = 0x3C; - private static final byte INS_PROVISION_ATTESTATION_CERT_CHAIN_CMD = 0x3D; - private static final byte INS_PROVISION_ATTESTATION_CERT_PARAMS_CMD = 0x3E; - private static final byte INS_PROVISION_ATTEST_IDS_CMD = 0x3F; - private static final byte INS_PROVISION_SHARED_SECRET_CMD = 0x40; - private static final byte INS_COMMIT_ATTESTIDS_SHARED_SECRET_CMD = 0x41; - private static final byte INS_GET_PROVISION_STATUS_CMD = 0x42; + private static final byte INS_PROVISION_ATTESTATION_KEY_CMD = 0x29; + private static final byte INS_PROVISION_ATTESTATION_CERT_CHAIN_CMD = 0x30; + private static final byte INS_PROVISION_ATTESTATION_CERT_PARAMS_CMD = 0x31; + private static final byte INS_PROVISION_ATTEST_IDS_CMD = 0x32; + private static final byte INS_PROVISION_SHARED_SECRET_CMD = 0x33; + private static final byte INS_COMMIT_ATTESTIDS_SHARED_SECRET_CMD = 0x34; + private static final byte INS_GET_PROVISION_STATUS_CMD = 0x35; //Provision reporting status private static final byte NOT_PROVISIONED = 0x00; private static final byte PROVISION_STATUS_SIGN_KEY = 0x01; From 411e7b9dc925bfd9f9de438541543245deac918a Mon Sep 17 00:00:00 2001 From: Manish Dwivedi Date: Fri, 20 Nov 2020 02:57:50 +0000 Subject: [PATCH 18/42] Add Begin/End STATE, rm old B&R & mv handle statem --- .../javacard/keymaster/KMKeymasterApplet.java | 214 ++++++++---------- 1 file changed, 98 insertions(+), 116 deletions(-) diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index df85418c..ccb3f8c0 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -72,6 +72,7 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe private static final byte INACTIVE_STATE = 0x06; private static final byte UNINSTALLED_STATE = 0x07; // Commands + private static final byte INS_BEGIN_KM_CMD = 0x09; private static final byte INS_GENERATE_KEY_CMD = 0x10; private static final byte INS_IMPORT_KEY_CMD = 0x11; private static final byte INS_IMPORT_WRAPPED_KEY_CMD = 0x12; @@ -94,18 +95,19 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe private static final byte INS_SET_BOOT_PARAMS_CMD = 0x23; private static final byte INS_DEVICE_LOCKED_CMD = 0x24; private static final byte INS_EARLY_BOOT_ENDED_CMD = 0x25; - private static final byte INS_BACKUP_CMD = 0x26; - private static final byte INS_RESTORE_CMD = 0x27; - private static final byte INS_GET_CERT_CHAIN_CMD = 0x28; - //Instructions for Provision Commands. - private static final byte INS_PROVISION_ATTESTATION_KEY_CMD = 0x3C; - private static final byte INS_PROVISION_ATTESTATION_CERT_CHAIN_CMD = 0x3D; - private static final byte INS_PROVISION_ATTESTATION_CERT_PARAMS_CMD = 0x3E; - private static final byte INS_PROVISION_ATTEST_IDS_CMD = 0x3F; - private static final byte INS_PROVISION_SHARED_SECRET_CMD = 0x40; - private static final byte INS_COMMIT_ATTESTIDS_SHARED_SECRET_CMD = 0x41; - private static final byte INS_GET_PROVISION_STATUS_CMD = 0x42; - //Provision reporting status + private static final byte INS_GET_CERT_CHAIN_CMD = 0x26; + + // Instructions for Provision Commands. + private static final byte INS_PROVISION_ATTESTATION_KEY_CMD = 0x27; + private static final byte INS_PROVISION_ATTESTATION_CERT_CHAIN_CMD = 0x28; + private static final byte INS_PROVISION_ATTESTATION_CERT_PARAMS_CMD = 0x29; + private static final byte INS_PROVISION_ATTEST_IDS_CMD = 0x30; + private static final byte INS_PROVISION_SHARED_SECRET_CMD = 0x3A; + private static final byte INS_COMMIT_ATTESTIDS_SHARED_SECRET_CMD = 0x3B; + private static final byte INS_GET_PROVISION_STATUS_CMD = 0x3C; + private static final byte INS_END_KM_CMD = 0x3D; + + // Provision reporting status private static final byte NOT_PROVISIONED = 0x00; private static final byte PROVISION_STATUS_SIGN_KEY = 0x01; private static final byte PROVISION_STATUS_SIGN_CERT_CHAIN = 0x02; @@ -299,7 +301,7 @@ public void process(APDU apdu) { ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } // Validate whether INS can be supported - if (!(apduIns >= INS_GENERATE_KEY_CMD && apduIns <= INS_GET_PROVISION_STATUS_CMD)) { + if (!(apduIns > INS_BEGIN_KM_CMD && apduIns < INS_END_KM_CMD)) { ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); } // Process the apdu @@ -307,59 +309,71 @@ public void process(APDU apdu) { // Validate if INS is provision command if applet is in // FIRST_SELECT_STATE. if (keymasterState == KMKeymasterApplet.FIRST_SELECT_STATE) { - // If the Applet is in the FIRST_SELECT_STATE, then either Provision - // Commands or Restore Command is allowed. - // If there is no backup available, then only provision command is - // allowed. - // If backup available, then only restore command is allowed. - if (seProvider.isBackupAvailable()) { - if ((apduIns != INS_RESTORE_CMD)) { - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); - } - } else { - switch (apduIns) { - case INS_PROVISION_ATTESTATION_KEY_CMD: { + switch (apduIns) { + case INS_PROVISION_ATTESTATION_KEY_CMD: + { if ((provisionStatus & PROVISION_STATUS_SIGN_KEY) == PROVISION_STATUS_SIGN_KEY) { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } else { processProvisionAttestationKey(apdu); + provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_SIGN_KEY; + handleStateTransition(); + sendError(apdu, KMError.OK); } break; } - case INS_PROVISION_ATTESTATION_CERT_CHAIN_CMD: { - if ((provisionStatus & PROVISION_STATUS_SIGN_CERT_CHAIN) == PROVISION_STATUS_SIGN_CERT_CHAIN) { + case INS_PROVISION_ATTESTATION_CERT_CHAIN_CMD: + { + if ((provisionStatus & PROVISION_STATUS_SIGN_CERT_CHAIN) + == PROVISION_STATUS_SIGN_CERT_CHAIN) { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } else { processProvisionAttestationCertChainCmd(apdu); + provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_SIGN_CERT_CHAIN; + handleStateTransition(); + sendError(apdu, KMError.OK); } break; } - case INS_PROVISION_ATTESTATION_CERT_PARAMS_CMD: { - if ((provisionStatus & PROVISION_STATUS_SIGN_CERT_PARAMS) == PROVISION_STATUS_SIGN_CERT_PARAMS) { + case INS_PROVISION_ATTESTATION_CERT_PARAMS_CMD: + { + if ((provisionStatus & PROVISION_STATUS_SIGN_CERT_PARAMS) + == PROVISION_STATUS_SIGN_CERT_PARAMS) { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } else { processProvisionAttestationCertParams(apdu); + provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_SIGN_CERT_PARAMS; + handleStateTransition(); + sendError(apdu, KMError.OK); } break; } - case INS_GET_PROVISION_STATUS_CMD: - processGetProvisionStatusCmd(apdu); - break; - default: - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); - break; - } + case INS_GET_PROVISION_STATUS_CMD: + processGetProvisionStatusCmd(apdu); + break; + default: + ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + break; } } else if (keymasterState == KMKeymasterApplet.PROVISIONED_AKEY_ACERT_STATE) { switch (apduIns) { case INS_PROVISION_ATTEST_IDS_CMD: processProvisionAttestIdsCmd(apdu); + provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_ATTEST_IDS; + handleStateTransition(); + sendError(apdu, KMError.OK); break; case INS_PROVISION_SHARED_SECRET_CMD: processProvisionSharedSecretCmd(apdu); + provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_SHARED_SECRET; + handleStateTransition(); + sendError(apdu, KMError.OK); break; case INS_COMMIT_ATTESTIDS_SHARED_SECRET_CMD: processCommitAttestIDSharedSecretCmd(apdu); + provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_APPLET_PROVISIONED; + handleStateTransition(); + sendError(apdu, KMError.OK); break; case INS_GET_PROVISION_STATUS_CMD: processGetProvisionStatusCmd(apdu); @@ -372,6 +386,8 @@ public void process(APDU apdu) { switch (apduIns) { case INS_SET_BOOT_PARAMS_CMD: processSetBootParamsCmd(apdu); + handleStateTransition(); + sendError(apdu, KMError.OK); break; case INS_GET_PROVISION_STATUS_CMD: processGetProvisionStatusCmd(apdu); @@ -380,15 +396,17 @@ public void process(APDU apdu) { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); break; } - } else {// ACTIVE_STATE - if (seProvider.isBootSignalEventSupported() - && (apduIns == INS_SET_BOOT_PARAMS_CMD)) { + + } else { // ACTIVE_STATE + if (seProvider.isBootSignalEventSupported() && (apduIns == INS_SET_BOOT_PARAMS_CMD)) { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } // Handle the command switch (apduIns) { case INS_SET_BOOT_PARAMS_CMD: processSetBootParamsCmd(apdu); + handleStateTransition(); + sendError(apdu, KMError.OK); break; case INS_GENERATE_KEY_CMD: processGenerateKey(apdu); @@ -459,12 +477,6 @@ public void process(APDU apdu) { case INS_GET_CERT_CHAIN_CMD: processGetCertChainCmd(apdu); break; - case INS_BACKUP_CMD: - processBackupCmd(apdu); - break; - case INS_RESTORE_CMD: - processRestoreCmd(apdu); - break; default: ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); } @@ -481,26 +493,6 @@ public void process(APDU apdu) { } } - private void processRestoreCmd(APDU apdu) { - // No arguments - if (!seProvider.isBackupRestoreSupported()) sendError(apdu, KMError.UNIMPLEMENTED); - byte[] data = repository.getDataTable(); - short buf = KMByteBlob.instance((short) data.length); - short len = - seProvider.restore(KMByteBlob.cast(buf).getBuffer(), KMByteBlob.cast(buf).getStartOff()); - repository.restoreData(buf); - keymasterState = ACTIVE_STATE; - sendError(apdu, KMError.OK); - } - - private void processBackupCmd(APDU apdu) { - // No arguments - if (!seProvider.isBackupRestoreSupported()) sendError(apdu, KMError.UNIMPLEMENTED); - byte[] data = repository.getDataTable(); - seProvider.backup(data, (short) 0, (short) data.length); - sendError(apdu, KMError.OK); - } - private void freeOperations() { if (data[OP_HANDLE] != KMType.INVALID_VALUE) { KMOperationState op = repository.findOperation(KMInteger.cast(data[OP_HANDLE]).getShort()); @@ -638,21 +630,29 @@ private void processGetCertChainCmd(APDU apdu) { } private void handleStateTransition() { - if (keymasterState == KMKeymasterApplet.FIRST_SELECT_STATE) { - if (provisionStatus == (PROVISION_STATUS_SIGN_KEY - | PROVISION_STATUS_SIGN_CERT_CHAIN | PROVISION_STATUS_SIGN_CERT_PARAMS)) { - keymasterState = KMKeymasterApplet.PROVISIONED_AKEY_ACERT_STATE; + byte currentKMState = keymasterState; + byte nextKMState = keymasterState; + if (currentKMState == KMKeymasterApplet.FIRST_SELECT_STATE) { + if (provisionStatus + == (PROVISION_STATUS_SIGN_KEY + | PROVISION_STATUS_SIGN_CERT_CHAIN + | PROVISION_STATUS_SIGN_CERT_PARAMS)) { + nextKMState = KMKeymasterApplet.PROVISIONED_AKEY_ACERT_STATE; } - } else if (keymasterState == KMKeymasterApplet.PROVISIONED_AKEY_ACERT_STATE) { - if (provisionStatus == (PROVISION_STATUS_SIGN_KEY + } else if (currentKMState == KMKeymasterApplet.PROVISIONED_AKEY_ACERT_STATE) { + if (provisionStatus + == (PROVISION_STATUS_SIGN_KEY | PROVISION_STATUS_SIGN_CERT_CHAIN - | PROVISION_STATUS_SIGN_CERT_PARAMS | PROVISION_STATUS_ATTEST_IDS - | PROVISION_STATUS_SHARED_SECRET | PROVISION_STATUS_APPLET_PROVISIONED)) { - keymasterState = KMKeymasterApplet.PROVISIONED_AKEY_ACERT_AID_SS_STATE; + | PROVISION_STATUS_SIGN_CERT_PARAMS + | PROVISION_STATUS_ATTEST_IDS + | PROVISION_STATUS_SHARED_SECRET + | PROVISION_STATUS_APPLET_PROVISIONED)) { + nextKMState = KMKeymasterApplet.PROVISIONED_AKEY_ACERT_AID_SS_STATE; } - } else if (keymasterState == KMKeymasterApplet.PROVISIONED_AKEY_ACERT_AID_SS_STATE) { - keymasterState = KMKeymasterApplet.ACTIVE_STATE; + } else if (currentKMState == KMKeymasterApplet.PROVISIONED_AKEY_ACERT_AID_SS_STATE) { + nextKMState = KMKeymasterApplet.ACTIVE_STATE; } + keymasterState = nextKMState; } private void processProvisionAttestationCertParams(APDU apdu) { @@ -705,25 +705,23 @@ private void processProvisionAttestationCertChainCmd(APDU apdu) { short context = KMByteBlob.instance(KMDecoder.CONTEXT_LEN); Util.arrayFillNonAtomic( - KMByteBlob.cast(context).getBuffer(), - KMByteBlob.cast(context).getStartOff(), - KMByteBlob.cast(context).length(), - (byte) 0); + KMByteBlob.cast(context).getBuffer(), + KMByteBlob.cast(context).getStartOff(), + KMByteBlob.cast(context).length(), + (byte) 0); while (recvLen > 0 && ((short) bytesRead <= bufferLength)) { Util.arrayCopyNonAtomic(srcBuffer, srcOffset, buffer, bufferStartOffset, recvLen); decoder.incrementalReceiveAndValidateCertificateChain( - KMByteBlob.cast(context).getBuffer(), - KMByteBlob.cast(context).getStartOff(), - KMByteBlob.cast(context).length(), - buffer, bufferStartOffset, recvLen); - seProvider.persistPartialCertificateChain(buffer, bufferStartOffset, recvLen, - bufferLength); + KMByteBlob.cast(context).getBuffer(), + KMByteBlob.cast(context).getStartOff(), + KMByteBlob.cast(context).length(), + buffer, + bufferStartOffset, + recvLen); + seProvider.persistPartialCertificateChain(buffer, bufferStartOffset, recvLen, bufferLength); bytesRead += recvLen; recvLen = apdu.receiveBytes(srcOffset); } - provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_SIGN_CERT_CHAIN; - handleStateTransition(); - sendError(apdu, KMError.OK); } private void processProvisionAttestationKey(APDU apdu) { @@ -768,7 +766,7 @@ private void processProvisionAttestationKey(APDU apdu) { } else { KMException.throwIt(KMError.INVALID_ARGUMENT); } - //Purpose should be ATTEST_KEY + // Purpose should be ATTEST_KEY tmpVariables[0] = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PURPOSE, data[KEY_PARAMETERS]); if (tmpVariables[0] != KMType.INVALID_VALUE) { @@ -784,10 +782,6 @@ private void processProvisionAttestationKey(APDU apdu) { // persist key repository.persistAttestationKey(data[SECRET]); - - provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_SIGN_KEY; - handleStateTransition(); - sendError(apdu, KMError.OK); } private void processProvisionAttestIdsCmd(APDU apdu) { @@ -808,9 +802,6 @@ private void processProvisionAttestIdsCmd(APDU apdu) { saveAttId(KMType.ATTESTATION_ID_IMEI); saveAttId(KMType.ATTESTATION_ID_MEID); saveAttId(KMType.ATTESTATION_ID_SERIAL); - - provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_ATTEST_IDS; - sendError(apdu, KMError.OK); } private void processProvisionSharedSecretCmd(APDU apdu) { @@ -823,8 +814,8 @@ private void processProvisionSharedSecretCmd(APDU apdu) { short args = decoder.decode(argsProto, buffer, bufferStartOffset, bufferLength); tmpVariables[0] = KMArray.cast(args).get((short) 0); - if (tmpVariables[0] != KMType.INVALID_VALUE && - KMByteBlob.cast(tmpVariables[0]).length() != KMRepository.SHARED_SECRET_KEY_SIZE) { + if (tmpVariables[0] != KMType.INVALID_VALUE + && KMByteBlob.cast(tmpVariables[0]).length() != KMRepository.SHARED_SECRET_KEY_SIZE) { KMException.throwIt(KMError.INVALID_ARGUMENT); } // Persist shared Hmac. @@ -832,9 +823,6 @@ private void processProvisionSharedSecretCmd(APDU apdu) { KMByteBlob.cast(tmpVariables[0]).getBuffer(), KMByteBlob.cast(tmpVariables[0]).getStartOff(), KMByteBlob.cast(tmpVariables[0]).length()); - - provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_SHARED_SECRET; - sendError(apdu, KMError.OK); } private void processCommitAttestIDSharedSecretCmd(APDU apdu) { @@ -843,9 +831,6 @@ private void processCommitAttestIDSharedSecretCmd(APDU apdu) { if (KMByteBlob.cast(keyBlob).length() == 0) { KMException.throwIt(KMError.KEY_NOT_YET_VALID); } - provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_APPLET_PROVISIONED; - handleStateTransition(); - sendError(apdu, KMError.OK); } private void processGetProvisionStatusCmd(APDU apdu) { @@ -931,10 +916,8 @@ private void processGetHmacSharingParamCmd(APDU apdu) { // No Arguments // Create HMAC Sharing Parameters tmpVariables[2] = KMHmacSharingParameters.instance(); - KMHmacSharingParameters.cast(tmpVariables[2]).setNonce( - repository.getHmacNonce()); - KMHmacSharingParameters.cast(tmpVariables[2]).setSeed( - KMByteBlob.instance((short) 0)); + KMHmacSharingParameters.cast(tmpVariables[2]).setNonce(repository.getHmacNonce()); + KMHmacSharingParameters.cast(tmpVariables[2]).setSeed(KMByteBlob.instance((short) 0)); // prepare the response tmpVariables[3] = KMArray.instance((short) 2); KMArray.cast(tmpVariables[3]).add((short) 0, KMInteger.uint_16(KMError.OK)); @@ -1079,7 +1062,9 @@ private void processComputeSharedHmacCmd(APDU apdu) { KMByteBlob.cast(tmpVariables[8]).getBuffer(), KMByteBlob.cast(tmpVariables[8]).getStartOff(), KMByteBlob.cast(tmpVariables[8]).length(), - ckdfLable, (short)0,(short)ckdfLable.length, + ckdfLable, + (short) 0, + (short) ckdfLable.length, repository.getHeap(), tmpVariables[1], tmpVariables[3], @@ -2312,7 +2297,7 @@ private void processUpdateOperationCmd(APDU apdu) { } } // Allocate output buffer as input data is already block aligned - data[OUTPUT_DATA] = KMByteBlob.instance((short) (tmpVariables[0]+additionalExpOutLen)); + data[OUTPUT_DATA] = KMByteBlob.instance((short) (tmpVariables[0] + additionalExpOutLen)); // Otherwise just update the data. // HAL consumes all the input and maintains a buffered data inside it. So the // applet sends the inputConsumed length as same as the input length. @@ -3544,11 +3529,8 @@ private void processSetBootParamsCmd(APDU apdu) { repository.clearHmacNonce(); // Hmac is cleared, so generate a new Hmac nonce. - seProvider.newRandomNumber(scratchPad, (short) 0, - KMRepository.HMAC_SEED_NONCE_SIZE); - repository.initHmacNonce(scratchPad, (short) 0, - KMRepository.HMAC_SEED_NONCE_SIZE); - handleStateTransition(); + seProvider.newRandomNumber(scratchPad, (short) 0, KMRepository.HMAC_SEED_NONCE_SIZE); + repository.initHmacNonce(scratchPad, (short) 0, KMRepository.HMAC_SEED_NONCE_SIZE); } private static void processGenerateKey(APDU apdu) { From 91012bf0293b17667d7c3de9bb619f45d4538443 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Fri, 20 Nov 2020 19:48:44 +0000 Subject: [PATCH 19/42] 1. AES CCM to AES GCM while deriving the key. 2. Updated the comments. 3. Modified the Instruction command values. --- .../javacard/keymaster/KMKeymasterApplet.java | 126 +++++++++++------- 1 file changed, 77 insertions(+), 49 deletions(-) diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index be1ace0a..01ff6ef2 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -101,17 +101,17 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe private static final byte INS_PROVISION_ATTESTATION_KEY_CMD = 0x27; private static final byte INS_PROVISION_ATTESTATION_CERT_CHAIN_CMD = 0x28; private static final byte INS_PROVISION_ATTESTATION_CERT_PARAMS_CMD = 0x29; - private static final byte INS_PROVISION_ATTEST_IDS_CMD = 0x30; - private static final byte INS_PROVISION_SHARED_SECRET_CMD = 0x3A; - private static final byte INS_COMMIT_ATTESTIDS_SHARED_SECRET_CMD = 0x3B; - private static final byte INS_GET_PROVISION_STATUS_CMD = 0x3C; - private static final byte INS_END_KM_CMD = 0x3D; + private static final byte INS_PROVISION_ATTEST_IDS_CMD = 0x2A; + private static final byte INS_PROVISION_SHARED_SECRET_CMD = 0x2B; + private static final byte INS_COMMIT_ATTESTIDS_SHARED_SECRET_CMD = 0x2C; + private static final byte INS_GET_PROVISION_STATUS_CMD = 0x2D; + private static final byte INS_END_KM_CMD = 0x2E; // Provision reporting status private static final byte NOT_PROVISIONED = 0x00; - private static final byte PROVISION_STATUS_SIGN_KEY = 0x01; - private static final byte PROVISION_STATUS_SIGN_CERT_CHAIN = 0x02; - private static final byte PROVISION_STATUS_SIGN_CERT_PARAMS = 0x04; + private static final byte PROVISION_STATUS_ATTESTATION_KEY = 0x01; + private static final byte PROVISION_STATUS_ATTESTATION_CERT_CHAIN = 0x02; + private static final byte PROVISION_STATUS_ATTESTATION_CERT_PARAMS = 0x04; private static final byte PROVISION_STATUS_ATTEST_IDS = 0x08; private static final byte PROVISION_STATUS_SHARED_SECRET = 0x10; private static final byte PROVISION_STATUS_APPLET_PROVISIONED = 0x20; @@ -312,11 +312,11 @@ public void process(APDU apdu) { switch (apduIns) { case INS_PROVISION_ATTESTATION_KEY_CMD: { - if ((provisionStatus & PROVISION_STATUS_SIGN_KEY) == PROVISION_STATUS_SIGN_KEY) { + if ((provisionStatus & PROVISION_STATUS_ATTESTATION_KEY) == PROVISION_STATUS_ATTESTATION_KEY) { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } else { processProvisionAttestationKey(apdu); - provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_SIGN_KEY; + provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_ATTESTATION_KEY; handleStateTransition(); sendError(apdu, KMError.OK); } @@ -324,12 +324,12 @@ public void process(APDU apdu) { } case INS_PROVISION_ATTESTATION_CERT_CHAIN_CMD: { - if ((provisionStatus & PROVISION_STATUS_SIGN_CERT_CHAIN) - == PROVISION_STATUS_SIGN_CERT_CHAIN) { + if ((provisionStatus & PROVISION_STATUS_ATTESTATION_CERT_CHAIN) + == PROVISION_STATUS_ATTESTATION_CERT_CHAIN) { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } else { processProvisionAttestationCertChainCmd(apdu); - provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_SIGN_CERT_CHAIN; + provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_ATTESTATION_CERT_CHAIN; handleStateTransition(); sendError(apdu, KMError.OK); } @@ -337,12 +337,12 @@ public void process(APDU apdu) { } case INS_PROVISION_ATTESTATION_CERT_PARAMS_CMD: { - if ((provisionStatus & PROVISION_STATUS_SIGN_CERT_PARAMS) - == PROVISION_STATUS_SIGN_CERT_PARAMS) { + if ((provisionStatus & PROVISION_STATUS_ATTESTATION_CERT_PARAMS) + == PROVISION_STATUS_ATTESTATION_CERT_PARAMS) { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } else { processProvisionAttestationCertParams(apdu); - provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_SIGN_CERT_PARAMS; + provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_ATTESTATION_CERT_PARAMS; handleStateTransition(); sendError(apdu, KMError.OK); } @@ -634,16 +634,16 @@ private void handleStateTransition() { byte nextKMState = keymasterState; if (currentKMState == KMKeymasterApplet.FIRST_SELECT_STATE) { if (provisionStatus - == (PROVISION_STATUS_SIGN_KEY - | PROVISION_STATUS_SIGN_CERT_CHAIN - | PROVISION_STATUS_SIGN_CERT_PARAMS)) { + == (PROVISION_STATUS_ATTESTATION_KEY + | PROVISION_STATUS_ATTESTATION_CERT_CHAIN + | PROVISION_STATUS_ATTESTATION_CERT_PARAMS)) { nextKMState = KMKeymasterApplet.PROVISIONED_AKEY_ACERT_STATE; } } else if (currentKMState == KMKeymasterApplet.PROVISIONED_AKEY_ACERT_STATE) { if (provisionStatus - == (PROVISION_STATUS_SIGN_KEY - | PROVISION_STATUS_SIGN_CERT_CHAIN - | PROVISION_STATUS_SIGN_CERT_PARAMS + == (PROVISION_STATUS_ATTESTATION_KEY + | PROVISION_STATUS_ATTESTATION_CERT_CHAIN + | PROVISION_STATUS_ATTESTATION_CERT_PARAMS | PROVISION_STATUS_ATTEST_IDS | PROVISION_STATUS_SHARED_SECRET | PROVISION_STATUS_APPLET_PROVISIONED)) { @@ -686,10 +686,6 @@ private void processProvisionAttestationCertParams(APDU apdu) { KMByteBlob.cast(tmpVariables[0]).getBuffer(), KMByteBlob.cast(tmpVariables[0]).getStartOff(), KMByteBlob.cast(tmpVariables[0]).length()); - - provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_SIGN_CERT_PARAMS; - handleStateTransition(); - sendError(apdu, KMError.OK); } private void processProvisionAttestationCertChainCmd(APDU apdu) { @@ -2862,12 +2858,17 @@ private void beginSignVerifyOperation(KMOperationState op) { } break; case KMType.HMAC: - // For HMAC, either sign or verify we do sign operation only and we compare the - // signature manually. The reason for doing this is the TAG_MAC_LENGTH can be 32 bytes - // length or less than that in case if it is less than 32 we are truncating it and sending - // back to the user. For Verify user will send the truncated and if we pass the truncated - // signature to Javacard verify API it will fail because it expects the full length - // signature. + // As per Keymaster HAL documentation, the length of the Hmac output can + // be decided by using TAG_MAC_LENGTH in Keyparameters. But there is no + // such provision to control the length of the Hmac output using JavaCard + // crypto APIs and the current implementation always returns 32 bytes + // length of Hmac output. So to provide support to TAG_MAC_LENGTH + // feature, we truncate the output signature to TAG_MAC_LENGTH and return + // the truncated signature back to the caller. At the time of verfication + // we again compute the signature of the plain text input, truncate it to + // TAG_MAC_LENGTH and compare it with the input signature for + // verification. So this is the reason we are using KMType.SIGN directly + // instead of using op.getPurpose(). try { op.setOperation( seProvider.initSymmetricOperation( @@ -4114,30 +4115,57 @@ private static short deriveKey(byte[] scratchPad) { tmpVariables[1] = repository.alloc((short) 256); // generate derivation material from hidden parameters tmpVariables[2] = encoder.encode(tmpVariables[0], repository.getHeap(), tmpVariables[1]); - // create derived key i.e. MAC - /* tmpVariables[3] = - seProvider.aesCCMSign( + // KeyDerivation: + // 1. AesGCM Encryption, with below input parameters. + // authData - HIDDEN_PARAMTERS + // Key - Master Key + // InputData - AUTH_DATA + // IV - NONCE + // 2. After encryption it generates two outputs + // a. Encrypted output + // b. Auth Tag + // 3. Do HMAC Sign, with below input parameters. + // Key - Auth Tag (Generated in step 2). + // Input data - Encrypted output (Generated in step 2). + // 4. HMAC Sign generates an output of 32 bytes length. + // Consume only first 16 bytes as derived key. + tmpVariables[4] = repository.getMasterKeySecret(); + tmpVariables[5] = repository.alloc(AES_GCM_AUTH_TAG_LENGTH); + tmpVariables[3] = + seProvider.aesGCMEncrypt( + KMByteBlob.cast(tmpVariables[4]).getBuffer(), + KMByteBlob.cast(tmpVariables[4]).getStartOff(), + KMByteBlob.cast(tmpVariables[4]).length(), + repository.getHeap(), + data[AUTH_DATA], + data[AUTH_DATA_LENGTH], + scratchPad, + (short) 0, + KMByteBlob.cast(data[NONCE]).getBuffer(), + KMByteBlob.cast(data[NONCE]).getStartOff(), + KMByteBlob.cast(data[NONCE]).length(), repository.getHeap(), tmpVariables[1], tmpVariables[2], - repository.getMasterKeySecret(), - scratchPad, - (short) 0); - */ - tmpVariables[4] = repository.getMasterKeySecret(); - tmpVariables[3] = - seProvider.aesCCMSign( + repository.getHeap(), + tmpVariables[5], + AES_GCM_AUTH_TAG_LENGTH); + // Hmac sign. + tmpVariables[3] = seProvider.hmacSign( repository.getHeap(), - tmpVariables[1], - tmpVariables[2], - KMByteBlob.cast(tmpVariables[4]).getBuffer(), - KMByteBlob.cast(tmpVariables[4]).getStartOff(), - KMByteBlob.cast(tmpVariables[4]).length(), + tmpVariables[5], + AES_GCM_AUTH_TAG_LENGTH, scratchPad, - (short) 0); - if (tmpVariables[3] < 0) { + (short) 0, + tmpVariables[3], + repository.getHeap(), + tmpVariables[1]); + if (tmpVariables[3] < 16) { KMException.throwIt(KMError.UNKNOWN_ERROR); } + tmpVariables[3] = 16; + Util.arrayCopyNonAtomic(repository.getHeap(), tmpVariables[1], scratchPad, + (short) 0, tmpVariables[3]); // store the derived secret in data dictionary data[DERIVED_KEY] = repository.alloc(tmpVariables[3]); Util.arrayCopyNonAtomic( From 7c1fc4b62d35b294da89ee6e677af02b0d489a54 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Sun, 22 Nov 2020 23:57:56 +0000 Subject: [PATCH 20/42] Modified Applet state machine --- .../javacard/keymaster/AndroidSEProvider.java | 11 + .../javacard/keymaster/KMJcardSimulator.java | 10 + .../javacard/keymaster/KMKeymasterApplet.java | 216 +++++++----------- .../javacard/keymaster/KMSEProvider.java | 13 ++ 4 files changed, 118 insertions(+), 132 deletions(-) diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java index e170280e..bc06cf6e 100644 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java +++ b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java @@ -1245,4 +1245,15 @@ public boolean isBootSignalEventSupported() { return false; } + @Override + public boolean isDeviceRebooted() { + return false; + } + + @Override + public void setDeviceBooted(boolean resetBootFlag) { + // To be filled + } + + } diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java index 4a5aa041..85f26c5b 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java +++ b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java @@ -1351,6 +1351,16 @@ public boolean isBootSignalEventSupported() { return false; } + @Override + public boolean isDeviceRebooted() { + return false; + } + + @Override + public void setDeviceBooted(boolean resetBootFlag) { + // To be filled + } + /* private static void print (String lab, byte[] b, short s, short l){ byte[] i = new byte[l]; diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 01ff6ef2..008211e2 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -65,12 +65,10 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe // Possible states of the applet. private static final byte ILLEGAL_STATE = 0x00; private static final byte INIT_STATE = 0x01; - private static final byte FIRST_SELECT_STATE = 0x02; - private static final byte PROVISIONED_AKEY_ACERT_STATE = 0x03; - private static final byte PROVISIONED_AKEY_ACERT_AID_SS_STATE = 0x04; - private static final byte ACTIVE_STATE = 0x05; - private static final byte INACTIVE_STATE = 0x06; - private static final byte UNINSTALLED_STATE = 0x07; + private static final byte IN_PROVISION_STATE = 0x02; + private static final byte ACTIVE_STATE = 0x03; + private static final byte INACTIVE_STATE = 0x04; + private static final byte UNINSTALLED_STATE = 0x05; // Commands private static final byte INS_BEGIN_KM_CMD = 0x09; private static final byte INS_GENERATE_KEY_CMD = 0x10; @@ -96,14 +94,14 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe private static final byte INS_DEVICE_LOCKED_CMD = 0x24; private static final byte INS_EARLY_BOOT_ENDED_CMD = 0x25; private static final byte INS_GET_CERT_CHAIN_CMD = 0x26; - + // Instructions for Provision Commands. private static final byte INS_PROVISION_ATTESTATION_KEY_CMD = 0x27; private static final byte INS_PROVISION_ATTESTATION_CERT_CHAIN_CMD = 0x28; private static final byte INS_PROVISION_ATTESTATION_CERT_PARAMS_CMD = 0x29; private static final byte INS_PROVISION_ATTEST_IDS_CMD = 0x2A; private static final byte INS_PROVISION_SHARED_SECRET_CMD = 0x2B; - private static final byte INS_COMMIT_ATTESTIDS_SHARED_SECRET_CMD = 0x2C; + private static final byte INS_LOCK_PROVISIONING_CMD = 0x2C; private static final byte INS_GET_PROVISION_STATUS_CMD = 0x2D; private static final byte INS_END_KM_CMD = 0x2E; @@ -114,7 +112,8 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe private static final byte PROVISION_STATUS_ATTESTATION_CERT_PARAMS = 0x04; private static final byte PROVISION_STATUS_ATTEST_IDS = 0x08; private static final byte PROVISION_STATUS_SHARED_SECRET = 0x10; - private static final byte PROVISION_STATUS_APPLET_PROVISIONED = 0x20; + private static final byte PROVISION_STATUS_BOOT_PARAM = 0x20; + private static final byte PROVISION_STATUS_PROVISIONING_LOCKED = 0x40; // Data Dictionary items public static final byte DATA_ARRAY_SIZE = 30; @@ -239,7 +238,7 @@ public static void install(byte[] bArray, short bOffset, byte bLength) { public boolean select() { repository.onSelect(); if (keymasterState == KMKeymasterApplet.INIT_STATE) { - keymasterState = KMKeymasterApplet.FIRST_SELECT_STATE; + keymasterState = KMKeymasterApplet.IN_PROVISION_STATE; } else if (keymasterState == KMKeymasterApplet.INACTIVE_STATE) { keymasterState = KMKeymasterApplet.ACTIVE_STATE; } @@ -306,108 +305,76 @@ public void process(APDU apdu) { } // Process the apdu try { - // Validate if INS is provision command if applet is in - // FIRST_SELECT_STATE. - if (keymasterState == KMKeymasterApplet.FIRST_SELECT_STATE) { + + if (keymasterState == KMKeymasterApplet.IN_PROVISION_STATE) { switch (apduIns) { case INS_PROVISION_ATTESTATION_KEY_CMD: - { - if ((provisionStatus & PROVISION_STATUS_ATTESTATION_KEY) == PROVISION_STATUS_ATTESTATION_KEY) { - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); - } else { - processProvisionAttestationKey(apdu); - provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_ATTESTATION_KEY; - handleStateTransition(); - sendError(apdu, KMError.OK); - } - break; - } + processProvisionAttestationKey(apdu); + provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_ATTESTATION_KEY; + sendError(apdu, KMError.OK); + break; + case INS_PROVISION_ATTESTATION_CERT_CHAIN_CMD: - { - if ((provisionStatus & PROVISION_STATUS_ATTESTATION_CERT_CHAIN) - == PROVISION_STATUS_ATTESTATION_CERT_CHAIN) { - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); - } else { - processProvisionAttestationCertChainCmd(apdu); - provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_ATTESTATION_CERT_CHAIN; - handleStateTransition(); - sendError(apdu, KMError.OK); - } - break; - } - case INS_PROVISION_ATTESTATION_CERT_PARAMS_CMD: - { - if ((provisionStatus & PROVISION_STATUS_ATTESTATION_CERT_PARAMS) - == PROVISION_STATUS_ATTESTATION_CERT_PARAMS) { - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); - } else { - processProvisionAttestationCertParams(apdu); - provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_ATTESTATION_CERT_PARAMS; - handleStateTransition(); - sendError(apdu, KMError.OK); - } - break; - } - case INS_GET_PROVISION_STATUS_CMD: - processGetProvisionStatusCmd(apdu); + processProvisionAttestationCertChainCmd(apdu); + provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_ATTESTATION_CERT_CHAIN; + sendError(apdu, KMError.OK); break; - default: - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + + case INS_PROVISION_ATTESTATION_CERT_PARAMS_CMD: + processProvisionAttestationCertParams(apdu); + provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_ATTESTATION_CERT_PARAMS; + sendError(apdu, KMError.OK); break; - } - } else if (keymasterState == KMKeymasterApplet.PROVISIONED_AKEY_ACERT_STATE) { - switch (apduIns) { + case INS_PROVISION_ATTEST_IDS_CMD: processProvisionAttestIdsCmd(apdu); provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_ATTEST_IDS; - handleStateTransition(); sendError(apdu, KMError.OK); break; + case INS_PROVISION_SHARED_SECRET_CMD: processProvisionSharedSecretCmd(apdu); provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_SHARED_SECRET; - handleStateTransition(); - sendError(apdu, KMError.OK); - break; - case INS_COMMIT_ATTESTIDS_SHARED_SECRET_CMD: - processCommitAttestIDSharedSecretCmd(apdu); - provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_APPLET_PROVISIONED; - handleStateTransition(); sendError(apdu, KMError.OK); break; - case INS_GET_PROVISION_STATUS_CMD: - processGetProvisionStatusCmd(apdu); - break; - default: - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + + case INS_LOCK_PROVISIONING_CMD: + if (isProvisioningComplete()) { + provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_PROVISIONING_LOCKED; + keymasterState = KMKeymasterApplet.ACTIVE_STATE; + sendError(apdu, KMError.OK); + return; + } else { + ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + } break; } - } else if (keymasterState == KMKeymasterApplet.PROVISIONED_AKEY_ACERT_AID_SS_STATE) { + } + + if ((keymasterState == KMKeymasterApplet.ACTIVE_STATE) + || (keymasterState == KMKeymasterApplet.IN_PROVISION_STATE)) { switch (apduIns) { case INS_SET_BOOT_PARAMS_CMD: + if (seProvider.isBootSignalEventSupported() + && (!seProvider.isDeviceRebooted())) { + ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); + } + seProvider.setDeviceBooted(false); processSetBootParamsCmd(apdu); - handleStateTransition(); + provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_BOOT_PARAM; sendError(apdu, KMError.OK); break; + case INS_GET_PROVISION_STATUS_CMD: processGetProvisionStatusCmd(apdu); break; - default: - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); - break; } + } - } else { // ACTIVE_STATE - if (seProvider.isBootSignalEventSupported() && (apduIns == INS_SET_BOOT_PARAMS_CMD)) { - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); - } - // Handle the command + if ((keymasterState == KMKeymasterApplet.ACTIVE_STATE) + || ((keymasterState == KMKeymasterApplet.IN_PROVISION_STATE) + && isProvisioningComplete())) { switch (apduIns) { - case INS_SET_BOOT_PARAMS_CMD: - processSetBootParamsCmd(apdu); - handleStateTransition(); - sendError(apdu, KMError.OK); - break; case INS_GENERATE_KEY_CMD: processGenerateKey(apdu); break; @@ -465,9 +432,6 @@ public void process(APDU apdu) { case INS_ABORT_OPERATION_CMD: processAbortOperationCmd(apdu); break; - case INS_GET_PROVISION_STATUS_CMD: - processGetProvisionStatusCmd(apdu); - break; case INS_DEVICE_LOCKED_CMD: processDeviceLockedCmd(apdu); break; @@ -493,6 +457,18 @@ public void process(APDU apdu) { } } + private boolean isProvisioningComplete() { + if((0 != (provisionStatus & PROVISION_STATUS_ATTESTATION_KEY)) + && (0 != (provisionStatus & PROVISION_STATUS_ATTESTATION_CERT_CHAIN)) + && (0 != (provisionStatus & PROVISION_STATUS_ATTESTATION_CERT_PARAMS)) + && (0 != (provisionStatus & PROVISION_STATUS_SHARED_SECRET)) + && (0 != (provisionStatus & PROVISION_STATUS_BOOT_PARAM))) { + return true; + } else { + return false; + } + } + private void freeOperations() { if (data[OP_HANDLE] != KMType.INVALID_VALUE) { KMOperationState op = repository.findOperation(KMInteger.cast(data[OP_HANDLE]).getShort()); @@ -629,31 +605,6 @@ private void processGetCertChainCmd(APDU apdu) { sendOutgoing(apdu); } - private void handleStateTransition() { - byte currentKMState = keymasterState; - byte nextKMState = keymasterState; - if (currentKMState == KMKeymasterApplet.FIRST_SELECT_STATE) { - if (provisionStatus - == (PROVISION_STATUS_ATTESTATION_KEY - | PROVISION_STATUS_ATTESTATION_CERT_CHAIN - | PROVISION_STATUS_ATTESTATION_CERT_PARAMS)) { - nextKMState = KMKeymasterApplet.PROVISIONED_AKEY_ACERT_STATE; - } - } else if (currentKMState == KMKeymasterApplet.PROVISIONED_AKEY_ACERT_STATE) { - if (provisionStatus - == (PROVISION_STATUS_ATTESTATION_KEY - | PROVISION_STATUS_ATTESTATION_CERT_CHAIN - | PROVISION_STATUS_ATTESTATION_CERT_PARAMS - | PROVISION_STATUS_ATTEST_IDS - | PROVISION_STATUS_SHARED_SECRET - | PROVISION_STATUS_APPLET_PROVISIONED)) { - nextKMState = KMKeymasterApplet.PROVISIONED_AKEY_ACERT_AID_SS_STATE; - } - } else if (currentKMState == KMKeymasterApplet.PROVISIONED_AKEY_ACERT_AID_SS_STATE) { - nextKMState = KMKeymasterApplet.ACTIVE_STATE; - } - keymasterState = nextKMState; - } private void processProvisionAttestationCertParams(APDU apdu) { receiveIncoming(apdu); @@ -821,14 +772,6 @@ private void processProvisionSharedSecretCmd(APDU apdu) { KMByteBlob.cast(tmpVariables[0]).length()); } - private void processCommitAttestIDSharedSecretCmd(APDU apdu) { - // Check if shared secret is persisted. If not persisted throw error. - short keyBlob = repository.getSharedKey(); - if (KMByteBlob.cast(keyBlob).length() == 0) { - KMException.throwIt(KMError.KEY_NOT_YET_VALID); - } - } - private void processGetProvisionStatusCmd(APDU apdu) { tmpVariables[0] = KMArray.instance((short) 2); KMArray.cast(tmpVariables[0]).add((short) 0, KMInteger.uint_16(KMError.OK)); @@ -1448,6 +1391,7 @@ private void processAttestKeyCmd(APDU apdu) { bufferLength = (short) (cert.getCertLength() + (cert.getCertStart() - bufferStartOffset)); sendOutgoing(apdu); } + // -------------------------------- private void addAttestationIds(KMAttestationCert cert) { final short[] attTags = @@ -1502,6 +1446,7 @@ private void addTags(short params, boolean hwEnforced, KMAttestationCert cert) { index++; } } + // -------------------------------------- private short convertToDate(short time, byte[] scratchPad, boolean utcFlag) { short yrsCount = 0; @@ -1601,15 +1546,18 @@ private short convertToDate(short time, byte[] scratchPad, boolean utcFlag) { len += numberToString(ssCount, scratchPad, len); scratchPad[len] = Z; len++; - if (utcFlag) return KMByteBlob.instance(scratchPad, (short) 2, (short) (len - 2)); // YY - else return KMByteBlob.instance(scratchPad, (short) 0, len); // YYYY + if (utcFlag) + return KMByteBlob.instance(scratchPad, (short) 2, (short) (len - 2)); // YY + else + return KMByteBlob.instance(scratchPad, (short) 0, len); // YYYY } private short numberToString(short number, byte[] scratchPad, short offset) { byte zero = 0x30; byte len = 2; byte digit; - if (number > 999) len = 4; + if (number > 999) + len = 4; byte index = len; while (index > 0) { digit = (byte) (number % 10); @@ -2013,14 +1961,17 @@ private void finishSigningVerifyingOperation(KMOperationState op, byte[] scratch } break; case KMType.HMAC: - // For HMAC, either sign or verify we do sign operation only and we compare the - // signature manually. The reason for doing this is the TAG_MAC_LENGTH can be 32 bytes - // length or less than that in case if it is less than 32 we are truncating it and sending - // back to the user. For Verify user will send the truncated and if we pass the truncated - // signature to javacard verify API it will fail because it expects the full length - // signature. - // digest is always present. - // len of signature will always be 32 bytes. + // As per Keymaster HAL documentation, the length of the Hmac output can + // be decided by using TAG_MAC_LENGTH in Keyparameters. But there is no + // such provision to control the length of the Hmac output using JavaCard + // crypto APIs and the current implementation always returns 32 bytes + // length of Hmac output. So to provide support to TAG_MAC_LENGTH + // feature, we truncate the output signature to TAG_MAC_LENGTH and return + // the truncated signature back to the caller. At the time of verfication + // we again compute the signature of the plain text input, truncate it to + // TAG_MAC_LENGTH and compare it with the input signature for + // verification. So this is the reason we are using KMType.SIGN directly + // instead of using op.getPurpose(). op.getOperation() .sign( KMByteBlob.cast(data[INPUT_DATA]).getBuffer(), @@ -2387,7 +2338,8 @@ private void processBeginOperationCmd(APDU apdu) { tmpVariables[0] = KMEnum.cast(tmpVariables[0]).getVal(); data[HW_TOKEN] = KMArray.cast(args).get((short) 3); KMOperationState op = repository.reserveOperation(); - if (op == null) KMException.throwIt(KMError.TOO_MANY_OPERATIONS); + if (op == null) + KMException.throwIt(KMError.TOO_MANY_OPERATIONS); data[OP_HANDLE] = op.getHandle(); op.setPurpose((byte) tmpVariables[0]); op.setKeySize(KMByteBlob.cast(data[SECRET]).length()); diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java b/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java index 1adf798e..140e7981 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java @@ -512,4 +512,17 @@ KMOperation initAsymmetricOperation( * @return true if supported, false otherwise. */ boolean isBootSignalEventSupported(); + + /** + * This function tells if the device is booted or not. + * + * @return true if device booted, false otherwise. + */ + boolean isDeviceRebooted(); + + /** + * This function is supposed to be used to reset the device booted stated after set boot param is handled + * @param resetBootFlag is false if event has been handled + */ + void setDeviceBooted(boolean resetBootFlag); } From 0259beff19976195ad4bd385305b0d5b0e12a8c2 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Mon, 23 Nov 2020 21:39:05 +0000 Subject: [PATCH 21/42] 1. Rearranged the Instruction set. 2. Renamed setDeviceBooted to clearDeviceBooted. 3. Removed UINSTALLED_STATE, INACTIVE_STATE. --- .../javacard/keymaster/AndroidSEProvider.java | 2 +- .../javacard/keymaster/KMJcardSimulator.java | 2 +- .../javacard/keymaster/KMKeymasterApplet.java | 114 +++++++++--------- .../javacard/keymaster/KMSEProvider.java | 2 +- 4 files changed, 57 insertions(+), 63 deletions(-) diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java index bc06cf6e..2040b9b2 100644 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java +++ b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java @@ -1251,7 +1251,7 @@ public boolean isDeviceRebooted() { } @Override - public void setDeviceBooted(boolean resetBootFlag) { + public void clearDeviceBooted(boolean resetBootFlag) { // To be filled } diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java index 85f26c5b..5da8dd2e 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java +++ b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java @@ -1357,7 +1357,7 @@ public boolean isDeviceRebooted() { } @Override - public void setDeviceBooted(boolean resetBootFlag) { + public void clearDeviceBooted(boolean resetBootFlag) { // To be filled } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 008211e2..49789f13 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -63,47 +63,50 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe }; // Possible states of the applet. - private static final byte ILLEGAL_STATE = 0x00; - private static final byte INIT_STATE = 0x01; - private static final byte IN_PROVISION_STATE = 0x02; - private static final byte ACTIVE_STATE = 0x03; - private static final byte INACTIVE_STATE = 0x04; - private static final byte UNINSTALLED_STATE = 0x05; - // Commands - private static final byte INS_BEGIN_KM_CMD = 0x09; - private static final byte INS_GENERATE_KEY_CMD = 0x10; - private static final byte INS_IMPORT_KEY_CMD = 0x11; - private static final byte INS_IMPORT_WRAPPED_KEY_CMD = 0x12; - private static final byte INS_EXPORT_KEY_CMD = 0x13; - private static final byte INS_ATTEST_KEY_CMD = 0x14; - private static final byte INS_UPGRADE_KEY_CMD = 0x15; - private static final byte INS_DELETE_KEY_CMD = 0x16; - private static final byte INS_DELETE_ALL_KEYS_CMD = 0x17; - private static final byte INS_ADD_RNG_ENTROPY_CMD = 0x18; - private static final byte INS_COMPUTE_SHARED_HMAC_CMD = 0x19; - private static final byte INS_DESTROY_ATT_IDS_CMD = 0x1A; - private static final byte INS_VERIFY_AUTHORIZATION_CMD = 0x1B; - private static final byte INS_GET_HMAC_SHARING_PARAM_CMD = 0x1C; - private static final byte INS_GET_KEY_CHARACTERISTICS_CMD = 0x1D; - private static final byte INS_GET_HW_INFO_CMD = 0x1E; - private static final byte INS_BEGIN_OPERATION_CMD = 0x1F; - private static final byte INS_UPDATE_OPERATION_CMD = 0x20; - private static final byte INS_FINISH_OPERATION_CMD = 0x21; - private static final byte INS_ABORT_OPERATION_CMD = 0x22; - private static final byte INS_SET_BOOT_PARAMS_CMD = 0x23; - private static final byte INS_DEVICE_LOCKED_CMD = 0x24; - private static final byte INS_EARLY_BOOT_ENDED_CMD = 0x25; - private static final byte INS_GET_CERT_CHAIN_CMD = 0x26; + private static final byte KM_BEGIN_STATE = 0x00; + private static final byte ILLEGAL_STATE = KM_BEGIN_STATE + 1; + private static final byte INIT_STATE = KM_BEGIN_STATE + 2; + private static final byte IN_PROVISION_STATE = KM_BEGIN_STATE + 3; + private static final byte ACTIVE_STATE = KM_BEGIN_STATE + 4; + // Commands + private static final byte INS_BEGIN_KM_CMD = 0x00; // Instructions for Provision Commands. - private static final byte INS_PROVISION_ATTESTATION_KEY_CMD = 0x27; - private static final byte INS_PROVISION_ATTESTATION_CERT_CHAIN_CMD = 0x28; - private static final byte INS_PROVISION_ATTESTATION_CERT_PARAMS_CMD = 0x29; - private static final byte INS_PROVISION_ATTEST_IDS_CMD = 0x2A; - private static final byte INS_PROVISION_SHARED_SECRET_CMD = 0x2B; - private static final byte INS_LOCK_PROVISIONING_CMD = 0x2C; - private static final byte INS_GET_PROVISION_STATUS_CMD = 0x2D; - private static final byte INS_END_KM_CMD = 0x2E; + private static final byte INS_PROVISION_ATTESTATION_KEY_CMD = INS_BEGIN_KM_CMD + 1; + private static final byte INS_PROVISION_ATTESTATION_CERT_CHAIN_CMD = INS_BEGIN_KM_CMD + 2; + private static final byte INS_PROVISION_ATTESTATION_CERT_PARAMS_CMD = INS_BEGIN_KM_CMD + 3; + private static final byte INS_PROVISION_ATTEST_IDS_CMD = INS_BEGIN_KM_CMD + 4; + private static final byte INS_PROVISION_SHARED_SECRET_CMD = INS_BEGIN_KM_CMD + 5; + private static final byte INS_SET_BOOT_PARAMS_CMD = INS_BEGIN_KM_CMD + 6; + private static final byte INS_LOCK_PROVISIONING_CMD = INS_BEGIN_KM_CMD + 7; + private static final byte INS_GET_PROVISION_STATUS_CMD = INS_BEGIN_KM_CMD + 8; + // Top 32 commands are reserved for provisioning. + private static final byte INS_END_KM_PROVISION_CMD = 0x20; + + private static final byte INS_GENERATE_KEY_CMD = INS_END_KM_PROVISION_CMD + 1; + private static final byte INS_IMPORT_KEY_CMD = INS_END_KM_PROVISION_CMD + 2; + private static final byte INS_IMPORT_WRAPPED_KEY_CMD = INS_END_KM_PROVISION_CMD + 3; + private static final byte INS_EXPORT_KEY_CMD = INS_END_KM_PROVISION_CMD + 4; + private static final byte INS_ATTEST_KEY_CMD = INS_END_KM_PROVISION_CMD + 5; + private static final byte INS_UPGRADE_KEY_CMD = INS_END_KM_PROVISION_CMD + 6; + private static final byte INS_DELETE_KEY_CMD = INS_END_KM_PROVISION_CMD + 7; + private static final byte INS_DELETE_ALL_KEYS_CMD = INS_END_KM_PROVISION_CMD + 8; + private static final byte INS_ADD_RNG_ENTROPY_CMD = INS_END_KM_PROVISION_CMD + 9; + private static final byte INS_COMPUTE_SHARED_HMAC_CMD = INS_END_KM_PROVISION_CMD + 10; + private static final byte INS_DESTROY_ATT_IDS_CMD = INS_END_KM_PROVISION_CMD + 11; + private static final byte INS_VERIFY_AUTHORIZATION_CMD = INS_END_KM_PROVISION_CMD + 12; + private static final byte INS_GET_HMAC_SHARING_PARAM_CMD = INS_END_KM_PROVISION_CMD + 13; + private static final byte INS_GET_KEY_CHARACTERISTICS_CMD = INS_END_KM_PROVISION_CMD + 14; + private static final byte INS_GET_HW_INFO_CMD = INS_END_KM_PROVISION_CMD + 15; + private static final byte INS_BEGIN_OPERATION_CMD = INS_END_KM_PROVISION_CMD + 16; + private static final byte INS_UPDATE_OPERATION_CMD = INS_END_KM_PROVISION_CMD + 17; + private static final byte INS_FINISH_OPERATION_CMD = INS_END_KM_PROVISION_CMD + 18; + private static final byte INS_ABORT_OPERATION_CMD = INS_END_KM_PROVISION_CMD + 19; + private static final byte INS_DEVICE_LOCKED_CMD = INS_END_KM_PROVISION_CMD + 20; + private static final byte INS_EARLY_BOOT_ENDED_CMD = INS_END_KM_PROVISION_CMD + 21; + private static final byte INS_GET_CERT_CHAIN_CMD = INS_END_KM_PROVISION_CMD + 22; + + private static final byte INS_END_KM_CMD = 0x7F; // Provision reporting status private static final byte NOT_PROVISIONED = 0x00; @@ -239,8 +242,6 @@ public boolean select() { repository.onSelect(); if (keymasterState == KMKeymasterApplet.INIT_STATE) { keymasterState = KMKeymasterApplet.IN_PROVISION_STATE; - } else if (keymasterState == KMKeymasterApplet.INACTIVE_STATE) { - keymasterState = KMKeymasterApplet.ACTIVE_STATE; } return true; } @@ -249,18 +250,12 @@ public boolean select() { @Override public void deselect() { repository.onDeselect(); - if (keymasterState == KMKeymasterApplet.ACTIVE_STATE) { - keymasterState = KMKeymasterApplet.INACTIVE_STATE; - } } /** Uninstalls the applet after cleaning the repository. */ @Override public void uninstall() { repository.onUninstall(); - if (keymasterState != KMKeymasterApplet.UNINSTALLED_STATE) { - keymasterState = KMKeymasterApplet.UNINSTALLED_STATE; - } } /** @@ -273,9 +268,7 @@ public void process(APDU apdu) { repository.onProcess(); // Verify whether applet is in correct state. if ((keymasterState == KMKeymasterApplet.INIT_STATE) - || (keymasterState == KMKeymasterApplet.INACTIVE_STATE) - || (keymasterState == KMKeymasterApplet.ILLEGAL_STATE) - || (keymasterState == KMKeymasterApplet.UNINSTALLED_STATE)) { + || (keymasterState == KMKeymasterApplet.ILLEGAL_STATE)) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } // If this is select applet apdu which is selecting this applet then return @@ -312,42 +305,41 @@ public void process(APDU apdu) { processProvisionAttestationKey(apdu); provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_ATTESTATION_KEY; sendError(apdu, KMError.OK); - break; + return; case INS_PROVISION_ATTESTATION_CERT_CHAIN_CMD: processProvisionAttestationCertChainCmd(apdu); provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_ATTESTATION_CERT_CHAIN; sendError(apdu, KMError.OK); - break; + return; case INS_PROVISION_ATTESTATION_CERT_PARAMS_CMD: processProvisionAttestationCertParams(apdu); provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_ATTESTATION_CERT_PARAMS; sendError(apdu, KMError.OK); - break; + return; case INS_PROVISION_ATTEST_IDS_CMD: processProvisionAttestIdsCmd(apdu); provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_ATTEST_IDS; sendError(apdu, KMError.OK); - break; + return; case INS_PROVISION_SHARED_SECRET_CMD: processProvisionSharedSecretCmd(apdu); provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_SHARED_SECRET; sendError(apdu, KMError.OK); - break; + return; case INS_LOCK_PROVISIONING_CMD: if (isProvisioningComplete()) { provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_PROVISIONING_LOCKED; keymasterState = KMKeymasterApplet.ACTIVE_STATE; sendError(apdu, KMError.OK); - return; } else { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } - break; + return; } } @@ -359,15 +351,15 @@ public void process(APDU apdu) { && (!seProvider.isDeviceRebooted())) { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } - seProvider.setDeviceBooted(false); + seProvider.clearDeviceBooted(false); processSetBootParamsCmd(apdu); provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_BOOT_PARAM; sendError(apdu, KMError.OK); - break; + return; case INS_GET_PROVISION_STATUS_CMD: processGetProvisionStatusCmd(apdu); - break; + return; } } @@ -444,6 +436,8 @@ && isProvisioningComplete())) { default: ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); } + } else { + ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } } catch (KMException exception) { freeOperations(); diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java b/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java index 140e7981..58e51692 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java @@ -524,5 +524,5 @@ KMOperation initAsymmetricOperation( * This function is supposed to be used to reset the device booted stated after set boot param is handled * @param resetBootFlag is false if event has been handled */ - void setDeviceBooted(boolean resetBootFlag); + void clearDeviceBooted(boolean resetBootFlag); } From eff52b7901eb9dd30ecd901122d11a01b02ab028 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Tue, 24 Nov 2020 00:35:02 +0000 Subject: [PATCH 22/42] 1. Modified certChain command. --- .../android/javacard/keymaster/KMDecoder.java | 32 +++---------------- .../javacard/keymaster/KMKeymasterApplet.java | 32 +++++++------------ 2 files changed, 15 insertions(+), 49 deletions(-) diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMDecoder.java b/Applet/Applet/src/com/android/javacard/keymaster/KMDecoder.java index 6a12379c..948728ec 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMDecoder.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMDecoder.java @@ -21,7 +21,6 @@ import javacard.framework.Util; public class KMDecoder { - public static final short CONTEXT_LEN = 6; // major types private static final short UINT_TYPE = 0x00; private static final short BYTES_TYPE = 0x40; @@ -409,36 +408,13 @@ private void incrementStartOff(short inc) { } } - // Context holds below values - // 1. number of certificates. - // 2. number of certificates read. - // 3. Relative offset from where next certificate will start. - public void incrementalReceiveAndValidateCertificateChain(byte[] context, - short contextStart, short contextLen, byte[] buf, short bufOffset, + public short readCertificateChainLengthAndHeaderLen(byte[] buf, short bufOffset, short bufLen) { - short payLoadLength; - short index = 0; this.buffer = buf; this.startOff = bufOffset; this.length = (short) (bufOffset + bufLen); - // Increment the startOff to the cert data starting location. - startOff += Util.getShort(context, (short) (contextStart + 4)); - if (0 == Util.getShort(context, contextStart)) { - payLoadLength = readMajorTypeWithPayloadLength(ARRAY_TYPE); - if (0 == payLoadLength) - ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); - Util.setShort(context, contextStart, payLoadLength); - } - while (startOff < length) { - if (Util.getShort(context, contextStart) <= Util.getShort(context, - (short) (contextStart + 2))) { - ISOException.throwIt(ISO7816.SW_DATA_INVALID); - } - payLoadLength = readMajorTypeWithPayloadLength(BYTES_TYPE); - Util.setShort(context, (short) (contextStart + 2), ++index); - startOff += payLoadLength; - } - Util.setShort(context, (short) (contextStart + 4), - (short) (startOff - length)); + short totalLen = readMajorTypeWithPayloadLength(BYTES_TYPE); + totalLen += (short)( startOff - bufOffset); + return totalLen; } } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 49789f13..e039f09b 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -351,9 +351,9 @@ public void process(APDU apdu) { && (!seProvider.isDeviceRebooted())) { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } - seProvider.clearDeviceBooted(false); processSetBootParamsCmd(apdu); provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_BOOT_PARAM; + seProvider.clearDeviceBooted(false); sendError(apdu, KMError.OK); return; @@ -639,30 +639,20 @@ private void processProvisionAttestationCertChainCmd(APDU apdu) { short srcOffset = apdu.getOffsetCdata(); bufferLength = apdu.getIncomingLength(); short bytesRead = 0; - // Receive data - if (bufferLength > MAX_IO_LENGTH) { - ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); - } - - short context = KMByteBlob.instance(KMDecoder.CONTEXT_LEN); - Util.arrayFillNonAtomic( - KMByteBlob.cast(context).getBuffer(), - KMByteBlob.cast(context).getStartOff(), - KMByteBlob.cast(context).length(), - (byte) 0); + // tmpVariables[1] holds the total length + Header length. + tmpVariables[1] = decoder.readCertificateChainLengthAndHeaderLen(srcBuffer, + srcOffset, recvLen); while (recvLen > 0 && ((short) bytesRead <= bufferLength)) { - Util.arrayCopyNonAtomic(srcBuffer, srcOffset, buffer, bufferStartOffset, recvLen); - decoder.incrementalReceiveAndValidateCertificateChain( - KMByteBlob.cast(context).getBuffer(), - KMByteBlob.cast(context).getStartOff(), - KMByteBlob.cast(context).length(), - buffer, - bufferStartOffset, - recvLen); - seProvider.persistPartialCertificateChain(buffer, bufferStartOffset, recvLen, bufferLength); + Util.arrayCopyNonAtomic(srcBuffer, srcOffset, buffer, bufferStartOffset, + recvLen); + seProvider.persistPartialCertificateChain(buffer, bufferStartOffset, + recvLen, bufferLength); bytesRead += recvLen; recvLen = apdu.receiveBytes(srcOffset); } + if (tmpVariables[1] != bytesRead) { + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + } } private void processProvisionAttestationKey(APDU apdu) { From 7421351e9071e3c12a17ce3f79d255ea0979db55 Mon Sep 17 00:00:00 2001 From: mdwivedi Date: Mon, 23 Nov 2020 18:50:57 -0800 Subject: [PATCH 23/42] Update KMKeymasterApplet.java Added real numbers for reference (to be referred in design doc too) --- .../javacard/keymaster/KMKeymasterApplet.java | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index e039f09b..8ee56ad2 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -72,39 +72,39 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe // Commands private static final byte INS_BEGIN_KM_CMD = 0x00; // Instructions for Provision Commands. - private static final byte INS_PROVISION_ATTESTATION_KEY_CMD = INS_BEGIN_KM_CMD + 1; - private static final byte INS_PROVISION_ATTESTATION_CERT_CHAIN_CMD = INS_BEGIN_KM_CMD + 2; - private static final byte INS_PROVISION_ATTESTATION_CERT_PARAMS_CMD = INS_BEGIN_KM_CMD + 3; - private static final byte INS_PROVISION_ATTEST_IDS_CMD = INS_BEGIN_KM_CMD + 4; - private static final byte INS_PROVISION_SHARED_SECRET_CMD = INS_BEGIN_KM_CMD + 5; - private static final byte INS_SET_BOOT_PARAMS_CMD = INS_BEGIN_KM_CMD + 6; - private static final byte INS_LOCK_PROVISIONING_CMD = INS_BEGIN_KM_CMD + 7; - private static final byte INS_GET_PROVISION_STATUS_CMD = INS_BEGIN_KM_CMD + 8; + private static final byte INS_PROVISION_ATTESTATION_KEY_CMD = INS_BEGIN_KM_CMD + 1; //0x01 + private static final byte INS_PROVISION_ATTESTATION_CERT_CHAIN_CMD = INS_BEGIN_KM_CMD + 2; //0x02 + private static final byte INS_PROVISION_ATTESTATION_CERT_PARAMS_CMD = INS_BEGIN_KM_CMD + 3; //0x03 + private static final byte INS_PROVISION_ATTEST_IDS_CMD = INS_BEGIN_KM_CMD + 4; //0x04 + private static final byte INS_PROVISION_SHARED_SECRET_CMD = INS_BEGIN_KM_CMD + 5; //0x05 + private static final byte INS_SET_BOOT_PARAMS_CMD = INS_BEGIN_KM_CMD + 6; //0x06 + private static final byte INS_LOCK_PROVISIONING_CMD = INS_BEGIN_KM_CMD + 7; //0x07 + private static final byte INS_GET_PROVISION_STATUS_CMD = INS_BEGIN_KM_CMD + 8; //0x08 // Top 32 commands are reserved for provisioning. private static final byte INS_END_KM_PROVISION_CMD = 0x20; - private static final byte INS_GENERATE_KEY_CMD = INS_END_KM_PROVISION_CMD + 1; - private static final byte INS_IMPORT_KEY_CMD = INS_END_KM_PROVISION_CMD + 2; - private static final byte INS_IMPORT_WRAPPED_KEY_CMD = INS_END_KM_PROVISION_CMD + 3; - private static final byte INS_EXPORT_KEY_CMD = INS_END_KM_PROVISION_CMD + 4; - private static final byte INS_ATTEST_KEY_CMD = INS_END_KM_PROVISION_CMD + 5; - private static final byte INS_UPGRADE_KEY_CMD = INS_END_KM_PROVISION_CMD + 6; - private static final byte INS_DELETE_KEY_CMD = INS_END_KM_PROVISION_CMD + 7; - private static final byte INS_DELETE_ALL_KEYS_CMD = INS_END_KM_PROVISION_CMD + 8; - private static final byte INS_ADD_RNG_ENTROPY_CMD = INS_END_KM_PROVISION_CMD + 9; - private static final byte INS_COMPUTE_SHARED_HMAC_CMD = INS_END_KM_PROVISION_CMD + 10; - private static final byte INS_DESTROY_ATT_IDS_CMD = INS_END_KM_PROVISION_CMD + 11; - private static final byte INS_VERIFY_AUTHORIZATION_CMD = INS_END_KM_PROVISION_CMD + 12; - private static final byte INS_GET_HMAC_SHARING_PARAM_CMD = INS_END_KM_PROVISION_CMD + 13; - private static final byte INS_GET_KEY_CHARACTERISTICS_CMD = INS_END_KM_PROVISION_CMD + 14; - private static final byte INS_GET_HW_INFO_CMD = INS_END_KM_PROVISION_CMD + 15; - private static final byte INS_BEGIN_OPERATION_CMD = INS_END_KM_PROVISION_CMD + 16; - private static final byte INS_UPDATE_OPERATION_CMD = INS_END_KM_PROVISION_CMD + 17; - private static final byte INS_FINISH_OPERATION_CMD = INS_END_KM_PROVISION_CMD + 18; - private static final byte INS_ABORT_OPERATION_CMD = INS_END_KM_PROVISION_CMD + 19; - private static final byte INS_DEVICE_LOCKED_CMD = INS_END_KM_PROVISION_CMD + 20; - private static final byte INS_EARLY_BOOT_ENDED_CMD = INS_END_KM_PROVISION_CMD + 21; - private static final byte INS_GET_CERT_CHAIN_CMD = INS_END_KM_PROVISION_CMD + 22; + private static final byte INS_GENERATE_KEY_CMD = INS_END_KM_PROVISION_CMD + 1; //0x21 + private static final byte INS_IMPORT_KEY_CMD = INS_END_KM_PROVISION_CMD + 2; //0x22 + private static final byte INS_IMPORT_WRAPPED_KEY_CMD = INS_END_KM_PROVISION_CMD + 3; //0x23 + private static final byte INS_EXPORT_KEY_CMD = INS_END_KM_PROVISION_CMD + 4; //0x24 + private static final byte INS_ATTEST_KEY_CMD = INS_END_KM_PROVISION_CMD + 5; //0x25 + private static final byte INS_UPGRADE_KEY_CMD = INS_END_KM_PROVISION_CMD + 6; //0x26 + private static final byte INS_DELETE_KEY_CMD = INS_END_KM_PROVISION_CMD + 7; //0x27 + private static final byte INS_DELETE_ALL_KEYS_CMD = INS_END_KM_PROVISION_CMD + 8; //0x28 + private static final byte INS_ADD_RNG_ENTROPY_CMD = INS_END_KM_PROVISION_CMD + 9; //0x29 + private static final byte INS_COMPUTE_SHARED_HMAC_CMD = INS_END_KM_PROVISION_CMD + 10; //0x2A + private static final byte INS_DESTROY_ATT_IDS_CMD = INS_END_KM_PROVISION_CMD + 11; //0x2B + private static final byte INS_VERIFY_AUTHORIZATION_CMD = INS_END_KM_PROVISION_CMD + 12; //0x2C + private static final byte INS_GET_HMAC_SHARING_PARAM_CMD = INS_END_KM_PROVISION_CMD + 13; //0x2D + private static final byte INS_GET_KEY_CHARACTERISTICS_CMD = INS_END_KM_PROVISION_CMD + 14; //0x2E + private static final byte INS_GET_HW_INFO_CMD = INS_END_KM_PROVISION_CMD + 15; //0x2F + private static final byte INS_BEGIN_OPERATION_CMD = INS_END_KM_PROVISION_CMD + 16; //0x30 + private static final byte INS_UPDATE_OPERATION_CMD = INS_END_KM_PROVISION_CMD + 17; //0x31 + private static final byte INS_FINISH_OPERATION_CMD = INS_END_KM_PROVISION_CMD + 18; //0x32 + private static final byte INS_ABORT_OPERATION_CMD = INS_END_KM_PROVISION_CMD + 19; //0x33 + private static final byte INS_DEVICE_LOCKED_CMD = INS_END_KM_PROVISION_CMD + 20;//0x34 + private static final byte INS_EARLY_BOOT_ENDED_CMD = INS_END_KM_PROVISION_CMD + 21; //0x35 + private static final byte INS_GET_CERT_CHAIN_CMD = INS_END_KM_PROVISION_CMD + 22; //0x36 private static final byte INS_END_KM_CMD = 0x7F; From cbed872bf3c0abbb64c3b9e8925fa49706f296e8 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Tue, 24 Nov 2020 14:05:59 +0000 Subject: [PATCH 24/42] Removed BackupRestoreApplet --- .../javacard/keymaster/AndroidSEProvider.java | 70 +------------ .../keymaster/KMBackupRestoreAgent.java | 11 --- .../keymaster/KMBackupStoreApplet.java | 97 ------------------- .../javacard/keymaster/KMJcardSimulator.java | 85 ---------------- .../javacard/keymaster/KMKeymasterApplet.java | 11 ++- .../javacard/keymaster/KMSEProvider.java | 46 +-------- 6 files changed, 9 insertions(+), 311 deletions(-) delete mode 100644 Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java delete mode 100644 Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java index 2040b9b2..77e93dc3 100644 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java +++ b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java @@ -15,9 +15,6 @@ */ package com.android.javacard.keymaster; -import javacard.framework.AID; -import javacard.framework.ISO7816; -import javacard.framework.ISOException; import javacard.framework.JCSystem; import javacard.framework.Util; import javacard.security.AESKey; @@ -107,8 +104,6 @@ public class AndroidSEProvider implements KMSEProvider { public static final short TMP_ARRAY_SIZE = 256; public static final short NUM_OF_CERTS = 1; public static final short CERT_CHAIN_MAX_SIZE = 2050;//First 2 bytes for length. - private static final byte[] aidArr = new byte[] { - (byte)0xA0, 0x00, 0x00, 0x00, 0x63}; final byte[] CIPHER_ALGS = { Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, @@ -1130,52 +1125,6 @@ public short aesCCMSign(byte[] bufIn, short bufInStart, short buffInLength, return kdf.sign(bufIn, bufInStart, buffInLength, bufOut, bufStart); } - @Override - public boolean isBackupRestoreSupported() { - return true; - } - - @Override - public void backup(byte[] buf, short start, short len) { - short certChainLen = Util.getShort(certificateChain, (short) 0); - certChainLen += 2; //including the length of certifcate. - AID aid = JCSystem.lookupAID(aidArr, (short) 0, (byte) aidArr.length); - if (null == aid) - ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED); - KMBackupRestoreAgent backupStore = (KMBackupRestoreAgent) JCSystem - .getAppletShareableInterfaceObject(aid, (byte) 0); - backupStore.backupProviderData(certificateChain, (short)0, certChainLen); - backupStore.backup(buf, (short) start, len); - } - - @Override - public short restore(byte[] buf, short start) { - AID aid = JCSystem.lookupAID(aidArr, (short) 0, (byte) aidArr.length); - if (null == aid) - ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED); - KMBackupRestoreAgent backupStore = (KMBackupRestoreAgent) JCSystem - .getAppletShareableInterfaceObject(aid, (byte) 0); - short len = backupStore.restore(buf, (short) start); - short heapOff = KMRepository.instance().alloc(CERT_CHAIN_MAX_SIZE); - short certChainLen = backupStore.restoreProviderData(KMRepository - .instance().getHeap(), heapOff); - JCSystem.beginTransaction(); - Util.arrayCopy(KMRepository.instance().getHeap(), heapOff, - certificateChain, (short) 0, certChainLen); - JCSystem.commitTransaction(); - - return len; - } - - @Override - public boolean isBackupAvailable() { - AID aid = JCSystem.lookupAID(aidArr,(short)0,(byte)aidArr.length); - if(null == aid) - return false; - KMBackupRestoreAgent backupStore = (KMBackupRestoreAgent) JCSystem.getAppletShareableInterfaceObject(aid,(byte)0); - return backupStore.isBackupAvailable(); - } - @Override public short cmacKdf(byte[] keyMaterial, short keyMaterialStart, short keyMaterialLen, byte[] label, short labelStart, short labelLen, @@ -1187,6 +1136,7 @@ public short cmacKdf(byte[] keyMaterial, short keyMaterialStart, } //This function supports multi-part request data. + @Override public void persistPartialCertificateChain(byte[] buf, short offset, short len, short totalLen) { // _____________________________________________________ // | 2 Bytes | 1 Byte | 3 Bytes | Cert1 | 3 Bytes | Cert2|... @@ -1207,22 +1157,6 @@ public void persistPartialCertificateChain(byte[] buf, short offset, short len, JCSystem.commitTransaction(); } - @Override - public void persistCertificateChain(byte[] buf, short offset, short len) { - // _____________________________________________________ - // | 2 Bytes | 1 Byte | 3 Bytes | Cert1 | 3 Bytes | Cert2|... - // |_________|________|_________|_______|_________|______| - // First two bytes holds the length of the total buffer. - // CBOR format: - // Next single byte holds the array header. - // Next 3 bytes holds the Byte array header with the cert1 length. - // Next 3 bytes holds the Byte array header with the cert2 length. - JCSystem.beginTransaction(); - Util.setShort(certificateChain, (short)0, len); - Util.arrayCopyNonAtomic(buf, offset, certificateChain, (short)2, len); - JCSystem.commitTransaction(); - } - @Override public short readCertificateChain(byte[] buf, short offset) { short len = Util.getShort(certificateChain, (short)0); @@ -1254,6 +1188,4 @@ public boolean isDeviceRebooted() { public void clearDeviceBooted(boolean resetBootFlag) { // To be filled } - - } diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java deleted file mode 100644 index 764d4a3e..00000000 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.android.javacard.keymaster; - -import javacard.framework.Shareable; - -public interface KMBackupRestoreAgent extends Shareable { - void backup(byte[] buf, short start, short len); - short restore(byte[] buf, short start); - void backupProviderData(byte[] buf, short start, short len); - short restoreProviderData(byte[] buf, short start); - boolean isBackupAvailable(); -} diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java deleted file mode 100644 index 4e851e5c..00000000 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.android.javacard.keymaster; - -import javacard.framework.AID; -import javacard.framework.APDU; -import javacard.framework.Applet; -import javacard.framework.JCSystem; -import javacard.framework.Shareable; -import javacard.framework.Util; - -public class KMBackupStoreApplet extends Applet implements KMBackupRestoreAgent { - private static final short PROVIDER_MEM_SIZE = 2050; - private static final short KM_APPLET_MEM_SIZE = 2050; - private static final short PROVIDER_OFFSET = 0; - private static final short KM_APPLET_DATA_OFFSET = PROVIDER_MEM_SIZE; - private static final byte[] aidArr = new byte[]{ (byte)0xA0, 0x00, 0x00, 0x00, 0x62}; - - private byte[] dataTable; - boolean backupAvailable; - - private KMBackupStoreApplet() { - dataTable = new byte[KM_APPLET_MEM_SIZE + PROVIDER_MEM_SIZE]; - backupAvailable = false; - } - - public static void install(byte bArray[], short bOffset, byte bLength) { - new KMBackupStoreApplet().register(); - } - - @Override - public boolean select() { - return true; - } - - @Override - public void process(APDU apdu) { - - } - - @Override - public void backup(byte[] buf, short start, short len) { - // Store the data - if (len > 0) { - JCSystem.beginTransaction(); - // dataTableSize = len; - Util.setShort(dataTable, KM_APPLET_DATA_OFFSET, len); - Util.arrayCopy(buf, start, dataTable, - (short) (KM_APPLET_DATA_OFFSET + 2), len); - JCSystem.commitTransaction(); - } - backupAvailable = true; - } - - @Override - public short restore(byte[] buf, short start) { - // Restore the data - short len = Util.getShort(dataTable, KM_APPLET_DATA_OFFSET); - Util.arrayCopyNonAtomic(dataTable, (short) (KM_APPLET_DATA_OFFSET + 2), buf, start, - len); - return len; - } - - @Override - public Shareable getShareableInterfaceObject(AID aid, byte param){ - byte[] aidBytes = new byte[10]; - byte len = aid.getBytes(aidBytes, (short)0); - if(Util.arrayCompare(aidArr,(short)0,aidBytes,(short)0,len) == 0){ - return this; - } - return null; - } - - @Override - public boolean isBackupAvailable() { - return backupAvailable; - } - - @Override - public void backupProviderData(byte[] buf, short start, short len) { - // Store the data - if (len > 0) { - JCSystem.beginTransaction(); - Util.arrayCopy(buf, start, dataTable, PROVIDER_OFFSET, len); - JCSystem.commitTransaction(); - } - backupAvailable = true; - } - - @Override - public short restoreProviderData(byte[] buf, short start) { - // Restore the data - short len = Util.getShort(dataTable, PROVIDER_OFFSET); - len += 2;// including length. - Util.arrayCopyNonAtomic(dataTable, PROVIDER_OFFSET, buf, start, len); - return len; - } - -} diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java index 5da8dd2e..8fad85e5 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java +++ b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java @@ -27,7 +27,6 @@ import java.security.spec.RSAPrivateKeySpec; import java.security.spec.RSAPublicKeySpec; -import javacard.framework.AID; import javacard.framework.ISO7816; import javacard.framework.ISOException; import javacard.framework.JCSystem; @@ -41,7 +40,6 @@ import javacard.security.Key; import javacard.security.KeyBuilder; import javacard.security.KeyPair; -import javacard.security.MessageDigest; import javacard.security.RSAPrivateKey; import javacard.security.RSAPublicKey; import javacard.security.RandomData; @@ -71,9 +69,7 @@ public class KMJcardSimulator implements KMSEProvider { public static final short MAX_RND_NUM_SIZE = 64; public static final short ENTROPY_POOL_SIZE = 16; // simulator does not support 256 bit aes keys public static final byte[] aesICV = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - private static final int AES_GCM_KEY_SIZE = 16; private static final short CERT_CHAIN_MAX_SIZE = 2050;//First 2 bytes for length. - private static final byte[] aidArr = new byte[]{ (byte)0xA0, 0x00, 0x00, 0x00, 0x63}; public static final short NUM_OF_CERTS = 1; @@ -1183,9 +1179,6 @@ public KMCipher createRsaCipher(short padding, short digest, byte[] modBuffer, s if (cipherAlg == Cipher.ALG_RSA_PKCS1_OAEP) { return createRsaOAEP256Cipher(KMType.ENCRYPT, (byte)digest, null,(short)0,(short)0,modBuffer,modOff,modLength); } - /*else if(padding == KMCipher.PAD_PKCS1) cipherAlg = Cipher.ALG_RSA_PKCS1; - else cipherAlg = Cipher.ALG_RSA_NOPAD; - */ Cipher rsaCipher = Cipher.getInstance(cipherAlg,false); RSAPublicKey key = (RSAPublicKey) KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PUBLIC, KeyBuilder.LENGTH_RSA_2048, false); byte[] exponent = new byte[]{0x01,0x00,0x01}; @@ -1199,14 +1192,9 @@ public KMCipher createRsaCipher(short padding, short digest, byte[] modBuffer, s return inst; } - public Signature createRsaVerifier(short digest, short padding, byte[] modBuffer, short modOff, short modLength) { short alg = mapSignature256Alg(KMType.RSA,(byte)padding); if(digest == KMType.DIGEST_NONE || padding == KMType.PADDING_NONE) CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - /*else if(padding == KMCipher.PAD_PKCS1_PSS) alg = Signature.ALG_RSA_SHA_256_PKCS1_PSS; - else if(padding == KMCipher.PAD_PKCS1) alg = Signature.ALG_RSA_SHA_256_PKCS1; - else CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - */ Signature rsaVerifier = Signature.getInstance((byte)alg, false); RSAPublicKey key = (RSAPublicKey) KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PUBLIC, KeyBuilder.LENGTH_RSA_2048, false); byte[] exponent = new byte[]{0x01,0x00,0x01}; @@ -1216,7 +1204,6 @@ public Signature createRsaVerifier(short digest, short padding, byte[] modBuffer return rsaVerifier; } - public Signature createEcVerifier(short digest, byte[] pubKey, short pubKeyStart, short pubKeyLength) { short alg = mapSignature256Alg(KMType.EC, (byte)0); Signature ecVerifier; @@ -1232,63 +1219,12 @@ public Signature createEcVerifier(short digest, byte[] pubKey, short pubKeyStart return ecVerifier; } - - @Override - public boolean isBackupRestoreSupported() { - return true; - } - @Override public KMAttestationCert getAttestationCert(boolean rsaCert) { //certBuilder.reset(); return KMAttestationCertImpl.instance(rsaCert); } - @Override - public void backup(byte[] buf, short start, short len) { - short certChainLen = Util.getShort(certificateChain, (short) 0); - certChainLen += 2; // including the length of certifcate. - short arrayLen = (certChainLen > len) ? certChainLen : len; - byte[] data = new byte[arrayLen]; - AID aid = JCSystem.lookupAID(aidArr, (short) 0, (byte) aidArr.length); - KMBackupRestoreAgent backupStore = (KMBackupRestoreAgent) JCSystem - .getAppletShareableInterfaceObject(aid, (byte) 0); - Util.arrayCopyNonAtomic(certificateChain, (short) 0, data, (short) 0, - certChainLen); - backupStore.backupProviderData(data, (short) 0, certChainLen); - Util.arrayCopyNonAtomic(buf, start, data, (short) 0, len); - backupStore.backup(data, (short) 0, len); - } - - @Override - public short restore(byte[] buf, short start) { - byte[] data = new byte[4250]; - AID aid = JCSystem.lookupAID(aidArr, (short) 0, (byte) aidArr.length); - KMBackupRestoreAgent backupStore = (KMBackupRestoreAgent) JCSystem - .getAppletShareableInterfaceObject(aid, (byte) 0); - short len = backupStore.restore(data, (short) 0); - Util.arrayCopyNonAtomic(data, (short) 0, buf, start, (short) len); - start = len; - len = backupStore.restoreProviderData(data, (short) 0); - JCSystem.beginTransaction(); - Util.arrayCopy(data, (short) 0, certificateChain, (short) 0, (short) len); - JCSystem.commitTransaction(); - return start; - } - - @Override - public boolean isBackupAvailable() { - return false; - } - - @Override - public void persistCertificateChain(byte[] buf, short offset, short len) { - JCSystem.beginTransaction(); - Util.setShort(certificateChain, (short)0, len); - Util.arrayCopyNonAtomic(buf, offset, certificateChain, (short)2, len); - JCSystem.commitTransaction(); - } - public short readCertificateChain(byte[] buf, short offset) { short len = Util.getShort(certificateChain, (short)0); Util.arrayCopyNonAtomic(certificateChain, (short)2, buf, offset, len); @@ -1305,7 +1241,6 @@ public short getNumberOfCerts() { return NUM_OF_CERTS; } - @Override public short ecSign256(byte[] secret, short secretStart, short secretLength, byte[] inputDataBuf, short inputDataStart, short inputDataLength, @@ -1322,7 +1257,6 @@ public short ecSign256(byte[] secret, short secretStart, short secretLength, outputDataBuf, outputDataStart); } - @Override public void persistPartialCertificateChain(byte[] buf, short offset, short len, short totalLen) { @@ -1345,7 +1279,6 @@ public void persistPartialCertificateChain(byte[] buf, short offset, JCSystem.commitTransaction(); } - @Override public boolean isBootSignalEventSupported() { return false; @@ -1360,22 +1293,4 @@ public boolean isDeviceRebooted() { public void clearDeviceBooted(boolean resetBootFlag) { // To be filled } - - /* - private static void print (String lab, byte[] b, short s, short l){ - byte[] i = new byte[l]; - Util.arrayCopyNonAtomic(b,s,i,(short)0,l); - print(lab,i); - } - private static void print(String label, byte[] buf){ - System.out.println(label+": "); - StringBuilder sb = new StringBuilder(); - for(int i = 0; i < buf.length; i++){ - sb.append(String.format(" 0x%02X", buf[i])) ; - if(((i-1)%38 == 0) && ((i-1) >0)){ - sb.append(";\n"); - } - } - System.out.println(sb.toString()); - }*/ } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index e039f09b..d6715e03 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -639,16 +639,19 @@ private void processProvisionAttestationCertChainCmd(APDU apdu) { short srcOffset = apdu.getOffsetCdata(); bufferLength = apdu.getIncomingLength(); short bytesRead = 0; + Util.arrayCopyNonAtomic(srcBuffer, srcOffset, buffer, bufferStartOffset, + recvLen); // tmpVariables[1] holds the total length + Header length. - tmpVariables[1] = decoder.readCertificateChainLengthAndHeaderLen(srcBuffer, - srcOffset, recvLen); + tmpVariables[1] = decoder.readCertificateChainLengthAndHeaderLen(buffer, + bufferStartOffset, recvLen); while (recvLen > 0 && ((short) bytesRead <= bufferLength)) { - Util.arrayCopyNonAtomic(srcBuffer, srcOffset, buffer, bufferStartOffset, - recvLen); seProvider.persistPartialCertificateChain(buffer, bufferStartOffset, recvLen, bufferLength); bytesRead += recvLen; recvLen = apdu.receiveBytes(srcOffset); + if (recvLen > 0) + Util.arrayCopyNonAtomic(srcBuffer, srcOffset, buffer, bufferStartOffset, + recvLen); } if (tmpVariables[1] != bytesRead) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java b/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java index 58e51692..04d02300 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java @@ -428,53 +428,9 @@ KMOperation initAsymmetricOperation( */ KMAttestationCert getAttestationCert(boolean rsaCert); - /** - * This operation indicates whether SE Provider supports backup and restore functionality required - * for upgrading the applet. - * - * @return true if backup and restore is supported. - */ - boolean isBackupRestoreSupported(); - - /** - * This operation passes the data that needs to be backup to SE Provider. The exact mechanism to - * backup the data is SE provider implementation specific. - * - * @param buf is the data buffer. - * @param start is the start of the data. - * @param len is the length of the data. - */ - void backup(byte[] buf, short start, short len); - - /** - * This operation retrieves the backed up data from SE Provider. - * - * @param buf is the data buffer. - * @param start is the start of the data. - * @return the length of the data buffer in bytes. - */ - short restore(byte[] buf, short start); - - /** - * This operation returns true if backup is available, otherwise false - * if backup is not available. - * - * @return true if backup is available, false if no backup. - */ - boolean isBackupAvailable(); - - /** - * This operation persists the certificate chain in the persistent memory. - * - * @param buf buffer containing certificate chain. - * @param offset is the start of the buffer. - * @param len is the length of the buffer. - */ - void persistCertificateChain(byte[] buf, short offset, short len); - /** * This operation persists the certificate chain in the persistent memory - * in multiple requets. + * in multiple requests. * * @param buf buffer containing certificate chain. * @param offset is the start of the buffer. From 140a3a4a3685c2695495e4c603c6b3bd335fe66b Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Tue, 24 Nov 2020 15:13:59 +0000 Subject: [PATCH 25/42] Removed OracleSimProvider --- .../javacard/keymaster/KMSEProviderImpl.java | 8 - .../javacard/keymaster/KMSimulator.java | 517 ------------------ 2 files changed, 525 deletions(-) delete mode 100644 Applet/Applet/OracleSimProvider/com/android/javacard/keymaster/KMSEProviderImpl.java delete mode 100644 Applet/Applet/OracleSimProvider/com/android/javacard/keymaster/KMSimulator.java diff --git a/Applet/Applet/OracleSimProvider/com/android/javacard/keymaster/KMSEProviderImpl.java b/Applet/Applet/OracleSimProvider/com/android/javacard/keymaster/KMSEProviderImpl.java deleted file mode 100644 index 9920c4ee..00000000 --- a/Applet/Applet/OracleSimProvider/com/android/javacard/keymaster/KMSEProviderImpl.java +++ /dev/null @@ -1,8 +0,0 @@ - -package com.android.javacard.keymaster; - -public class KMSEProviderImpl { - public static KMSEProvider instance(){ - return new KMSimulator(); - } -} diff --git a/Applet/Applet/OracleSimProvider/com/android/javacard/keymaster/KMSimulator.java b/Applet/Applet/OracleSimProvider/com/android/javacard/keymaster/KMSimulator.java deleted file mode 100644 index a0f41c73..00000000 --- a/Applet/Applet/OracleSimProvider/com/android/javacard/keymaster/KMSimulator.java +++ /dev/null @@ -1,517 +0,0 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.keymaster; - -import javacard.framework.ISO7816; -import javacard.framework.ISOException; -import javacard.framework.JCSystem; -import javacard.framework.Util; -import javacard.security.AESKey; -import javacard.security.CryptoException; -import javacard.security.DESKey; -import javacard.security.ECPrivateKey; -import javacard.security.ECPublicKey; -import javacard.security.HMACKey; -import javacard.security.Key; -import javacard.security.KeyBuilder; -import javacard.security.KeyPair; -import javacard.security.RSAPrivateKey; -import javacard.security.RandomData; -import javacard.security.Signature; -import javacardx.crypto.AEADCipher; -import javacardx.crypto.Cipher; - -/** - * Simulator only supports 512 bit RSA key pair, 128 AES Key, 128 bit 3Des key, less then 256 bit EC - * Key, and upto 512 bit HMAC key. Also simulator does not support TRNG, so this implementation just - * creates its own RNG using PRNG. - */ -public class KMSimulator implements KMSEProvider { - - public static final short AES_GCM_TAG_LENGTH = 12; - public static final short AES_GCM_NONCE_LENGTH = 12; - public static final short MAX_RND_NUM_SIZE = 64; - public static final short ENTROPY_POOL_SIZE = 16; // simulator does not support 256 bit aes keys - public static final byte[] aesICV = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - public static boolean jcardSim = false; - - private static KeyPair rsa512KeyPair; - private static KeyPair ec192KeyPair; - private static AESKey aes128Key; - private static DESKey triDesKey; - private static HMACKey hmac128Key; - private static HMACKey hmac256Key; - private static AEADCipher aesGcmCipher; - private static AESKey derivedKey; - private static Signature kdf; - - private static byte[] rngCounter; - private static AESKey aesRngKey; - private static Cipher aesRngCipher; - private static byte[] entropyPool; - private static byte[] rndNum; - - // Implements Oracle Simulator based restricted crypto provider - public KMSimulator() { - // Various Keys - rsa512KeyPair = new KeyPair(KeyPair.ALG_RSA, KeyBuilder.LENGTH_RSA_512); - ec192KeyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_192); - aes128Key = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false); - triDesKey = - (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES, KeyBuilder.LENGTH_DES3_2KEY, false); - hmac128Key = (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC, (short) 128, false); - hmac256Key = (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC, (short) 256, false); - derivedKey = - (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false); - kdf = Signature.getInstance(Signature.ALG_AES_CMAC_128, false); - - // RNG - rndNum = JCSystem.makeTransientByteArray(MAX_RND_NUM_SIZE, JCSystem.CLEAR_ON_RESET); - entropyPool = JCSystem.makeTransientByteArray(ENTROPY_POOL_SIZE, JCSystem.CLEAR_ON_RESET); - rngCounter = JCSystem.makeTransientByteArray((short) 8, JCSystem.CLEAR_ON_RESET); - initEntropyPool(entropyPool); - try { - aesRngCipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false); - } catch (CryptoException exp) { - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); - } - aesRngKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false); - } - - public KeyPair createRsaKeyPair() { - // By default 65537 is used as public exponent no need to set the public exponent. Now generate - // 512 bit RSA keypair for the given exponent - rsa512KeyPair.genKeyPair(); - return rsa512KeyPair; - } - - public KeyPair createECKeyPair() { - // Simulator does not support 256 bit keys. - // Generate default 192 bit key pair supported by simulator. - ec192KeyPair.genKeyPair(); - return ec192KeyPair; - } - - public AESKey createAESKey(short keysize) { - // keysize is ignored as simulator only supports 128 bit aes key - newRandomNumber(rndNum, (short) 0, (short) 16); - aes128Key.setKey(rndNum, (short) 0); - return aes128Key; - } - - public AESKey createAESKey(byte[] buf, short startOff, short length) { - if (length > 16) length = 16; - else if(length < 16) return null; - aes128Key.setKey(buf, startOff); - return aes128Key; - } - - public DESKey createTDESKey() { - // only 128 bit keys are supported - newRandomNumber(rndNum, (short) 0, (short) 21); - triDesKey.setKey(rndNum, (short) 0); - return triDesKey; - } - - public HMACKey createHMACKey(short keysize) { - // simulator only supports HMAC keys for SHA1 and SHA256 with block size 64. - // So only 128 and 256 bit HMAC keys are supported. - HMACKey key; - if (keysize == 128) { - key = hmac128Key; - keysize = 16; - } else if (keysize == 256) { - key = hmac256Key; - keysize = 32; - } else { - key = hmac128Key; // by default the simulator will return 128 bit keys for SHA1 - keysize = 16; - } - newRandomNumber(rndNum, (short) 0, keysize); - key.setKey(rndNum, (short) 0, keysize); - return key; - } - - @Override - public short createSymmetricKey(byte alg, short keysize, byte[] buf, short startOff) { - return 0; - } - - @Override - public void createAsymmetricKey(byte alg, byte[] privKeyBuf, short privKeyStart, short privKeyLength, byte[] pubModBuf, short pubModStart, short pubModLength, short[] lengths) { - - } - - @Override - public boolean importSymmetricKey(byte alg, short keysize, byte[] buf, short startOff, short length) { - return false; - } - - @Override - public boolean importAsymmetricKey(byte alg, byte[] privKeyBuf, short privKeyStart, short privKeyLength, byte[] pubModBuf, short pubModStart, short pubModLength) { - return false; - } - - @Override - public void addRngEntropy(byte[] num, short offset, short length) { - // Maximum length can be 256 bytes. But currently we support max 32 bytes seed. - // Get existing entropy pool. - if (length > 32) length = 32; - // Create new temporary pool. - // Populate the new pool with the entropy which is derived from current entropy pool. - newRandomNumber(rndNum, (short) 0, (short) entropyPool.length); - // Copy the entropy to the current pool - updates the entropy pool. - Util.arrayCopy(rndNum, (short) 0, entropyPool, (short) 0, (short) entropyPool.length); - short index = 0; - short randIndex = 0; - // XOR the seed received from the master in the entropy pool - 16 bytes (entPool.length). - // at a time. - while (index < length) { - entropyPool[randIndex] = (byte) (entropyPool[randIndex] ^ num[(short) (offset + index)]); - randIndex++; - index++; - if (randIndex >= entropyPool.length) { - randIndex = 0; - } - } - } - - @Override - public void getTrueRandomNumber(byte[] num, short offset, short length) { - // ignore the size as simulator only supports 128 bit entropy - Util.arrayCopy(entropyPool,(short)0,num,offset,length); - } - - @Override - public short aesGCMEncrypt( - byte[] aesKey, - short keyStart, - short keyLen, - byte[] secret, - short secretStart, - short secretLen, - byte[] encSecret, - short encSecretStart, - byte[] nonce, - short nonceStart, - short nonceLen, - byte[] authData, - short authDataStart, - short authDataLen, - byte[] authTag, - short authTagStart, - short authTagLen) { - if (jcardSim) return -1; - if(authTagLen != AES_GCM_TAG_LENGTH){ - KMException.throwIt(KMError.UNKNOWN_ERROR); - } - if(nonceLen != AES_GCM_NONCE_LENGTH){ - KMException.throwIt(KMError.UNKNOWN_ERROR); - } - if (aesGcmCipher == null) { - aesGcmCipher = (AEADCipher) Cipher.getInstance(AEADCipher.ALG_AES_GCM, false); - } - byte[] aad = JCSystem.makeTransientByteArray(authDataLen, JCSystem.CLEAR_ON_RESET); - Util.arrayCopyNonAtomic(authData, authDataStart, aad, (short) 0, authDataLen); - AESKey key = createAESKey(aesKey, keyStart, keyLen); - try { - aesGcmCipher.init(key, Cipher.MODE_ENCRYPT, nonce, nonceStart, nonceLen); - } catch (CryptoException exp) { - KMException.throwIt(exp.getReason()); - } - // add the auth data - try { - aesGcmCipher.updateAAD(aad, (short) 0, authDataLen); - } catch (CryptoException exp) { - KMException.throwIt(exp.getReason()); - } - // encrypt the secret - short ciphLen = aesGcmCipher.doFinal(secret, secretStart, secretLen, encSecret, encSecretStart); - // The tag buffer must be exact size otherwise simulator returns 0 tag. - byte[] tag = JCSystem.makeTransientByteArray(AES_GCM_TAG_LENGTH, JCSystem.CLEAR_ON_RESET); - aesGcmCipher.retrieveTag(tag, (short) 0, AES_GCM_TAG_LENGTH); - Util.arrayCopyNonAtomic(tag,(short)0, authTag, authTagStart,AES_GCM_TAG_LENGTH); - return ciphLen; -/* aesGcmCipher.init(key, Cipher.MODE_DECRYPT, nonce, nonceStart, nonceLen); - try { - aesGcmCipher.updateAAD(aad, (short) 0, authDataLen); - } catch (CryptoException exp) { - KMException.throwIt(exp.getReason()); - } - byte[] plain = JCSystem.makeTransientByteArray(secretLen, JCSystem.CLEAR_ON_RESET); - // encrypt the secret - ciphLen = aesGcmCipher.doFinal(encSecret, encSecretStart, ciphLen, plain, (short) 0); - boolean ver = aesGcmCipher.verifyTag(tag, (short) 0, (short) 12, (short) 12); - if (ver == true) { - KMException.throwIt((short) 10); - } else { - KMException.throwIt((short) 20); - } - return 0; - */ - } - - public boolean aesGCMDecrypt( - byte[] aesKey, - short keyStart, - short keyLen, - byte[] encSecret, - short encSecretStart, - short encSecretLen, - byte[] secret, - short secretStart, - byte[] nonce, - short nonceStart, - short nonceLen, - byte[] authData, - short authDataStart, - short authDataLen, - byte[] authTag, - short authTagStart, - short authTagLen) { - if(jcardSim) return true; - if (aesGcmCipher == null) { - aesGcmCipher = (AEADCipher) Cipher.getInstance(AEADCipher.ALG_AES_GCM, false); - } - // allocate aad buffer of exact size - otherwise simulator throws exception - byte[] aad = JCSystem.makeTransientByteArray(authDataLen, JCSystem.CLEAR_ON_RESET); - Util.arrayCopyNonAtomic(authData, authDataStart, aad, (short) 0, authDataLen); - // allocate tag of exact size. - byte[] tag = JCSystem.makeTransientByteArray(AES_GCM_TAG_LENGTH, JCSystem.CLEAR_ON_RESET); - Util.arrayCopyNonAtomic(authTag, authTagStart, tag, (short) 0, authTagLen); - boolean verification = false; - AESKey key = createAESKey(aesKey, keyStart, keyLen); - try { - aesGcmCipher.init(key, Cipher.MODE_DECRYPT, nonce, nonceStart, nonceLen); - aesGcmCipher.updateAAD(aad, (short) 0, authDataLen); - //byte[] plain = JCSystem.makeTransientByteArray(encSecretLen, JCSystem.CLEAR_ON_RESET); - // encrypt the secret - aesGcmCipher.doFinal(encSecret, encSecretStart, encSecretLen, secret, secretStart); - verification = aesGcmCipher.verifyTag(tag, (short) 0, (short) 12, (short) 12); - } catch (CryptoException exp) { - KMException.throwIt(KMError.UNKNOWN_ERROR); - } - return verification; - } - - @Override - public short aesCCMSign( - byte[] bufIn, - short bufInStart, - short buffInLength, - byte[] masterKeySecret, - short masterKeyStart, - short masterKeyLen, - byte[] bufOut, - short bufStart) { - if (masterKeyLen > 16) { - - return -1; - } - aes128Key.setKey(masterKeySecret, masterKeyStart); - kdf.init(aes128Key, Signature.MODE_SIGN); - return kdf.sign(bufIn, bufInStart, buffInLength, bufOut, bufStart); - } - - @Override - public short cmacKdf(byte[] aesKey, short aesKeyStart, short aesKeyLen, byte[] label, short labelStart, short labelLen, byte[] context, short contextStart, short contextLength, byte[] key, short keyStart) { - return 0; - } - - public ECPrivateKey createEcPrivateKey(byte[] pubBuffer, short pubOff, short pubLength, - byte[] privBuffer, short privOff, short privLength) { - // Simulator does not support NamedParameterSpec or 256 bit keys - ECPrivateKey privKey = (ECPrivateKey) ec192KeyPair.getPrivate(); - if(privLength > 24){ - privLength = 24;// simulator does not support more then 24 bytes - 192 bit key. - }else if(privLength <= 20){ - return null; - } - privKey.setS(privBuffer,privOff, privLength); - return privKey; - } - - public HMACKey createHMACKey(byte[] secretBuffer, short secretOff, short secretLength) { - // simulator only supports HMAC keys for SHA1 and SHA256 with block size 64. - // So only 128 and 256 bit HMAC keys are supported. - HMACKey key; - if (secretLength == 16) { - key = hmac128Key; - key.setKey(secretBuffer, secretOff, secretLength); - } else if (secretLength == 32) { - key = hmac256Key; - key.setKey(secretBuffer, secretOff, secretLength); - } else { - key = hmac128Key; // by default the simulator will return 128 bit keys for SHA1 - key.setKey(secretBuffer, secretOff, (short)16); - } - return key; - } - public DESKey createTDESKey(byte[] secretBuffer, short secretOff, short secretLength) { - // only 128 bit keys are supported - if(secretLength < 128) return null; - triDesKey.setKey(secretBuffer, secretOff); - return triDesKey; - } - - public RSAPrivateKey createRsaKey(byte[] modBuffer, short modOff, short modLength, byte[] privBuffer, short privOff, short privLength) { - return null; - } - - public HMACKey cmacKdf(byte[] keyMaterial, byte[] label, byte[] context, short contextStart, short contextLength) { - return null; - } - - public short hmacSign(HMACKey key, byte[] data, short dataStart, short dataLength, byte[] mac, short macStart) { - return 0; - } - - public boolean hmacVerify(HMACKey key, byte[] data, short dataStart, short dataLength, byte[] mac, short macStart, short macLength) { - return false; - } - - @Override - public short hmacSign(byte[] keyBuf, short keyStart, short keyLength, byte[] data, short dataStart, short dataLength, byte[] mac, short macStart) { - return 0; - } - - @Override - public boolean hmacVerify(byte[] keyBuf, short keyStart, short keyLength, byte[] data, short dataStart, short dataLength, byte[] mac, short macStart, short macLength) { - return false; - } - - @Override - public short rsaDecipherOAEP256(byte[] secret, short secretStart, short secretLength, byte[] modBuffer, short modOff, short modLength, byte[] inputDataBuf, short inputDataStart, short inputDataLength, byte[] outputDataBuf, short outputDataStart) { - return 0; - } - - @Override - public short rsaSignPKCS1256(byte[] secret, short secretStart, short secretLength, byte[] modBuffer, short modOff, short modLength, byte[] inputDataBuf, short inputDataStart, short inputDataLength, byte[] outputDataBuf, short outputDataStart) { - return 0; - } - - @Override - public KMOperation initSymmetricOperation(byte purpose, byte alg, byte digest, byte padding, byte blockMode, byte[] keyBuf, short keyStart, short keyLength, byte[] ivBuf, short ivStart, short ivLength, short macLength) { - return null; - } - - @Override - public KMOperation initAsymmetricOperation(byte purpose, byte alg, byte padding, byte digest, byte[] privKeyBuf, short privKeyStart, short privKeyLength, byte[] pubModBuf, short pubModStart, short pubModLength) { - return null; - } - - public RSAPrivateKey createRsaPrivateKey(byte[] modBuffer, short modOff, short modLength, byte[] privBuffer, short privOff, short privLength) { - RSAPrivateKey privKey = (RSAPrivateKey) rsa512KeyPair.getPrivate(); - if(privLength > 64) privLength = 64; - else if(privLength < 64)return null; - if(modLength > 64) modLength = 64; - else if( modLength < 64) return null; - privKey.setExponent(privBuffer, privOff, privLength); - privKey.setModulus(modBuffer, modOff, modLength); - return privKey; - } - - private void initEntropyPool(byte[] pool) { - byte index = 0; - RandomData trng; - while (index < rngCounter.length) { - rngCounter[index++] = 0; - } - try { - trng = RandomData.getInstance(RandomData.ALG_TRNG); - trng.nextBytes(pool, (short) 0, (short) pool.length); - } catch (CryptoException exp) { - if (exp.getReason() == CryptoException.NO_SUCH_ALGORITHM) { - // TODO change this when possible - // simulator does not support TRNG algorithm. So, PRNG algorithm (deprecated) is used. - trng = RandomData.getInstance(RandomData.ALG_PSEUDO_RANDOM); - trng.nextBytes(pool, (short) 0, (short) pool.length); - } else { - // TODO change this to proper error code - ISOException.throwIt(ISO7816.SW_UNKNOWN); - } - } - } - - // Generate a secure random number from existing entropy pool. This uses aes ecb algorithm with - // 8 byte rngCounter and 16 byte block size. - @Override - public void newRandomNumber(byte[] num, short startOff, short length) { - KMRepository repository = KMRepository.instance(); - byte[] bufPtr = repository.getHeap(); - short countBufInd = repository.alloc(KMKeymasterApplet.AES_BLOCK_SIZE); - short randBufInd = repository.alloc(KMKeymasterApplet.AES_BLOCK_SIZE); - short len = KMKeymasterApplet.AES_BLOCK_SIZE; - aesRngKey.setKey(entropyPool, (short) 0); - aesRngCipher.init(aesRngKey, Cipher.MODE_ENCRYPT, aesICV, (short) 0, (short) 16); - while (length > 0) { - if (length < len) len = length; - // increment rngCounter by one - incrementCounter(); - // copy the 8 byte rngCounter into the 16 byte rngCounter buffer. - Util.arrayCopy(rngCounter, (short) 0, bufPtr, countBufInd, (short) rngCounter.length); - // encrypt the rngCounter buffer with existing entropy which forms the aes key. - aesRngCipher.doFinal( - bufPtr, countBufInd, KMKeymasterApplet.AES_BLOCK_SIZE, bufPtr, randBufInd); - // copy the encrypted rngCounter block to buffer passed in the argument - Util.arrayCopy(bufPtr, randBufInd, num, startOff, len); - length = (short) (length - len); - startOff = (short) (startOff + len); - } - } - - // increment 8 byte rngCounter by one - private void incrementCounter() { - // start with least significant byte - short index = (short) (rngCounter.length - 1); - while (index >= 0) { - // if the msb of current byte is set then it will be negative - if (rngCounter[index] < 0) { - // then increment the rngCounter - rngCounter[index]++; - // is the msb still set? i.e. no carry over - if (rngCounter[index] < 0) break; // then break - else index--; // else go to the higher order byte - } else { - // if msb is not set then increment the rngCounter - rngCounter[index]++; - break; - } - } - } - - @Override - public boolean isBackupRestoreSupported() { - return false; - } - - @Override - public KMAttestationCert getAttestationCert(boolean rsaCert) { - return null; - } - - @Override - public void backup(byte[] buf, short start, short len) { - - } - - @Override - public short restore(byte[] buf, short start) { - return 0; - } - -} From 8d36fec72a4e2152cb674790800b5078bcb77a2f Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Tue, 24 Nov 2020 18:55:40 +0000 Subject: [PATCH 26/42] Removed unused function getNumberOfCerts from SEProvider --- .../com/android/javacard/keymaster/AndroidSEProvider.java | 6 ------ .../com/android/javacard/keymaster/KMJcardSimulator.java | 6 ------ .../src/com/android/javacard/keymaster/KMSEProvider.java | 7 ------- 3 files changed, 19 deletions(-) diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java index 77e93dc3..db8e86db 100644 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java +++ b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java @@ -102,7 +102,6 @@ public class AndroidSEProvider implements KMSEProvider { public static final byte KEYSIZE_128_OFFSET = 0x00; public static final byte KEYSIZE_256_OFFSET = 0x01; public static final short TMP_ARRAY_SIZE = 256; - public static final short NUM_OF_CERTS = 1; public static final short CERT_CHAIN_MAX_SIZE = 2050;//First 2 bytes for length. final byte[] CIPHER_ALGS = { @@ -1169,11 +1168,6 @@ public short getCertificateChainLength() { return Util.getShort(certificateChain, (short)0); } - @Override - public short getNumberOfCerts() { - return NUM_OF_CERTS; - } - @Override public boolean isBootSignalEventSupported() { return false; diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java index 8fad85e5..86bee82f 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java +++ b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java @@ -70,7 +70,6 @@ public class KMJcardSimulator implements KMSEProvider { public static final short ENTROPY_POOL_SIZE = 16; // simulator does not support 256 bit aes keys public static final byte[] aesICV = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; private static final short CERT_CHAIN_MAX_SIZE = 2050;//First 2 bytes for length. - public static final short NUM_OF_CERTS = 1; public static boolean jcardSim = false; @@ -1236,11 +1235,6 @@ public short getCertificateChainLength() { return Util.getShort(certificateChain, (short)0); } - @Override - public short getNumberOfCerts() { - return NUM_OF_CERTS; - } - @Override public short ecSign256(byte[] secret, short secretStart, short secretLength, byte[] inputDataBuf, short inputDataStart, short inputDataLength, diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java b/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java index 04d02300..8202fe12 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java @@ -455,13 +455,6 @@ KMOperation initAsymmetricOperation( */ short getCertificateChainLength(); - /** - * This function returns the number certificates in the cert chain. - * - * @return the number of certificates in cert chain. - */ - short getNumberOfCerts(); - /** * This function tells if boot signal event is supported or not. * From ce572144a1006bb3002ab4d316801f334e7aada3 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Wed, 25 Nov 2020 15:55:59 +0000 Subject: [PATCH 27/42] Moved all time related functions under Provider implementation with class KMUtils --- .../keymaster/KMAttestationCertImpl.java | 62 ++- .../android/javacard/keymaster/KMUtils.java | 321 +++++++++++++++ .../keymaster/KMAttestationCertImpl.java | 62 ++- .../android/javacard/keymaster/KMUtils.java | 321 +++++++++++++++ .../javacard/keymaster/KMAttestationCert.java | 38 +- .../javacard/keymaster/KMKeymasterApplet.java | 370 ++---------------- 6 files changed, 821 insertions(+), 353 deletions(-) create mode 100644 Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMUtils.java create mode 100644 Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMUtils.java diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java index 1d6ea2d9..25ef4c8f 100644 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -166,21 +166,36 @@ public KMAttestationCert verifiedBootState(byte val) { return this; } - @Override - public KMAttestationCert uniqueId(short obj) { + private KMAttestationCert uniqueId(short obj) { uniqueId = obj; return this; } @Override - public KMAttestationCert notBefore(short obj) { - notBefore = obj; + public KMAttestationCert notBefore(short obj, byte[] scratchpad) { + // convert milliseconds to UTC date + notBefore = KMUtils.convertToDate(obj, scratchpad, true); return this; } @Override - public KMAttestationCert notAfter(short obj) { - notAfter = obj; + public KMAttestationCert notAfter(short usageExpiryTimeObj, + short certExpirtyTimeObj, byte[] scratchPad, short tmpVar) { + if (usageExpiryTimeObj != KMType.INVALID_VALUE) { + // compare if the expiry time is greater then 2051 then use generalized + // time format else use utc time format. + usageExpiryTimeObj = KMIntegerTag.cast(usageExpiryTimeObj).getValue(); + tmpVar = KMInteger.uint_64(KMUtils.firstJan2051, (short) 0); + if (KMInteger.compare(usageExpiryTimeObj, tmpVar) >= 0) + usageExpiryTimeObj = KMUtils.convertToDate(usageExpiryTimeObj, scratchPad, + false); + else + usageExpiryTimeObj = KMUtils + .convertToDate(usageExpiryTimeObj, scratchPad, true); + notAfter = usageExpiryTimeObj; + } else { + notAfter = certExpirtyTimeObj; + } return this; } @@ -935,6 +950,41 @@ public void build() { } } + @Override + public KMAttestationCert makeUniqueId(byte[] scratchPad, short scratchPadOff, + byte[] creationTime, short timeOffset, short creationTimeLen, + byte[] attestAppId, short appIdOff, short attestAppIdLen, + byte resetSinceIdRotation, byte[] key, short keyOff, short keyLen) { + // Concatenate T||C||R + // temporal count T + short temp = KMUtils.countTemporalCount(creationTime, timeOffset, + creationTimeLen, scratchPad, scratchPadOff); + Util.setShort(scratchPad, (short) scratchPadOff, temp); + temp = scratchPadOff; + scratchPadOff += 2; + + // Application Id C + Util.arrayCopyNonAtomic(attestAppId, appIdOff, scratchPad, scratchPadOff, + attestAppIdLen); + scratchPadOff += attestAppIdLen; + + // Reset After Rotation R + scratchPad[scratchPadOff] = resetSinceIdRotation; + scratchPadOff++; + + timeOffset = KMByteBlob.instance((short) 32); + appIdOff = KMSEProviderImpl.instance().hmacSign(key, keyOff, keyLen, + scratchPad, /* data */ + temp, /* data start */ + scratchPadOff, /* data length */ + KMByteBlob.cast(timeOffset).getBuffer(), /* signature buffer */ + KMByteBlob.cast(timeOffset).getStartOff()); /* signature start */ + if (appIdOff != 32) { + KMException.throwIt(KMError.UNKNOWN_ERROR); + } + return uniqueId(timeOffset); + } + /* private static void print(byte[] buf, short start, short length){ StringBuilder sb = new StringBuilder(); for(int i = start; i < (start+length); i++){ diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMUtils.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMUtils.java new file mode 100644 index 00000000..d9dce03b --- /dev/null +++ b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMUtils.java @@ -0,0 +1,321 @@ +package com.android.javacard.keymaster; + +import javacard.framework.Util; + +public class KMUtils { + // 64 bit unsigned calculations for time + public static final byte[] oneSecMsec = { + 0, 0, 0, 0, 0, 0, 0x03, (byte) 0xE8 }; // 1000 msec + public static final byte[] oneMinMsec = { + 0, 0, 0, 0, 0, 0, (byte) 0xEA, 0x60 }; // 60000 msec + public static final byte[] oneHourMsec = { + 0, 0, 0, 0, 0, 0x36, (byte) 0xEE, (byte) 0x80 }; // 3600000 msec + public static final byte[] oneDayMsec = { + 0, 0, 0, 0, 0x05, 0x26, 0x5C, 0x00 }; // 86400000 msec + public static final byte[] oneMonthMsec = { + 0, 0, 0, 0, (byte) 0x9A, 0x7E, (byte) 0xC8, 0x00 }; // 2592000000 msec + public static final byte[] oneYearMsec = { + 0, 0, 0, 0x07, 0x57, (byte) 0xB1, 0x2C, 0x00 }; // 31536000000 msec + // Leap year + 3 yrs + public static final byte[] fourYrsMsec = { + 0, 0, 0, 0x1D, 0x63, (byte) 0xEB, 0x0C, 0x00 }; // 126230400000 msec + public static final byte[] firstJan2020 = { + 0, 0, 0x01, 0x6F, 0x60, 0x1E, 0x5C, 0x00 }; // 1577865600000 msec + public static final byte[] firstJan2051 = { + 0, 0, 0x02, 0x53, 0x27, (byte) 0xC5, (byte) 0x90, 0x00 }; // 2556172800000 + // msec + + // -------------------------------------- + public static short convertToDate(short time, byte[] scratchPad, + boolean utcFlag) { + short yrsCount = 0; + short monthCount = 0; + short dayCount = 0; + short hhCount = 0; + short mmCount = 0; + short ssCount = 0; + byte Z = 0x5A; + boolean from2020 = true; + Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0); + Util.arrayCopyNonAtomic(KMInteger.cast(time).getBuffer(), + KMInteger.cast(time).getStartOff(), scratchPad, + (short) (8 - KMInteger.cast(time).length()), KMInteger.cast(time) + .length()); + // If the time is less then 1 Jan 2020 then it is an error + if (Util.arrayCompare(scratchPad, (short) 0, firstJan2020, (short) 0, + (short) 8) < 0) { + KMException.throwIt(KMError.INVALID_ARGUMENT); + } + if (utcFlag + && Util.arrayCompare(scratchPad, (short) 0, firstJan2051, + (short) 0, (short) 8) >= 0) { + KMException.throwIt(KMError.INVALID_ARGUMENT); + } + + if (Util.arrayCompare(scratchPad, (short) 0, firstJan2051, (short) 0, + (short) 8) < 0) { + Util.arrayCopyNonAtomic(firstJan2020, (short) 0, scratchPad, (short) 8, + (short) 8); + subtract(scratchPad, (short) 0, (short) 8, (short) 16); + Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, + (short) 8); + } else { + from2020 = false; + Util.arrayCopyNonAtomic(firstJan2051, (short) 0, scratchPad, (short) 8, + (short) 8); + subtract(scratchPad, (short) 0, (short) 8, (short) 16); + Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, + (short) 8); + } + // divide the given time with four yrs msec count + if (Util.arrayCompare(scratchPad, (short) 0, fourYrsMsec, (short) 0, + (short) 8) >= 0) { + Util.arrayCopyNonAtomic(fourYrsMsec, (short) 0, scratchPad, (short) 8, + (short) 8); + yrsCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); // quotient + // is + // multiple + // of 4 + yrsCount = (short) (yrsCount * 4); // number of yrs. + // copy reminder as new dividend + Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, + (short) 8); + } + // divide the given time with one yr msec count + if (Util.arrayCompare(scratchPad, (short) 0, oneYearMsec, (short) 0, + (short) 8) >= 0) { + Util.arrayCopyNonAtomic(oneYearMsec, (short) 0, scratchPad, (short) 8, + (short) 8); + yrsCount += divide(scratchPad, (short) 0, (short) 8, (short) 16); + Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, + (short) 8); + } + // total yrs from 1970 + if (from2020) + yrsCount = (short) (2020 + yrsCount); + else + yrsCount = (short) (2051 + yrsCount); + + // divide the given time with one month msec count + if (Util.arrayCompare(scratchPad, (short) 0, oneMonthMsec, (short) 0, + (short) 8) >= 0) { + Util.arrayCopyNonAtomic(oneMonthMsec, (short) 0, scratchPad, (short) 8, + (short) 8); + monthCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); + Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, + (short) 8); + } + + // divide the given time with one day msec count + if (Util.arrayCompare(scratchPad, (short) 0, oneDayMsec, (short) 0, + (short) 8) >= 0) { + Util.arrayCopyNonAtomic(oneDayMsec, (short) 0, scratchPad, (short) 8, + (short) 8); + dayCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); + Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, + (short) 8); + } + + // divide the given time with one hour msec count + if (Util.arrayCompare(scratchPad, (short) 0, oneHourMsec, (short) 0, + (short) 8) >= 0) { + Util.arrayCopyNonAtomic(oneHourMsec, (short) 0, scratchPad, (short) 8, + (short) 8); + hhCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); + Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, + (short) 8); + } + + // divide the given time with one minute msec count + if (Util.arrayCompare(scratchPad, (short) 0, oneMinMsec, (short) 0, + (short) 8) >= 0) { + Util.arrayCopyNonAtomic(oneMinMsec, (short) 0, scratchPad, (short) 8, + (short) 8); + mmCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); + Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, + (short) 8); + } + + // divide the given time with one second msec count + if (Util.arrayCompare(scratchPad, (short) 0, oneSecMsec, (short) 0, + (short) 8) >= 0) { + Util.arrayCopyNonAtomic(oneSecMsec, (short) 0, scratchPad, (short) 8, + (short) 8); + ssCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); + Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, + (short) 8); + } + + // Now convert to ascii string YYMMDDhhmmssZ or YYYYMMDDhhmmssZ + Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0); + short len = numberToString(yrsCount, scratchPad, (short) 0); // returns YYYY + len += numberToString(monthCount, scratchPad, len); + len += numberToString(dayCount, scratchPad, len); + len += numberToString(hhCount, scratchPad, len); + len += numberToString(mmCount, scratchPad, len); + len += numberToString(ssCount, scratchPad, len); + scratchPad[len] = Z; + len++; + if (utcFlag) + return KMByteBlob.instance(scratchPad, (short) 2, (short) (len - 2)); // YY + else + return KMByteBlob.instance(scratchPad, (short) 0, len); // YYYY + } + + public static short numberToString(short number, byte[] scratchPad, + short offset) { + byte zero = 0x30; + byte len = 2; + byte digit; + if (number > 999) + len = 4; + byte index = len; + while (index > 0) { + digit = (byte) (number % 10); + number = (short) (number / 10); + scratchPad[(short) (offset + index - 1)] = (byte) (digit + zero); + index--; + } + return len; + } + + // Use Euclid's formula: dividend = quotient*divisor + remainder + // i.e. dividend - quotient*divisor = remainder where remainder < divisor. + // so this is division by subtraction until remainder remains. + public static short divide(byte[] buf, short dividend, short divisor, + short remainder) { + short expCnt = 1; + short q = 0; + // first increase divisor so that it becomes greater then dividend. + while (compare(buf, divisor, dividend) < 0) { + shiftLeft(buf, divisor); + expCnt = (short) (expCnt << 1); + } + // Now subtract divisor from dividend if dividend is greater then divisor. + // Copy remainder in the dividend and repeat. + while (expCnt != 0) { + if (compare(buf, dividend, divisor) >= 0) { + subtract(buf, dividend, divisor, remainder); + copy(buf, remainder, dividend); + q = (short) (q + expCnt); + } + expCnt = (short) (expCnt >> 1); + shiftRight(buf, divisor); + } + return q; + } + + public static void copy(byte[] buf, short from, short to) { + Util.arrayCopyNonAtomic(buf, from, buf, to, (short) 8); + } + + public static byte compare(byte[] buf, short lhs, short rhs) { + return Util.arrayCompare(buf, lhs, buf, rhs, (short) 8); + } + + public static void shiftLeft(byte[] buf, short start) { + byte index = 7; + byte carry = 0; + byte tmp; + while (index >= 0) { + tmp = buf[(short) (start + index)]; + buf[(short) (start + index)] = (byte) (buf[(short) (start + index)] << 1); + buf[(short) (start + index)] = (byte) (buf[(short) (start + index)] + carry); + if (tmp < 0) + carry = 1; + else + carry = 0; + index--; + } + } + + public static void shiftRight(byte[] buf, short start) { + byte index = 0; + byte carry = 0; + byte tmp; + while (index < 8) { + tmp = (byte) (buf[(short) (start + index)] & 0x01); + buf[(short) (start + index)] = (byte) (buf[(short) (start + index)] >> 1); + buf[(short) (start + index)] = (byte) (buf[(short) (start + index)] & 0x7F); + buf[(short) (start + index)] = (byte) (buf[(short) (start + index)] | carry); + if (tmp == 1) + carry = (byte) 0x80; + else + carry = 0; + index++; + } + } + + + // num1 must be greater then or equal to num2 and both must be positive + /*private short subtractIntegers(short num1, short num2) { + short buf = + repository.alloc((short)24); byte[] scratchPad = repository.getHeap(); + Util.arrayFillNonAtomic(scratchPad, buf, (short) 24, (byte) 0); + Util.arrayCopyNonAtomic(KMInteger.cast(num1).getBuffer(), + KMInteger.cast(num1).getStartOff(), scratchPad, + (short) (buf + 8 - KMInteger.cast(num1).length()), + KMInteger.cast(num1).length()); + Util.arrayCopyNonAtomic(KMInteger.cast(num2).getBuffer(), + KMInteger.cast(num2).getStartOff(), scratchPad, + (short) (buf + 16 - KMInteger.cast(num2).length()), + KMInteger.cast(num2).length()); + if (scratchPad[buf] < 0 || scratchPad[(short) (buf + 8)] < 0) + return KMType.INVALID_VALUE; + if (Util.arrayCompare(scratchPad, buf, scratchPad, (short) (buf + 8), + (short) 8) < 1) + return KMType.INVALID_VALUE; + subtract(scratchPad, buf, (short) (buf + 8), (short) (buf + 16)); + return KMInteger.uint_64(scratchPad, (short) (buf + 16)); + }*/ + + public static void add(byte[] buf, short op1, short op2, short result) { + byte index = 7; + byte carry = 0; + short tmp; + while (index >= 0) { + tmp = (short) (buf[(short) (op1 + index)] + buf[(short) (op2 + index)] + carry); + carry = 0; + if (tmp > 255) + carry = 1; // max unsigned byte value is 255 + buf[(short) (result + index)] = (byte) (tmp & (byte) 0xFF); + index--; + } + } + + // subtraction by borrowing. + public static void subtract(byte[] buf, short op1, short op2, short result) { + byte borrow = 0; + byte index = 7; + short r; + short x; + short y; + while (index >= 0) { + x = (short) (buf[(short) (op1 + index)] & 0xFF); + y = (short) (buf[(short) (op2 + index)] & 0xFF); + r = (short) (x - y - borrow); + borrow = 0; + if (r < 0) { + borrow = 1; + r = (short) (r + 256); // max unsigned byte value is 255 + } + buf[(short) (result + index)] = (byte) (r & 0xFF); + index--; + } + } + + public static short countTemporalCount(byte[] bufTime, short timeOff, + short timeLen, byte[] scratchPad, short offset) { + Util.arrayFillNonAtomic(scratchPad, (short) offset, (short) 24, (byte) 0); + Util.arrayCopyNonAtomic( + bufTime, + timeOff, + scratchPad, + (short) (offset + 8 - timeLen), + timeLen); + Util.arrayCopyNonAtomic(oneMonthMsec, (short) 0, scratchPad, (short) (offset + 8), + (short) 8); + return divide(scratchPad, (short) 0, (short) 8, (short) 16); + } + +} diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java index 1d6ea2d9..25ef4c8f 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -166,21 +166,36 @@ public KMAttestationCert verifiedBootState(byte val) { return this; } - @Override - public KMAttestationCert uniqueId(short obj) { + private KMAttestationCert uniqueId(short obj) { uniqueId = obj; return this; } @Override - public KMAttestationCert notBefore(short obj) { - notBefore = obj; + public KMAttestationCert notBefore(short obj, byte[] scratchpad) { + // convert milliseconds to UTC date + notBefore = KMUtils.convertToDate(obj, scratchpad, true); return this; } @Override - public KMAttestationCert notAfter(short obj) { - notAfter = obj; + public KMAttestationCert notAfter(short usageExpiryTimeObj, + short certExpirtyTimeObj, byte[] scratchPad, short tmpVar) { + if (usageExpiryTimeObj != KMType.INVALID_VALUE) { + // compare if the expiry time is greater then 2051 then use generalized + // time format else use utc time format. + usageExpiryTimeObj = KMIntegerTag.cast(usageExpiryTimeObj).getValue(); + tmpVar = KMInteger.uint_64(KMUtils.firstJan2051, (short) 0); + if (KMInteger.compare(usageExpiryTimeObj, tmpVar) >= 0) + usageExpiryTimeObj = KMUtils.convertToDate(usageExpiryTimeObj, scratchPad, + false); + else + usageExpiryTimeObj = KMUtils + .convertToDate(usageExpiryTimeObj, scratchPad, true); + notAfter = usageExpiryTimeObj; + } else { + notAfter = certExpirtyTimeObj; + } return this; } @@ -935,6 +950,41 @@ public void build() { } } + @Override + public KMAttestationCert makeUniqueId(byte[] scratchPad, short scratchPadOff, + byte[] creationTime, short timeOffset, short creationTimeLen, + byte[] attestAppId, short appIdOff, short attestAppIdLen, + byte resetSinceIdRotation, byte[] key, short keyOff, short keyLen) { + // Concatenate T||C||R + // temporal count T + short temp = KMUtils.countTemporalCount(creationTime, timeOffset, + creationTimeLen, scratchPad, scratchPadOff); + Util.setShort(scratchPad, (short) scratchPadOff, temp); + temp = scratchPadOff; + scratchPadOff += 2; + + // Application Id C + Util.arrayCopyNonAtomic(attestAppId, appIdOff, scratchPad, scratchPadOff, + attestAppIdLen); + scratchPadOff += attestAppIdLen; + + // Reset After Rotation R + scratchPad[scratchPadOff] = resetSinceIdRotation; + scratchPadOff++; + + timeOffset = KMByteBlob.instance((short) 32); + appIdOff = KMSEProviderImpl.instance().hmacSign(key, keyOff, keyLen, + scratchPad, /* data */ + temp, /* data start */ + scratchPadOff, /* data length */ + KMByteBlob.cast(timeOffset).getBuffer(), /* signature buffer */ + KMByteBlob.cast(timeOffset).getStartOff()); /* signature start */ + if (appIdOff != 32) { + KMException.throwIt(KMError.UNKNOWN_ERROR); + } + return uniqueId(timeOffset); + } + /* private static void print(byte[] buf, short start, short length){ StringBuilder sb = new StringBuilder(); for(int i = start; i < (start+length); i++){ diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMUtils.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMUtils.java new file mode 100644 index 00000000..d9dce03b --- /dev/null +++ b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMUtils.java @@ -0,0 +1,321 @@ +package com.android.javacard.keymaster; + +import javacard.framework.Util; + +public class KMUtils { + // 64 bit unsigned calculations for time + public static final byte[] oneSecMsec = { + 0, 0, 0, 0, 0, 0, 0x03, (byte) 0xE8 }; // 1000 msec + public static final byte[] oneMinMsec = { + 0, 0, 0, 0, 0, 0, (byte) 0xEA, 0x60 }; // 60000 msec + public static final byte[] oneHourMsec = { + 0, 0, 0, 0, 0, 0x36, (byte) 0xEE, (byte) 0x80 }; // 3600000 msec + public static final byte[] oneDayMsec = { + 0, 0, 0, 0, 0x05, 0x26, 0x5C, 0x00 }; // 86400000 msec + public static final byte[] oneMonthMsec = { + 0, 0, 0, 0, (byte) 0x9A, 0x7E, (byte) 0xC8, 0x00 }; // 2592000000 msec + public static final byte[] oneYearMsec = { + 0, 0, 0, 0x07, 0x57, (byte) 0xB1, 0x2C, 0x00 }; // 31536000000 msec + // Leap year + 3 yrs + public static final byte[] fourYrsMsec = { + 0, 0, 0, 0x1D, 0x63, (byte) 0xEB, 0x0C, 0x00 }; // 126230400000 msec + public static final byte[] firstJan2020 = { + 0, 0, 0x01, 0x6F, 0x60, 0x1E, 0x5C, 0x00 }; // 1577865600000 msec + public static final byte[] firstJan2051 = { + 0, 0, 0x02, 0x53, 0x27, (byte) 0xC5, (byte) 0x90, 0x00 }; // 2556172800000 + // msec + + // -------------------------------------- + public static short convertToDate(short time, byte[] scratchPad, + boolean utcFlag) { + short yrsCount = 0; + short monthCount = 0; + short dayCount = 0; + short hhCount = 0; + short mmCount = 0; + short ssCount = 0; + byte Z = 0x5A; + boolean from2020 = true; + Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0); + Util.arrayCopyNonAtomic(KMInteger.cast(time).getBuffer(), + KMInteger.cast(time).getStartOff(), scratchPad, + (short) (8 - KMInteger.cast(time).length()), KMInteger.cast(time) + .length()); + // If the time is less then 1 Jan 2020 then it is an error + if (Util.arrayCompare(scratchPad, (short) 0, firstJan2020, (short) 0, + (short) 8) < 0) { + KMException.throwIt(KMError.INVALID_ARGUMENT); + } + if (utcFlag + && Util.arrayCompare(scratchPad, (short) 0, firstJan2051, + (short) 0, (short) 8) >= 0) { + KMException.throwIt(KMError.INVALID_ARGUMENT); + } + + if (Util.arrayCompare(scratchPad, (short) 0, firstJan2051, (short) 0, + (short) 8) < 0) { + Util.arrayCopyNonAtomic(firstJan2020, (short) 0, scratchPad, (short) 8, + (short) 8); + subtract(scratchPad, (short) 0, (short) 8, (short) 16); + Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, + (short) 8); + } else { + from2020 = false; + Util.arrayCopyNonAtomic(firstJan2051, (short) 0, scratchPad, (short) 8, + (short) 8); + subtract(scratchPad, (short) 0, (short) 8, (short) 16); + Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, + (short) 8); + } + // divide the given time with four yrs msec count + if (Util.arrayCompare(scratchPad, (short) 0, fourYrsMsec, (short) 0, + (short) 8) >= 0) { + Util.arrayCopyNonAtomic(fourYrsMsec, (short) 0, scratchPad, (short) 8, + (short) 8); + yrsCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); // quotient + // is + // multiple + // of 4 + yrsCount = (short) (yrsCount * 4); // number of yrs. + // copy reminder as new dividend + Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, + (short) 8); + } + // divide the given time with one yr msec count + if (Util.arrayCompare(scratchPad, (short) 0, oneYearMsec, (short) 0, + (short) 8) >= 0) { + Util.arrayCopyNonAtomic(oneYearMsec, (short) 0, scratchPad, (short) 8, + (short) 8); + yrsCount += divide(scratchPad, (short) 0, (short) 8, (short) 16); + Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, + (short) 8); + } + // total yrs from 1970 + if (from2020) + yrsCount = (short) (2020 + yrsCount); + else + yrsCount = (short) (2051 + yrsCount); + + // divide the given time with one month msec count + if (Util.arrayCompare(scratchPad, (short) 0, oneMonthMsec, (short) 0, + (short) 8) >= 0) { + Util.arrayCopyNonAtomic(oneMonthMsec, (short) 0, scratchPad, (short) 8, + (short) 8); + monthCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); + Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, + (short) 8); + } + + // divide the given time with one day msec count + if (Util.arrayCompare(scratchPad, (short) 0, oneDayMsec, (short) 0, + (short) 8) >= 0) { + Util.arrayCopyNonAtomic(oneDayMsec, (short) 0, scratchPad, (short) 8, + (short) 8); + dayCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); + Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, + (short) 8); + } + + // divide the given time with one hour msec count + if (Util.arrayCompare(scratchPad, (short) 0, oneHourMsec, (short) 0, + (short) 8) >= 0) { + Util.arrayCopyNonAtomic(oneHourMsec, (short) 0, scratchPad, (short) 8, + (short) 8); + hhCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); + Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, + (short) 8); + } + + // divide the given time with one minute msec count + if (Util.arrayCompare(scratchPad, (short) 0, oneMinMsec, (short) 0, + (short) 8) >= 0) { + Util.arrayCopyNonAtomic(oneMinMsec, (short) 0, scratchPad, (short) 8, + (short) 8); + mmCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); + Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, + (short) 8); + } + + // divide the given time with one second msec count + if (Util.arrayCompare(scratchPad, (short) 0, oneSecMsec, (short) 0, + (short) 8) >= 0) { + Util.arrayCopyNonAtomic(oneSecMsec, (short) 0, scratchPad, (short) 8, + (short) 8); + ssCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); + Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, + (short) 8); + } + + // Now convert to ascii string YYMMDDhhmmssZ or YYYYMMDDhhmmssZ + Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0); + short len = numberToString(yrsCount, scratchPad, (short) 0); // returns YYYY + len += numberToString(monthCount, scratchPad, len); + len += numberToString(dayCount, scratchPad, len); + len += numberToString(hhCount, scratchPad, len); + len += numberToString(mmCount, scratchPad, len); + len += numberToString(ssCount, scratchPad, len); + scratchPad[len] = Z; + len++; + if (utcFlag) + return KMByteBlob.instance(scratchPad, (short) 2, (short) (len - 2)); // YY + else + return KMByteBlob.instance(scratchPad, (short) 0, len); // YYYY + } + + public static short numberToString(short number, byte[] scratchPad, + short offset) { + byte zero = 0x30; + byte len = 2; + byte digit; + if (number > 999) + len = 4; + byte index = len; + while (index > 0) { + digit = (byte) (number % 10); + number = (short) (number / 10); + scratchPad[(short) (offset + index - 1)] = (byte) (digit + zero); + index--; + } + return len; + } + + // Use Euclid's formula: dividend = quotient*divisor + remainder + // i.e. dividend - quotient*divisor = remainder where remainder < divisor. + // so this is division by subtraction until remainder remains. + public static short divide(byte[] buf, short dividend, short divisor, + short remainder) { + short expCnt = 1; + short q = 0; + // first increase divisor so that it becomes greater then dividend. + while (compare(buf, divisor, dividend) < 0) { + shiftLeft(buf, divisor); + expCnt = (short) (expCnt << 1); + } + // Now subtract divisor from dividend if dividend is greater then divisor. + // Copy remainder in the dividend and repeat. + while (expCnt != 0) { + if (compare(buf, dividend, divisor) >= 0) { + subtract(buf, dividend, divisor, remainder); + copy(buf, remainder, dividend); + q = (short) (q + expCnt); + } + expCnt = (short) (expCnt >> 1); + shiftRight(buf, divisor); + } + return q; + } + + public static void copy(byte[] buf, short from, short to) { + Util.arrayCopyNonAtomic(buf, from, buf, to, (short) 8); + } + + public static byte compare(byte[] buf, short lhs, short rhs) { + return Util.arrayCompare(buf, lhs, buf, rhs, (short) 8); + } + + public static void shiftLeft(byte[] buf, short start) { + byte index = 7; + byte carry = 0; + byte tmp; + while (index >= 0) { + tmp = buf[(short) (start + index)]; + buf[(short) (start + index)] = (byte) (buf[(short) (start + index)] << 1); + buf[(short) (start + index)] = (byte) (buf[(short) (start + index)] + carry); + if (tmp < 0) + carry = 1; + else + carry = 0; + index--; + } + } + + public static void shiftRight(byte[] buf, short start) { + byte index = 0; + byte carry = 0; + byte tmp; + while (index < 8) { + tmp = (byte) (buf[(short) (start + index)] & 0x01); + buf[(short) (start + index)] = (byte) (buf[(short) (start + index)] >> 1); + buf[(short) (start + index)] = (byte) (buf[(short) (start + index)] & 0x7F); + buf[(short) (start + index)] = (byte) (buf[(short) (start + index)] | carry); + if (tmp == 1) + carry = (byte) 0x80; + else + carry = 0; + index++; + } + } + + + // num1 must be greater then or equal to num2 and both must be positive + /*private short subtractIntegers(short num1, short num2) { + short buf = + repository.alloc((short)24); byte[] scratchPad = repository.getHeap(); + Util.arrayFillNonAtomic(scratchPad, buf, (short) 24, (byte) 0); + Util.arrayCopyNonAtomic(KMInteger.cast(num1).getBuffer(), + KMInteger.cast(num1).getStartOff(), scratchPad, + (short) (buf + 8 - KMInteger.cast(num1).length()), + KMInteger.cast(num1).length()); + Util.arrayCopyNonAtomic(KMInteger.cast(num2).getBuffer(), + KMInteger.cast(num2).getStartOff(), scratchPad, + (short) (buf + 16 - KMInteger.cast(num2).length()), + KMInteger.cast(num2).length()); + if (scratchPad[buf] < 0 || scratchPad[(short) (buf + 8)] < 0) + return KMType.INVALID_VALUE; + if (Util.arrayCompare(scratchPad, buf, scratchPad, (short) (buf + 8), + (short) 8) < 1) + return KMType.INVALID_VALUE; + subtract(scratchPad, buf, (short) (buf + 8), (short) (buf + 16)); + return KMInteger.uint_64(scratchPad, (short) (buf + 16)); + }*/ + + public static void add(byte[] buf, short op1, short op2, short result) { + byte index = 7; + byte carry = 0; + short tmp; + while (index >= 0) { + tmp = (short) (buf[(short) (op1 + index)] + buf[(short) (op2 + index)] + carry); + carry = 0; + if (tmp > 255) + carry = 1; // max unsigned byte value is 255 + buf[(short) (result + index)] = (byte) (tmp & (byte) 0xFF); + index--; + } + } + + // subtraction by borrowing. + public static void subtract(byte[] buf, short op1, short op2, short result) { + byte borrow = 0; + byte index = 7; + short r; + short x; + short y; + while (index >= 0) { + x = (short) (buf[(short) (op1 + index)] & 0xFF); + y = (short) (buf[(short) (op2 + index)] & 0xFF); + r = (short) (x - y - borrow); + borrow = 0; + if (r < 0) { + borrow = 1; + r = (short) (r + 256); // max unsigned byte value is 255 + } + buf[(short) (result + index)] = (byte) (r & 0xFF); + index--; + } + } + + public static short countTemporalCount(byte[] bufTime, short timeOff, + short timeLen, byte[] scratchPad, short offset) { + Util.arrayFillNonAtomic(scratchPad, (short) offset, (short) 24, (byte) 0); + Util.arrayCopyNonAtomic( + bufTime, + timeOff, + scratchPad, + (short) (offset + 8 - timeLen), + timeLen); + Util.arrayCopyNonAtomic(oneMonthMsec, (short) 0, scratchPad, (short) (offset + 8), + (short) 8); + return divide(scratchPad, (short) 0, (short) 8, (short) 16); + } + +} diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java b/Applet/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java index cb9e4e15..67453706 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java @@ -43,27 +43,47 @@ public interface KMAttestationCert { /** * Set uniqueId received from CA certificate during provisioning. * - * @param obj Ths is a KMByteBlob containing uniqueId. - * @return instance of KMAttestationCert - */ - KMAttestationCert uniqueId(short obj); + * @param scratchpad Buffer to store intermediate results. + * @param scratchPadOff Start offset of the scratchpad buffer. + * @param creationTime This buffer contains the CREATION_TIME value. + * @param creationTimeOff Start offset of creattionTime buffer. + * @param creationTimeLen Length of the creationTime buffer. + * @param attestAppId This buffer contains the ATTESTATION_APPLICATION_ID value. + * @param attestAppIdOff Start offset of the attestAppId buffer. + * @param attestAppIdLen Length of the attestAppId buffer. + * @param resetSinceIdRotation This holds the information of RESET_SINCE_ID_ROTATION. + * @param key This buffer contains the master secret. + * @param keyOff Start offset of the master key. + * @param keyLen Length of the master key. + * @return instance of KMAttestationCert. + */ + KMAttestationCert makeUniqueId(byte[] scratchpad, short scratchPadOff, byte[] creationTime, + short creationTimeOff, short creationTimeLen, byte[] attestAppId, + short attestAppIdOff, short attestAppIdLen, byte resetSinceIdRotation, + byte[] key, short keyOff, short keyLen); /** * Set start time received from creation/activation time tag. Used for certificate's valid period. * - * @param obj Ths is a KMByteBlob containing start time. - * @return instance of KMAttestationCert + * @param obj This is a KMByteBlob object containing start time. + * @param scratchpad Buffer to store intermediate results. + * @return instance of KMAttestationCert. */ - KMAttestationCert notBefore(short obj); + KMAttestationCert notBefore(short obj, byte[] scratchpad); + /** * Set expiry time received from expiry time tag or ca certificates expiry time. * Used for certificate's valid period. * - * @param obj Ths is a KMByteBlob containing expiry time. + * @param usageExpiryTimeObj This is a KMByteBlob containing expiry time. + * @param certExpirtyTimeObj This is a KMByteblob containing expirty time extracted from certificate. + * @param scratchpad Buffer to store intermediate results. + * @param offset Variable used to store intermediate results. * @return instance of KMAttestationCert */ - KMAttestationCert notAfter(short obj); + KMAttestationCert notAfter(short usageExpiryTimeObj, + short certExpirtyTimeObj, byte[] scratchPad, short offset); /** * Set device lock status received during booting time or due to device lock command. diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 86314090..ca6a2bd9 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -165,29 +165,6 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe private static final byte AES_GCM_NONCE_LENGTH = 12; // ComputeHMAC constants private static final short HMAC_SHARED_PARAM_MAX_SIZE = 64; - // 64 bit unsigned calculations for time - private static final byte[] oneSecMsec = {0, 0, 0, 0, 0, 0, 0x03, (byte) 0xE8}; // 1000 msec - private static final byte[] oneMinMsec = {0, 0, 0, 0, 0, 0, (byte) 0xEA, 0x60}; // 60000 msec - private static final byte[] oneHourMsec = { - 0, 0, 0, 0, 0, 0x36, (byte) 0xEE, (byte) 0x80 - }; // 3600000 msec - private static final byte[] oneDayMsec = {0, 0, 0, 0, 0x05, 0x26, 0x5C, 0x00}; // 86400000 msec - private static final byte[] oneMonthMsec = { - 0, 0, 0, 0, (byte) 0x9A, 0x7E, (byte) 0xC8, 0x00 - }; // 2592000000 msec - private static final byte[] oneYearMsec = { - 0, 0, 0, 0x07, 0x57, (byte) 0xB1, 0x2C, 0x00 - }; // 31536000000 msec - // Leap year + 3 yrs - private static final byte[] fourYrsMsec = { - 0, 0, 0, 0x1D, 0x63, (byte) 0xEB, 0x0C, 0x00 - }; // 126230400000 msec - private static final byte[] firstJan2020 = { - 0, 0, 0x01, 0x6F, 0x60, 0x1E, 0x5C, 0x00 - }; // 1577865600000 msec - private static final byte[] firstJan2051 = { - 0, 0, 0x02, 0x53, 0x27, (byte) 0xC5, (byte) 0x90, 0x00 - }; // 2556172800000 msec // Keymaster Applet attributes private static byte keymasterState = ILLEGAL_STATE; @@ -1313,8 +1290,8 @@ private void processAttestKeyCmd(APDU apdu) { } cert.attestationChallenge(KMByteTag.cast(tmpVariables[0]).getValue()); // unique id byte blob - uses application id and temporal month count of creation time. - tmpVariables[0] = makeUniqueId(scratchPad); - cert.uniqueId(tmpVariables[0]); + setUniqueId(cert, scratchPad); + // validity period // active time or creation time - byte blob // TODO current assumption is that if active and creation time are missing from characteristics @@ -1331,25 +1308,12 @@ private void processAttestKeyCmd(APDU apdu) { tmpVariables[1] = KMIntegerTag.cast(tmpVariables[1]).getValue(); } // convert milliseconds to UTC date. Start of validity period has to be UTC. - tmpVariables[1] = convertToDate(tmpVariables[1], scratchPad, true); - cert.notBefore(tmpVariables[1]); + cert.notBefore(tmpVariables[1], scratchPad); // expiry time - byte blob tmpVariables[2] = KMKeyParameters.findTag(KMType.DATE_TAG, KMType.USAGE_EXPIRE_DATETIME, data[SW_PARAMETERS]); - if (tmpVariables[2] != KMType.INVALID_VALUE) { - // compare if the expiry time is greater then 2051 then use generalized time format else use - // utc time format - tmpVariables[2] = KMIntegerTag.cast(tmpVariables[1]).getValue(); - tmpVariables[3] = KMInteger.uint_64(firstJan2051, (short) 0); - if (KMInteger.compare(tmpVariables[2], tmpVariables[3]) >= 0) - tmpVariables[2] = convertToDate(tmpVariables[2], scratchPad, false); - else tmpVariables[2] = convertToDate(tmpVariables[1], scratchPad, true); - } else { - // if no expiry tag is present then use the attestation key certificate's expiry time - // that was provisioned in the provision command. This will be in Generalized or UTC time - tmpVariables[2] = repository.getCertExpiryTime(); - } - cert.notAfter(tmpVariables[2]); + cert.notAfter(tmpVariables[2], repository.getCertExpiryTime(), scratchPad, (short) 0); + addAttestationIds(cert); addTags(KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getHardwareEnforced(), true, cert); addTags( @@ -1434,205 +1398,50 @@ private void addTags(short params, boolean hwEnforced, KMAttestationCert cert) { } } - // -------------------------------------- - private short convertToDate(short time, byte[] scratchPad, boolean utcFlag) { - short yrsCount = 0; - short monthCount = 0; - short dayCount = 0; - short hhCount = 0; - short mmCount = 0; - short ssCount = 0; - byte Z = 0x5A; - boolean from2020 = true; - Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0); - Util.arrayCopyNonAtomic( - KMInteger.cast(time).getBuffer(), - KMInteger.cast(time).getStartOff(), - scratchPad, - (short) (8 - KMInteger.cast(time).length()), - KMInteger.cast(time).length()); - // If the time is less then 1 Jan 2020 then it is an error - if (Util.arrayCompare(scratchPad, (short) 0, firstJan2020, (short) 0, (short) 8) < 0) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - if (utcFlag - && Util.arrayCompare(scratchPad, (short) 0, firstJan2051, (short) 0, (short) 8) >= 0) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - - if (Util.arrayCompare(scratchPad, (short) 0, firstJan2051, (short) 0, (short) 8) < 0) { - Util.arrayCopyNonAtomic(firstJan2020, (short) 0, scratchPad, (short) 8, (short) 8); - subtract(scratchPad, (short) 0, (short) 8, (short) 16); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, (short) 8); - } else { - from2020 = false; - Util.arrayCopyNonAtomic(firstJan2051, (short) 0, scratchPad, (short) 8, (short) 8); - subtract(scratchPad, (short) 0, (short) 8, (short) 16); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, (short) 8); - } - // divide the given time with four yrs msec count - if (Util.arrayCompare(scratchPad, (short) 0, fourYrsMsec, (short) 0, (short) 8) >= 0) { - Util.arrayCopyNonAtomic(fourYrsMsec, (short) 0, scratchPad, (short) 8, (short) 8); - yrsCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); // quotient is multiple of 4 - yrsCount = (short) (yrsCount * 4); // number of yrs. - // copy reminder as new dividend - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, (short) 8); - } - // divide the given time with one yr msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneYearMsec, (short) 0, (short) 8) >= 0) { - Util.arrayCopyNonAtomic(oneYearMsec, (short) 0, scratchPad, (short) 8, (short) 8); - yrsCount += divide(scratchPad, (short) 0, (short) 8, (short) 16); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, (short) 8); - } - // total yrs from 1970 - if (from2020) yrsCount = (short) (2020 + yrsCount); - else yrsCount = (short) (2051 + yrsCount); - - // divide the given time with one month msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneMonthMsec, (short) 0, (short) 8) >= 0) { - Util.arrayCopyNonAtomic(oneMonthMsec, (short) 0, scratchPad, (short) 8, (short) 8); - monthCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, (short) 8); - } - - // divide the given time with one day msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneDayMsec, (short) 0, (short) 8) >= 0) { - Util.arrayCopyNonAtomic(oneDayMsec, (short) 0, scratchPad, (short) 8, (short) 8); - dayCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, (short) 8); - } - - // divide the given time with one hour msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneHourMsec, (short) 0, (short) 8) >= 0) { - Util.arrayCopyNonAtomic(oneHourMsec, (short) 0, scratchPad, (short) 8, (short) 8); - hhCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, (short) 8); - } - - // divide the given time with one minute msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneMinMsec, (short) 0, (short) 8) >= 0) { - Util.arrayCopyNonAtomic(oneMinMsec, (short) 0, scratchPad, (short) 8, (short) 8); - mmCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, (short) 8); - } - - // divide the given time with one second msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneSecMsec, (short) 0, (short) 8) >= 0) { - Util.arrayCopyNonAtomic(oneSecMsec, (short) 0, scratchPad, (short) 8, (short) 8); - ssCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, (short) 8); - } - - // Now convert to ascii string YYMMDDhhmmssZ or YYYYMMDDhhmmssZ - Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0); - short len = numberToString(yrsCount, scratchPad, (short) 0); // returns YYYY - len += numberToString(monthCount, scratchPad, len); - len += numberToString(dayCount, scratchPad, len); - len += numberToString(hhCount, scratchPad, len); - len += numberToString(mmCount, scratchPad, len); - len += numberToString(ssCount, scratchPad, len); - scratchPad[len] = Z; - len++; - if (utcFlag) - return KMByteBlob.instance(scratchPad, (short) 2, (short) (len - 2)); // YY - else - return KMByteBlob.instance(scratchPad, (short) 0, len); // YYYY - } - - private short numberToString(short number, byte[] scratchPad, short offset) { - byte zero = 0x30; - byte len = 2; - byte digit; - if (number > 999) - len = 4; - byte index = len; - while (index > 0) { - digit = (byte) (number % 10); - number = (short) (number / 10); - scratchPad[(short) (offset + index - 1)] = (byte) (digit + zero); - index--; - } - return len; - } - - private short makeUniqueId(byte[] scratchPad) { - tmpVariables[0] = - KMKeyParameters.findTag(KMType.BOOL_TAG, KMType.INCLUDE_UNIQUE_ID, data[HW_PARAMETERS]); + private void setUniqueId(KMAttestationCert cert, byte[] scratchPad) { + tmpVariables[0] = KMKeyParameters.findTag(KMType.BOOL_TAG, + KMType.INCLUDE_UNIQUE_ID, data[HW_PARAMETERS]); if (tmpVariables[0] == KMType.INVALID_VALUE) { - return 0; + return; } - // Concatenate T||C||R + // temporal count T - tmpVariables[0] = - KMKeyParameters.findTag(KMType.DATE_TAG, KMType.CREATION_DATETIME, data[SW_PARAMETERS]); - if (tmpVariables[0] == KMType.INVALID_VALUE) KMException.throwIt(KMError.INVALID_TAG); + tmpVariables[0] = KMKeyParameters.findTag(KMType.DATE_TAG, + KMType.CREATION_DATETIME, data[SW_PARAMETERS]); + if (tmpVariables[0] == KMType.INVALID_VALUE) + KMException.throwIt(KMError.INVALID_TAG); tmpVariables[0] = KMIntegerTag.cast(tmpVariables[0]).getValue(); - tmpVariables[0] = countTemporalCount(tmpVariables[0], scratchPad); // just a short count - Util.setShort(scratchPad, (short) 0, tmpVariables[0]); - tmpVariables[1] = (short) 2; // Application Id C - tmpVariables[0] = - KMKeyParameters.findTag( - KMType.BYTES_TAG, KMType.ATTESTATION_APPLICATION_ID, data[KEY_PARAMETERS]); - if (tmpVariables[0] == KMType.INVALID_VALUE) + tmpVariables[1] = KMKeyParameters.findTag(KMType.BYTES_TAG, + KMType.ATTESTATION_APPLICATION_ID, data[KEY_PARAMETERS]); + if (tmpVariables[1] == KMType.INVALID_VALUE) KMException.throwIt(KMError.ATTESTATION_APPLICATION_ID_MISSING); - tmpVariables[0] = KMByteTag.cast(tmpVariables[0]).getValue(); - Util.arrayCopyNonAtomic( - KMByteBlob.cast(tmpVariables[0]).getBuffer(), - KMByteBlob.cast(tmpVariables[0]).getStartOff(), - scratchPad, - tmpVariables[1], - KMByteBlob.cast(tmpVariables[0]).length()); - tmpVariables[1] += KMByteBlob.cast(tmpVariables[0]).length(); + tmpVariables[1] = KMByteTag.cast(tmpVariables[1]).getValue(); - // Reset After Rotation R - it will be part of HW Enforced key characteristics - scratchPad[tmpVariables[1]] = (byte) 0; - tmpVariables[0] = - KMKeyParameters.findTag( - KMType.BOOL_TAG, KMType.RESET_SINCE_ID_ROTATION, data[HW_PARAMETERS]); - if (tmpVariables[0] != KMType.INVALID_VALUE) { - scratchPad[tmpVariables[1]] = (byte) 0x01; + // Reset After Rotation R - it will be part of HW Enforced key + // characteristics + byte resetAfterRotation = 0; + tmpVariables[2] = KMKeyParameters.findTag(KMType.BOOL_TAG, + KMType.RESET_SINCE_ID_ROTATION, data[HW_PARAMETERS]); + if (tmpVariables[2] != KMType.INVALID_VALUE) { + resetAfterRotation = 0x01; } - tmpVariables[1]++; - // Sign - signature becomes unique id of 32 bits. Use 128 bits master key as an hmac key. - tmpVariables[0] = KMByteBlob.instance((short) 32); + //master key. tmpVariables[2] = repository.getMasterKeySecret(); - /* - tmpVariables[1]= seProvider.hmacSign( - repository.getMasterKeySecret(),(short)0, - (short)repository.getMasterKeySecret(, ).length, - scratchPad,(short)0,tmpVariables[1], - KMByteBlob.cast(tmpVariables[0]).getBuffer(), - KMByteBlob.cast(tmpVariables[0]).getStartOff()); - */ - tmpVariables[1] = - seProvider.hmacSign( - KMByteBlob.cast(tmpVariables[2]).getBuffer(), - KMByteBlob.cast(tmpVariables[2]).getStartOff(), - KMByteBlob.cast(tmpVariables[2]).length(), + cert.makeUniqueId( scratchPad, (short) 0, - tmpVariables[1], - KMByteBlob.cast(tmpVariables[0]).getBuffer(), - KMByteBlob.cast(tmpVariables[0]).getStartOff()); - if (tmpVariables[1] != 32) { - KMException.throwIt(KMError.UNKNOWN_ERROR); - } - return tmpVariables[0]; - } - - private short countTemporalCount(short time, byte[] scratchPad) { - Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 24, (byte) 0); - Util.arrayCopyNonAtomic( - KMInteger.cast(time).getBuffer(), - KMInteger.cast(time).getStartOff(), - scratchPad, - (short) (8 - KMInteger.cast(time).length()), - KMInteger.cast(time).length()); - Util.arrayCopyNonAtomic(oneMonthMsec, (short) 0, scratchPad, (short) 8, (short) 8); - return divide(scratchPad, (short) 0, (short) 8, (short) 16); + KMInteger.cast(tmpVariables[0]).getBuffer(), + KMInteger.cast(tmpVariables[0]).getStartOff(), + KMInteger.cast(tmpVariables[0]).length(), + KMByteBlob.cast(tmpVariables[1]).getBuffer(), + KMByteBlob.cast(tmpVariables[1]).getStartOff(), + KMByteBlob.cast(tmpVariables[1]).length(), resetAfterRotation, + KMByteBlob.cast(tmpVariables[2]).getBuffer(), + KMByteBlob.cast(tmpVariables[2]).getStartOff(), + KMByteBlob.cast(tmpVariables[2]).length()); } private void processDestroyAttIdsCmd(APDU apdu) { @@ -4137,27 +3946,6 @@ private short addIntegers(short num1, short num2) { return KMInteger.uint_64(scratchPad, (short) (buf + 16)); } - /* - // num1 must be greater then or equal to num2 and both must be positive - private short subtractIntegers(short num1, short num2){ - short buf = repository.alloc((short)24); - byte[] scratchPad = repository.getHeap(); - Util.arrayFillNonAtomic(scratchPad, buf, (short)24,(byte)0); - Util.arrayCopyNonAtomic( - KMInteger.cast(num1).getBuffer(), - KMInteger.cast(num1).getStartOff(),scratchPad,(short)(buf+8-KMInteger.cast(num1).length()), - KMInteger.cast(num1).length()); - Util.arrayCopyNonAtomic( - KMInteger.cast(num2).getBuffer(), - KMInteger.cast(num2).getStartOff(),scratchPad,(short)(buf+16-KMInteger.cast(num2).length()), - KMInteger.cast(num2).length()); - if(scratchPad[buf] < 0 || scratchPad[(short)(buf+8)] <0)return KMType.INVALID_VALUE; - if(Util.arrayCompare(scratchPad,buf, scratchPad,(short)(buf+8), (short)8) < 1) return KMType.INVALID_VALUE; - subtract(scratchPad,buf,(short)(buf+8),(short)(buf+16)); - return KMInteger.uint_64(scratchPad,(short)(buf+16)); - } - */ - private void add(byte[] buf, short op1, short op2, short result) { byte index = 7; byte carry = 0; @@ -4165,92 +3953,10 @@ private void add(byte[] buf, short op1, short op2, short result) { while (index >= 0) { tmp = (short) (buf[(short) (op1 + index)] + buf[(short) (op2 + index)] + carry); carry = 0; - if (tmp > 255) carry = 1; // max unsigned byte value is 255 + if (tmp > 255) + carry = 1; // max unsigned byte value is 255 buf[(short) (result + index)] = (byte) (tmp & (byte) 0xFF); index--; } } - - // subtraction by borrowing. - private void subtract(byte[] buf, short op1, short op2, short result) { - byte borrow = 0; - byte index = 7; - short r; - short x; - short y; - while (index >= 0) { - x = (short) (buf[(short) (op1 + index)] & 0xFF); - y = (short) (buf[(short) (op2 + index)] & 0xFF); - r = (short) (x - y - borrow); - borrow = 0; - if (r < 0) { - borrow = 1; - r = (short) (r + 256); // max unsigned byte value is 255 - } - buf[(short) (result + index)] = (byte) (r & 0xFF); - index--; - } - } - - // Use Euclid's formula: dividend = quotient*divisor + remainder - // i.e. dividend - quotient*divisor = remainder where remainder < divisor. - // so this is division by subtraction until remainder remains. - private short divide(byte[] buf, short dividend, short divisor, short remainder) { - short expCnt = 1; - short q = 0; - // first increase divisor so that it becomes greater then dividend. - while (compare(buf, divisor, dividend) < 0) { - shiftLeft(buf, divisor); - expCnt = (short) (expCnt << 1); - } - // Now subtract divisor from dividend if dividend is greater then divisor. - // Copy remainder in the dividend and repeat. - while (expCnt != 0) { - if (compare(buf, dividend, divisor) >= 0) { - subtract(buf, dividend, divisor, remainder); - copy(buf, remainder, dividend); - q = (short) (q + expCnt); - } - expCnt = (short) (expCnt >> 1); - shiftRight(buf, divisor); - } - return q; - } - - private void copy(byte[] buf, short from, short to) { - Util.arrayCopyNonAtomic(buf, from, buf, to, (short) 8); - } - - private byte compare(byte[] buf, short lhs, short rhs) { - return Util.arrayCompare(buf, lhs, buf, rhs, (short) 8); - } - - private void shiftLeft(byte[] buf, short start) { - byte index = 7; - byte carry = 0; - byte tmp; - while (index >= 0) { - tmp = buf[(short) (start + index)]; - buf[(short) (start + index)] = (byte) (buf[(short) (start + index)] << 1); - buf[(short) (start + index)] = (byte) (buf[(short) (start + index)] + carry); - if (tmp < 0) carry = 1; - else carry = 0; - index--; - } - } - - private void shiftRight(byte[] buf, short start) { - byte index = 0; - byte carry = 0; - byte tmp; - while (index < 8) { - tmp = (byte) (buf[(short) (start + index)] & 0x01); - buf[(short) (start + index)] = (byte) (buf[(short) (start + index)] >> 1); - buf[(short) (start + index)] = (byte) (buf[(short) (start + index)] & 0x7F); - buf[(short) (start + index)] = (byte) (buf[(short) (start + index)] | carry); - if (tmp == 1) carry = (byte) 0x80; - else carry = 0; - index++; - } - } } From 39707e2b764e4c6433e791c0831212a078c54eb3 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Wed, 25 Nov 2020 16:01:03 +0000 Subject: [PATCH 28/42] Removed Backuprestore classes from AndroidSEProvider --- .../keymaster/KMBackupRestoreAgent.java | 11 --- .../keymaster/KMBackupStoreApplet.java | 97 ------------------- 2 files changed, 108 deletions(-) delete mode 100644 Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java delete mode 100644 Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java deleted file mode 100644 index 764d4a3e..00000000 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMBackupRestoreAgent.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.android.javacard.keymaster; - -import javacard.framework.Shareable; - -public interface KMBackupRestoreAgent extends Shareable { - void backup(byte[] buf, short start, short len); - short restore(byte[] buf, short start); - void backupProviderData(byte[] buf, short start, short len); - short restoreProviderData(byte[] buf, short start); - boolean isBackupAvailable(); -} diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java deleted file mode 100644 index 4e851e5c..00000000 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMBackupStoreApplet.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.android.javacard.keymaster; - -import javacard.framework.AID; -import javacard.framework.APDU; -import javacard.framework.Applet; -import javacard.framework.JCSystem; -import javacard.framework.Shareable; -import javacard.framework.Util; - -public class KMBackupStoreApplet extends Applet implements KMBackupRestoreAgent { - private static final short PROVIDER_MEM_SIZE = 2050; - private static final short KM_APPLET_MEM_SIZE = 2050; - private static final short PROVIDER_OFFSET = 0; - private static final short KM_APPLET_DATA_OFFSET = PROVIDER_MEM_SIZE; - private static final byte[] aidArr = new byte[]{ (byte)0xA0, 0x00, 0x00, 0x00, 0x62}; - - private byte[] dataTable; - boolean backupAvailable; - - private KMBackupStoreApplet() { - dataTable = new byte[KM_APPLET_MEM_SIZE + PROVIDER_MEM_SIZE]; - backupAvailable = false; - } - - public static void install(byte bArray[], short bOffset, byte bLength) { - new KMBackupStoreApplet().register(); - } - - @Override - public boolean select() { - return true; - } - - @Override - public void process(APDU apdu) { - - } - - @Override - public void backup(byte[] buf, short start, short len) { - // Store the data - if (len > 0) { - JCSystem.beginTransaction(); - // dataTableSize = len; - Util.setShort(dataTable, KM_APPLET_DATA_OFFSET, len); - Util.arrayCopy(buf, start, dataTable, - (short) (KM_APPLET_DATA_OFFSET + 2), len); - JCSystem.commitTransaction(); - } - backupAvailable = true; - } - - @Override - public short restore(byte[] buf, short start) { - // Restore the data - short len = Util.getShort(dataTable, KM_APPLET_DATA_OFFSET); - Util.arrayCopyNonAtomic(dataTable, (short) (KM_APPLET_DATA_OFFSET + 2), buf, start, - len); - return len; - } - - @Override - public Shareable getShareableInterfaceObject(AID aid, byte param){ - byte[] aidBytes = new byte[10]; - byte len = aid.getBytes(aidBytes, (short)0); - if(Util.arrayCompare(aidArr,(short)0,aidBytes,(short)0,len) == 0){ - return this; - } - return null; - } - - @Override - public boolean isBackupAvailable() { - return backupAvailable; - } - - @Override - public void backupProviderData(byte[] buf, short start, short len) { - // Store the data - if (len > 0) { - JCSystem.beginTransaction(); - Util.arrayCopy(buf, start, dataTable, PROVIDER_OFFSET, len); - JCSystem.commitTransaction(); - } - backupAvailable = true; - } - - @Override - public short restoreProviderData(byte[] buf, short start) { - // Restore the data - short len = Util.getShort(dataTable, PROVIDER_OFFSET); - len += 2;// including length. - Util.arrayCopyNonAtomic(dataTable, PROVIDER_OFFSET, buf, start, len); - return len; - } - -} From fdf660daecd6b134b89a7cb3cc8bbb55c249c504 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Wed, 25 Nov 2020 23:27:02 +0000 Subject: [PATCH 29/42] 1. add sendError OK inside addRngEntropy which is missing 2. Removed commented code 3. Removed TODO code which is already handled. 4. Added Extended errors inside KMError to map ISOExceptions to KMErrors. --- .../keymaster/KMAttestationCertImpl.java | 61 ++----------------- .../keymaster/KMAttestationCertImpl.java | 61 ++----------------- .../KMEcdsa256NoDigestSignature.java | 2 - .../javacard/keymaster/KMJcardSimulator.java | 8 --- .../android/javacard/keymaster/KMDecoder.java | 4 -- .../android/javacard/keymaster/KMEncoder.java | 4 +- .../android/javacard/keymaster/KMError.java | 9 +++ .../android/javacard/keymaster/KMInteger.java | 3 - .../javacard/keymaster/KMIntegerArrayTag.java | 1 - .../javacard/keymaster/KMIntegerTag.java | 1 - .../javacard/keymaster/KMKeymasterApplet.java | 54 ++++++++-------- 11 files changed, 50 insertions(+), 158 deletions(-) diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java index 25ef4c8f..9468522e 100644 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -368,8 +368,7 @@ private static void pushValidity() { KMByteBlob.cast(notAfter).getStartOff(), KMByteBlob.cast(notAfter).length()); } else { - // TODO move this to keymaster applet - // pushBytes(repo.getCertDataBuffer(), repo.getCertExpiryTime(), repo.getCertExpiryTimeLen()); + KMException.throwIt(KMError.INVALID_DATA); } pushTimeHeader(KMByteBlob.cast(notAfter).length()); pushBytes( @@ -567,7 +566,7 @@ private static void pushTag(short tag) { break; case KMType.UINT_ARRAY_TAG: case KMType.ULONG_ARRAY_TAG: - // TODO According to keymaster hal only one user secure id is used but this conflicts with + // According to keymaster hal only one user secure id is used but this conflicts with // tag type which is ULONG-REP. Currently this is encoded as SET OF INTEGERS val = KMIntegerArrayTag.cast(tag).getValues(); pushIntegerArrayTag(tagId, val); @@ -602,29 +601,16 @@ private static void pushRoT() { KMByteBlob.cast(verifiedHash).getBuffer(), KMByteBlob.cast(verifiedHash).getStartOff(), KMByteBlob.cast(verifiedHash).length()); - /* - // verified boot state - // TODO change this once verifiedBootState is supported in repo - if (repo.selfSignedBootFlag) val = KMType.SELF_SIGNED_BOOT; - else if (repo.verifiedBootFlag) val = KMType.VERIFIED_BOOT; - else val = KMType.UNVERIFIED_BOOT; - - pushEnumerated(val); - */ pushEnumerated(verifiedState); - // device locked - /*val = 0x00; - if (repo.deviceLockedFlag) val = (byte) 0xFF; - pushBoolean(val); - */ + pushBoolean(deviceLocked); // verified boot Key pushOctetString( KMByteBlob.cast(verifiedBootKey).getBuffer(), KMByteBlob.cast(verifiedBootKey).getStartOff(), KMByteBlob.cast(verifiedBootKey).length()); - // pushOctetString(repo.verifiedBootKey, (short) 0, (short) repo.verifiedBootKey.length); + // Finally sequence header pushSequenceHeader((short) (last - stackPtr)); // ... and tag Id @@ -645,27 +631,7 @@ private static void pushBooleanHeader(short len) { pushLength(len); pushByte((byte) 0x01); } - /* - // All Attestation Id tags are byte tags/octet strings - private static boolean pushAttIds(short tagId) { - if(!repo.isAttIdSupported()) return true; - byte index = 0; - while (index < repo.ATT_ID_TABLE_SIZE) { - if (repo.getAttIdLen(index) != 0) { - if(tagId == repo.getAttIdTag(index)) { - pushBytesTag( - repo.getAttIdTag(index), - repo.getAttIdBuffer(index), - repo.getAttIdOffset(index), - repo.getAttIdLen(index)); - return true; - } - } - index++; - } - return false; - } - */ + // Only SET of INTEGERS supported are padding, digest, purpose and blockmode // All of these are enum array tags i.e. byte long values private static void pushEnumArrayTag(short tagId, byte[] buf, short start, short len) { @@ -797,13 +763,7 @@ private static void pushAuthKeyId() { short last = stackPtr; // if (repo.getAuthKeyId() == 0) return; if (authKey == 0) return; - /* - pushKeyIdentifier( - repo.getCertDataBuffer(), - repo.getAuthKeyId(), - repo.getAuthKeyIdLen()); // key identifier is [0]'th tagged in a sequence - */ pushKeyIdentifier( KMByteBlob.cast(authKey).getBuffer(), KMByteBlob.cast(authKey).getStartOff(), @@ -984,15 +944,4 @@ public KMAttestationCert makeUniqueId(byte[] scratchPad, short scratchPadOff, } return uniqueId(timeOffset); } - - /* private static void print(byte[] buf, short start, short length){ - StringBuilder sb = new StringBuilder(); - for(int i = start; i < (start+length); i++){ - sb.append(String.format("%02X", buf[i])) ; - //if((i-start)%16 == 0 && (i-start) != 0) sb.append(String.format("\n")); - } - System.out.println(sb.toString()); - } - - */ } diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java index 25ef4c8f..9468522e 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -368,8 +368,7 @@ private static void pushValidity() { KMByteBlob.cast(notAfter).getStartOff(), KMByteBlob.cast(notAfter).length()); } else { - // TODO move this to keymaster applet - // pushBytes(repo.getCertDataBuffer(), repo.getCertExpiryTime(), repo.getCertExpiryTimeLen()); + KMException.throwIt(KMError.INVALID_DATA); } pushTimeHeader(KMByteBlob.cast(notAfter).length()); pushBytes( @@ -567,7 +566,7 @@ private static void pushTag(short tag) { break; case KMType.UINT_ARRAY_TAG: case KMType.ULONG_ARRAY_TAG: - // TODO According to keymaster hal only one user secure id is used but this conflicts with + // According to keymaster hal only one user secure id is used but this conflicts with // tag type which is ULONG-REP. Currently this is encoded as SET OF INTEGERS val = KMIntegerArrayTag.cast(tag).getValues(); pushIntegerArrayTag(tagId, val); @@ -602,29 +601,16 @@ private static void pushRoT() { KMByteBlob.cast(verifiedHash).getBuffer(), KMByteBlob.cast(verifiedHash).getStartOff(), KMByteBlob.cast(verifiedHash).length()); - /* - // verified boot state - // TODO change this once verifiedBootState is supported in repo - if (repo.selfSignedBootFlag) val = KMType.SELF_SIGNED_BOOT; - else if (repo.verifiedBootFlag) val = KMType.VERIFIED_BOOT; - else val = KMType.UNVERIFIED_BOOT; - - pushEnumerated(val); - */ pushEnumerated(verifiedState); - // device locked - /*val = 0x00; - if (repo.deviceLockedFlag) val = (byte) 0xFF; - pushBoolean(val); - */ + pushBoolean(deviceLocked); // verified boot Key pushOctetString( KMByteBlob.cast(verifiedBootKey).getBuffer(), KMByteBlob.cast(verifiedBootKey).getStartOff(), KMByteBlob.cast(verifiedBootKey).length()); - // pushOctetString(repo.verifiedBootKey, (short) 0, (short) repo.verifiedBootKey.length); + // Finally sequence header pushSequenceHeader((short) (last - stackPtr)); // ... and tag Id @@ -645,27 +631,7 @@ private static void pushBooleanHeader(short len) { pushLength(len); pushByte((byte) 0x01); } - /* - // All Attestation Id tags are byte tags/octet strings - private static boolean pushAttIds(short tagId) { - if(!repo.isAttIdSupported()) return true; - byte index = 0; - while (index < repo.ATT_ID_TABLE_SIZE) { - if (repo.getAttIdLen(index) != 0) { - if(tagId == repo.getAttIdTag(index)) { - pushBytesTag( - repo.getAttIdTag(index), - repo.getAttIdBuffer(index), - repo.getAttIdOffset(index), - repo.getAttIdLen(index)); - return true; - } - } - index++; - } - return false; - } - */ + // Only SET of INTEGERS supported are padding, digest, purpose and blockmode // All of these are enum array tags i.e. byte long values private static void pushEnumArrayTag(short tagId, byte[] buf, short start, short len) { @@ -797,13 +763,7 @@ private static void pushAuthKeyId() { short last = stackPtr; // if (repo.getAuthKeyId() == 0) return; if (authKey == 0) return; - /* - pushKeyIdentifier( - repo.getCertDataBuffer(), - repo.getAuthKeyId(), - repo.getAuthKeyIdLen()); // key identifier is [0]'th tagged in a sequence - */ pushKeyIdentifier( KMByteBlob.cast(authKey).getBuffer(), KMByteBlob.cast(authKey).getStartOff(), @@ -984,15 +944,4 @@ public KMAttestationCert makeUniqueId(byte[] scratchPad, short scratchPadOff, } return uniqueId(timeOffset); } - - /* private static void print(byte[] buf, short start, short length){ - StringBuilder sb = new StringBuilder(); - for(int i = start; i < (start+length); i++){ - sb.append(String.format("%02X", buf[i])) ; - //if((i-start)%16 == 0 && (i-start) != 0) sb.append(String.format("\n")); - } - System.out.println(sb.toString()); - } - - */ } diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java index e33ebf69..242499ed 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java +++ b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java @@ -146,7 +146,6 @@ public short sign(byte[] bytes, short i, short i1, byte[] bytes1, short i2) thro Util.arrayCopyNonAtomic(sig, (short)0, bytes1, i2, (short)sig.length); return (short)sig.length; } catch (SignatureException e) { - // TODO Auto-generated catch block CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } return len; @@ -165,7 +164,6 @@ public boolean verify(byte[] bytes, short i, short i1, byte[] bytes1, short i2, update(bytes, i , i1); return sunSigner.verify(bytes1, i2, i3); } catch (SignatureException e) { - // TODO Auto-generated catch block CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } return false; diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java index 86bee82f..82f41313 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java +++ b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java @@ -162,7 +162,6 @@ public AESKey createAESKey(byte[] buf, short startOff, short length) { public DESKey createTDESKey() { - // TODO check whether 168 bit or 192 bit byte[] rndNum = new byte[24]; newRandomNumber(rndNum, (short) 0, (short)rndNum.length); return createTDESKey(rndNum, (short)0, (short)rndNum.length); @@ -683,13 +682,9 @@ public void getAESGCMOutputSize(short opHandle, short dataSize, short macLength) public KMCipher createRsaDecipher(short padding, short digest, byte[] secret, short secretStart, short secretLength, byte[] modBuffer, short modOff, short modLength) { byte cipherAlg = mapCipherAlg(KMType.RSA, (byte)padding, (byte)0); - // TODO implement OAEP algorithm using SunJCE. if (cipherAlg == Cipher.ALG_RSA_PKCS1_OAEP) { return createRsaOAEP256Cipher(KMType.DECRYPT,(byte)digest,secret,secretStart,secretLength,modBuffer,modOff,modLength); } - /*else if(padding == KMCipher.PAD_PKCS1) cipherAlg = Cipher.ALG_RSA_PKCS1; - else cipherAlg = Cipher.ALG_RSA_NOPAD; - */ Cipher rsaCipher = Cipher.getInstance(cipherAlg,false); RSAPrivateKey key = (RSAPrivateKey) KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PRIVATE, KeyBuilder.LENGTH_RSA_2048, false); key.setExponent(secret,secretStart,secretLength); @@ -870,7 +865,6 @@ public KMCipher createSymmetricCipher(short alg, short purpose, short blockMode, key = KeyBuilder.buildKey(KeyBuilder.TYPE_DES,len,false); ((DESKey) key).setKey(secret,secretStart); symmCipher = Cipher.getInstance((byte)cipherAlg, false); - //TODO Consume only 8 bytes of iv. the random number for iv is of 16 bytes. //While sending back the iv send only 8 bytes. symmCipher.init(key, mapPurpose(purpose), ivBuffer, ivStart, (short)8); break; @@ -1090,12 +1084,10 @@ private void initEntropyPool(byte[] pool) { trng.nextBytes(pool, (short) 0, (short) pool.length); } catch (CryptoException exp) { if (exp.getReason() == CryptoException.NO_SUCH_ALGORITHM) { - // TODO change this when possible // simulator does not support TRNG algorithm. So, PRNG algorithm (deprecated) is used. trng = RandomData.getInstance(RandomData.ALG_PSEUDO_RANDOM); trng.nextBytes(pool, (short) 0, (short) pool.length); } else { - // TODO change this to proper error code ISOException.throwIt(ISO7816.SW_UNKNOWN); } } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMDecoder.java b/Applet/Applet/src/com/android/javacard/keymaster/KMDecoder.java index 948728ec..d74e35d0 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMDecoder.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMDecoder.java @@ -192,8 +192,6 @@ private short decodeKeyParam(short exp) { private short decodeEnumArrayTag(short exp) { readTagKey(KMEnumArrayTag.cast(exp).getTagType()); - // The value must be byte blob - // TODO check this out. return KMEnumArrayTag.instance(this.tagKey, decode(KMEnumArrayTag.cast(exp).getValues())); } @@ -250,7 +248,6 @@ private short decodeArray(short exp) { private short decodeEnumTag(short exp) { readTagKey(KMEnumTag.cast(exp).getTagType()); // Enum Tag value will always be integer with max 1 byte length. - // TODO Check this out. if ((buffer[startOff] & MAJOR_TYPE_MASK) != UINT_TYPE) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } @@ -273,7 +270,6 @@ private short decodeEnumTag(short exp) { private short decodeBoolTag(short exp) { readTagKey(KMBoolTag.cast(exp).getTagType()); // BOOL Tag is a leaf node and it must always have tiny encoded uint value = 1. - // TODO check this out. if ((buffer[startOff] & MAJOR_TYPE_MASK) != UINT_TYPE) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMEncoder.java b/Applet/Applet/src/com/android/javacard/keymaster/KMEncoder.java index 79c246ec..273149ee 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMEncoder.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMEncoder.java @@ -30,7 +30,6 @@ public class KMEncoder { // masks private static final byte ADDITIONAL_MASK = 0x1F; - private static final byte MAJOR_TYPE_MASK = (byte) 0xE0; // value length private static final byte UINT8_LENGTH = (byte) 0x18; @@ -39,8 +38,7 @@ public class KMEncoder { private static final byte UINT64_LENGTH = (byte) 0x1B; private static final short TINY_PAYLOAD = 0x17; private static final short SHORT_PAYLOAD = 0x100; - - // TODO move the following to transient memory. + //TODO make this static. private byte[] buffer; private short startOff; private short length; diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMError.java b/Applet/Applet/src/com/android/javacard/keymaster/KMError.java index 8a971bba..043fae96 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMError.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMError.java @@ -83,4 +83,13 @@ public class KMError { public static short UNIMPLEMENTED = 100; public static short VERSION_MISMATCH = 101; public static short UNKNOWN_ERROR = 1000; + + //Extended errors + public static short SW_CONDITIONS_NOT_SATISFIED = 1001; + public static short UNSUPPORTED_CLA = 1002; + public static short INVALID_P1P2 = 1002; + public static short UNSUPPORTED_INSTRUCTION = 1002; + public static short CMD_NOT_ALLOWED = 1002; + public static short SW_WRONG_LENGTH = 1002; + public static short INVALID_DATA = 1002; } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMInteger.java b/Applet/Applet/src/com/android/javacard/keymaster/KMInteger.java index 0ebd4c52..090f6e86 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMInteger.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMInteger.java @@ -18,7 +18,6 @@ import javacard.framework.ISO7816; import javacard.framework.ISOException; -import javacard.framework.JCSystem; import javacard.framework.Util; /** @@ -159,10 +158,8 @@ public static short compare(short num1, short num2){ short num2Buf = repository.alloc((short)8); Util.arrayFillNonAtomic(repository.getHeap(),num1Buf,(short)8,(byte)0); Util.arrayFillNonAtomic(repository.getHeap(),num2Buf,(short)8,(byte)0); - short numPtr = KMInteger.cast(num1).getStartOff(); short len = KMInteger.cast(num1).length(); KMInteger.cast(num1).getValue(repository.getHeap(),(short)(num1Buf+(short)(8-len)),len); - numPtr = KMInteger.cast(num2).getStartOff(); len = KMInteger.cast(num2).length(); KMInteger.cast(num2).getValue(repository.getHeap(),(short)(num2Buf+(short)(8-len)),len); return Util.arrayCompare( diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMIntegerArrayTag.java b/Applet/Applet/src/com/android/javacard/keymaster/KMIntegerArrayTag.java index 3df79a56..7faa4c00 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMIntegerArrayTag.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMIntegerArrayTag.java @@ -125,7 +125,6 @@ private static boolean validateKey(short key) { return false; } - // TODO this should be combined with validateKey to actually isValidTag {tagType, tagKey} pair. private static boolean validateTagType(short tagType) { return (tagType == ULONG_ARRAY_TAG) || (tagType == UINT_ARRAY_TAG); } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMIntegerTag.java b/Applet/Applet/src/com/android/javacard/keymaster/KMIntegerTag.java index f8fb4c1a..2700580f 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMIntegerTag.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMIntegerTag.java @@ -133,7 +133,6 @@ private static boolean validateKey(short key) { return false; } - // TODO this should be combined with validateKey to actually isValidTag {tagType, tagKey} pair. private static boolean validateTagType(short tagType) { return (tagType == DATE_TAG) || (tagType == UINT_TAG) || (tagType == ULONG_TAG); } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index ca6a2bd9..846e81e0 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -235,6 +235,28 @@ public void uninstall() { repository.onUninstall(); } + private short mapISOErrorToKMError(short reason) { + switch (reason) { + case ISO7816.SW_CLA_NOT_SUPPORTED: + return KMError.UNSUPPORTED_CLA; + case ISO7816.SW_CONDITIONS_NOT_SATISFIED: + return KMError.SW_CONDITIONS_NOT_SATISFIED; + case ISO7816.SW_COMMAND_NOT_ALLOWED: + return KMError.CMD_NOT_ALLOWED; + case ISO7816.SW_DATA_INVALID: + return KMError.INVALID_DATA; + case ISO7816.SW_INCORRECT_P1P2: + return KMError.INVALID_P1P2; + case ISO7816.SW_INS_NOT_SUPPORTED: + return KMError.UNSUPPORTED_INSTRUCTION; + case ISO7816.SW_WRONG_LENGTH: + return KMError.SW_WRONG_LENGTH; + case ISO7816.SW_UNKNOWN: + default: + return KMError.UNKNOWN_ERROR; + } + } + /** * Processes an incoming APDU and handles it using command objects. * @@ -421,6 +443,7 @@ && isProvisioningComplete())) { sendError(apdu, KMException.reason); exception.clear(); } catch (ISOException exp) { + sendError(apdu, mapISOErrorToKMError(exp.getReason())); freeOperations(); } finally { resetData(); @@ -542,6 +565,9 @@ private void processGetHwInfoCmd(APDU apdu) { sendOutgoing(apdu); } + //TODO VTS 4.0 addLargeEntropy fails, as the input buffer is 2k + //TODO Need to fix this issue by introducing stackIndex which + //increase bottom to top on internal memory. private void processAddRngEntropyCmd(APDU apdu) { // Receive the incoming request fully from the master. receiveIncoming(apdu); @@ -557,6 +583,7 @@ private void processAddRngEntropyCmd(APDU apdu) { KMException.throwIt(KMError.INVALID_ARGUMENT); } seProvider.addRngEntropy(blob.getBuffer(), blob.getStartOff(), blob.length()); + sendError(apdu, KMError.OK); } private void processGetCertChainCmd(APDU apdu) { @@ -916,9 +943,6 @@ private void processComputeSharedHmacCmd(APDU apdu) { tmpVariables[6]); tmpVariables[3] += tmpVariables[6]; // increment the concat index } else if (tmpVariables[7] == 0) { - // TODO according to hal specs seed should always be empty. Confirm this. - // The seed we are passing is of zero length so if seed length is zero - // the seed generated here is found. tmpVariables[7] = 1; } // if nonce is present get nonce - 32 bytes @@ -1257,8 +1281,7 @@ private void processAttestKeyCmd(APDU apdu) { // parse key blob parseEncryptedKeyBlob(scratchPad); - // TODO This below code is added to pass one of the VTS 4.1 tests. - // TODO Need to confirm with Shawn and modify this accordingly. + // This below code is added to pass one of the VTS 4.1 tests. tmpVariables[0] = KMKeyParameters.findTag( KMType.BOOL_TAG, KMType.DEVICE_UNIQUE_ATTESTATION, data[KEY_PARAMETERS]); @@ -2009,7 +2032,6 @@ private void processUpdateOperationCmd(APDU apdu) { if (op.getAlgorithm() == KMType.RSA) { KMException.throwIt(KMError.OPERATION_CANCELLED); } - // TODO refactor and optimize this tmpVariables[0] = KMByteBlob.cast(data[INPUT_DATA]).length(); short additionalExpOutLen = 0; if (op.getAlgorithm() == KMType.AES) { @@ -2364,8 +2386,6 @@ private void authorizeBlockModeAndMacLength(KMOperationState op) { } op.setMacLength(macLen); } - // TODO Ignore MAC_LENGTH tag for other modes of operation. - // else if(macLen != KMType.INVALID_VALUE) KMException.throwIt(KMError.INVALID_ARGUMENT); break; case KMType.DES: if (param == KMType.INVALID_VALUE) KMException.throwIt(KMError.INVALID_ARGUMENT); @@ -2566,8 +2586,6 @@ private void beginSignVerifyOperation(KMOperationState op) { KMByteBlob.cast(data[PUB_KEY]).length())); } } catch (CryptoException exp) { - // TODO remove this - // Javacard does not support NO digest based signing. KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM); } break; @@ -2633,8 +2651,6 @@ private void beginSignVerifyOperation(KMOperationState op) { (short) 0, (short) 0)); } catch (CryptoException exp) { - // TODO remove the following - // Javacard does not support NO digest based signing. KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM); } break; @@ -2844,7 +2860,6 @@ private void importKey(APDU apdu, byte[] scratchPad) { if (tmpVariables[0] != KMType.INVALID_VALUE) { // before generating key, check whether max count reached if (repository.getKeyBlobCount() > KMRepository.MAX_BLOB_STORAGE) { - // TODO which error to return? KMException.throwIt(KMError.UNKNOWN_ERROR); } repository.persistAuthTag(data[AUTH_TAG]); @@ -3165,12 +3180,7 @@ private void updateKeyParameters(byte[] ptrArr, short len) { data[KEY_PARAMETERS] = KMKeyParameters.instance(tmpVariables[1]); } - // TODO Add Signature verification. - // This command is executed after every reboot of Android OS. - // TODO After every reboot the first command to be executed should be - // processSetBootParams, but there is no signal/notification triggered - // inside the applet when the android device reboots. So this check is not - // implemented. + // This command is executed to set the boot parameters. private void processSetBootParamsCmd(APDU apdu) { receiveIncoming(apdu); byte[] scratchPad = apdu.getBuffer(); @@ -3355,7 +3365,6 @@ private static void processGenerateKey(APDU apdu) { if (tmpVariables[0] != KMType.INVALID_VALUE) { // before generating key, check whether max count reached if (repository.getKeyBlobCount() > KMRepository.MAX_BLOB_STORAGE) { - // TODO which error to return? KMException.throwIt(KMError.UNKNOWN_ERROR); } repository.persistAuthTag(data[AUTH_TAG]); @@ -3667,9 +3676,6 @@ private static void createEncryptedKeyBlob(byte[] scratchPad) { // make key characteristics - returns key characteristics in data[KEY_CHARACTERISTICS] makeKeyCharacteristics(scratchPad); // make root of trust blob - // data[ROT] = - // KMByteBlob.instance( - // repository.verifiedBootKey, (short) 0, (short) repository.verifiedBootKey.length); data[ROT] = repository.getVerifiedBootKey(); // make hidden key params list @@ -3685,7 +3691,7 @@ private static void createEncryptedKeyBlob(byte[] scratchPad) { KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_AUTH_TAG, data[AUTH_TAG]); KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_NONCE, data[NONCE]); KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_KEYCHAR, data[KEY_CHARACTERISTICS]); - tmpVariables[0] = repository.alloc((short) 1024); // TODO use buffer + tmpVariables[0] = repository.alloc((short) 1024); tmpVariables[1] = encoder.encode(data[KEY_BLOB], repository.getHeap(), tmpVariables[0]); data[KEY_BLOB] = KMByteBlob.instance(repository.getHeap(), tmpVariables[0], tmpVariables[1]); } From b3d0f18ec5ea4fcfeeeb4e10bb0e2a56d34bbb21 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Thu, 26 Nov 2020 00:10:31 +0000 Subject: [PATCH 30/42] Support for Amendment H --- .../javacard/keymaster/AndroidSEProvider.java | 31 ++++++-- .../keymaster/KMAttestationCertImpl.java | 4 +- .../javacard/keymaster/KMSEProviderImpl.java | 4 +- .../keymaster/KMAttestationCertImpl.java | 4 +- .../javacard/keymaster/KMJcardSimulator.java | 33 +++++++++ .../javacard/keymaster/KMSEProviderImpl.java | 3 +- .../javacard/keymaster/KMKeymasterApplet.java | 68 +++++++++++++++--- .../javacard/keymaster/KMRepository.java | 42 +++++++++-- .../javacard/keymaster/KMSEProvider.java | 4 +- .../javacard/keymaster/KMUpgradable.java | 14 ++++ Applet/lib/gpapi-upgrade.jar | Bin 0 -> 12638 bytes 11 files changed, 179 insertions(+), 28 deletions(-) create mode 100644 Applet/Applet/src/com/android/javacard/keymaster/KMUpgradable.java create mode 100644 Applet/lib/gpapi-upgrade.jar diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java index db8e86db..d85dd781 100644 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java +++ b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java @@ -15,6 +15,7 @@ */ package com.android.javacard.keymaster; +import org.globalplatform.upgrade.Element; import javacard.framework.JCSystem; import javacard.framework.Util; import javacard.security.AESKey; @@ -159,12 +160,10 @@ public class AndroidSEProvider implements KMSEProvider { private static AndroidSEProvider androidSEProvider = null; public static AndroidSEProvider getInstance() { - if (androidSEProvider == null) - androidSEProvider = new AndroidSEProvider(); return androidSEProvider; } - private AndroidSEProvider() { + public AndroidSEProvider(boolean isUpgrading) { // Re-usable AES,DES and HMAC keys in persisted memory. aesKeys = new AESKey[2]; aesKeys[KEYSIZE_128_OFFSET] = (AESKey) KeyBuilder.buildKey( @@ -200,7 +199,9 @@ private AndroidSEProvider() { // Random number generator initialisation. rng = RandomData.getInstance(RandomData.ALG_KEYGENERATION); //Allocate buffer for certificate chain. - certificateChain = new byte[CERT_CHAIN_MAX_SIZE]; + if(!isUpgrading) + certificateChain = new byte[CERT_CHAIN_MAX_SIZE]; + androidSEProvider = this; } public void clean() { @@ -1182,4 +1183,26 @@ public boolean isDeviceRebooted() { public void clearDeviceBooted(boolean resetBootFlag) { // To be filled } + + @Override + public void onSave(Element element) { + element.write(certificateChain); + } + + @Override + public void onRestore(Element element) { + certificateChain = (byte[]) element.readObject(); + } + + @Override + public short getBackupPrimitiveByteCount() { + return (short) 0; + } + + @Override + public short getBackupObjectCount() { + return (short) 1; + } + + } diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java index 9468522e..77a97b1e 100644 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -889,7 +889,7 @@ public void build() { tbsLength = (short) (tbsLength - tbsOffset); pushSequenceHeader((short) (last - stackPtr)); certStart = stackPtr; - short sigLen = KMSEProviderImpl.instance() + short sigLen = AndroidSEProvider.getInstance() .ecSign256( KMByteBlob.cast(signPriv).getBuffer(), KMByteBlob.cast(signPriv).getStartOff(), @@ -933,7 +933,7 @@ public KMAttestationCert makeUniqueId(byte[] scratchPad, short scratchPadOff, scratchPadOff++; timeOffset = KMByteBlob.instance((short) 32); - appIdOff = KMSEProviderImpl.instance().hmacSign(key, keyOff, keyLen, + appIdOff = AndroidSEProvider.getInstance().hmacSign(key, keyOff, keyLen, scratchPad, /* data */ temp, /* data start */ scratchPadOff, /* data length */ diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMSEProviderImpl.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMSEProviderImpl.java index d9ff00eb..11778a7d 100644 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMSEProviderImpl.java +++ b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMSEProviderImpl.java @@ -2,7 +2,7 @@ package com.android.javacard.keymaster; public class KMSEProviderImpl { - public static KMSEProvider instance(){ - return AndroidSEProvider.getInstance(); + public static KMSEProvider instance(boolean isUpgrading){ + return new AndroidSEProvider(isUpgrading); } } diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java index 9468522e..401cfc18 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -889,7 +889,7 @@ public void build() { tbsLength = (short) (tbsLength - tbsOffset); pushSequenceHeader((short) (last - stackPtr)); certStart = stackPtr; - short sigLen = KMSEProviderImpl.instance() + short sigLen = KMJcardSimulator.getInstance() .ecSign256( KMByteBlob.cast(signPriv).getBuffer(), KMByteBlob.cast(signPriv).getStartOff(), @@ -933,7 +933,7 @@ public KMAttestationCert makeUniqueId(byte[] scratchPad, short scratchPadOff, scratchPadOff++; timeOffset = KMByteBlob.instance((short) 32); - appIdOff = KMSEProviderImpl.instance().hmacSign(key, keyOff, keyLen, + appIdOff = KMJcardSimulator.getInstance().hmacSign(key, keyOff, keyLen, scratchPad, /* data */ temp, /* data start */ scratchPadOff, /* data length */ diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java index 82f41313..76ebb3e9 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java +++ b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java @@ -58,6 +58,8 @@ import javax.crypto.spec.PSource; import javax.crypto.spec.SecretKeySpec; +import org.globalplatform.upgrade.Element; + /** * Simulator only supports 512 bit RSA key pair, 128 AES Key, 128 bit 3Des key, less then 256 bit EC * Key, and upto 512 bit HMAC key. Also simulator does not support TRNG, so this implementation just @@ -83,6 +85,12 @@ public class KMJcardSimulator implements KMSEProvider { private static byte[] rndNum; private byte[] certificateChain; + private static KMJcardSimulator jCardSimulator = null; + + public static KMJcardSimulator getInstance() { + return jCardSimulator; + } + // Implements Oracle Simulator based restricted crypto provider public KMJcardSimulator() { // Various Keys @@ -102,6 +110,7 @@ public KMJcardSimulator() { // various ciphers //Allocate buffer for certificate chain. certificateChain = new byte[CERT_CHAIN_MAX_SIZE]; + jCardSimulator = this; } @@ -1279,4 +1288,28 @@ public boolean isDeviceRebooted() { public void clearDeviceBooted(boolean resetBootFlag) { // To be filled } + + @Override + public void onSave(Element ele) { + // TODO Auto-generated method stub + + } + + @Override + public void onRestore(Element ele) { + // TODO Auto-generated method stub + + } + + @Override + public short getBackupPrimitiveByteCount() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public short getBackupObjectCount() { + // TODO Auto-generated method stub + return 0; + } } diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMSEProviderImpl.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMSEProviderImpl.java index 34628ba7..43eb2f94 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMSEProviderImpl.java +++ b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMSEProviderImpl.java @@ -2,7 +2,8 @@ package com.android.javacard.keymaster; public class KMSEProviderImpl { - public static KMSEProvider instance(){ + public static KMSEProvider instance(boolean isUpgrading) { + //Ignore isUpgrading flag as JCardSimulator does not support upgrade. return new KMJcardSimulator(); } } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 846e81e0..e6f0e55c 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -26,12 +26,13 @@ import javacard.security.CryptoException; import javacardx.apdu.ExtendedLength; +import org.globalplatform.upgrade.*; /** * KMKeymasterApplet implements the javacard applet. It creates repository and other install time * objects. It also implements the keymaster state machine and handles javacard applet life cycle * events. */ -public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLength { +public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLength, OnUpgradeListener { // Constants. public static final byte AES_BLOCK_SIZE = 16; public static final byte DES_BLOCK_SIZE = 8; @@ -182,20 +183,21 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe /** Registers this applet. */ protected KMKeymasterApplet() { - seProvider = KMSEProviderImpl.instance(); + boolean isUpgrading = UpgradeManager.isUpgrading(); + seProvider = KMSEProviderImpl.instance(isUpgrading); + repository = new KMRepository(isUpgrading); byte[] buf = JCSystem.makeTransientByteArray((short) 32, JCSystem.CLEAR_ON_DESELECT); - keymasterState = KMKeymasterApplet.INIT_STATE; data = JCSystem.makeTransientShortArray((short) DATA_ARRAY_SIZE, JCSystem.CLEAR_ON_RESET); - repository = new KMRepository(); tmpVariables = JCSystem.makeTransientShortArray((short) TMP_VARIABLE_ARRAY_SIZE, JCSystem.CLEAR_ON_RESET); - seProvider.getTrueRandomNumber(buf, (short) 0, KMRepository.MASTER_KEY_SIZE); - repository.initMasterKey(buf, (short) 0, KMRepository.MASTER_KEY_SIZE); - seProvider.newRandomNumber(buf, (short) 0, KMRepository.SHARED_SECRET_KEY_SIZE); + if(!isUpgrading) { + keymasterState = KMKeymasterApplet.INIT_STATE; + seProvider.getTrueRandomNumber(buf, (short) 0, KMRepository.MASTER_KEY_SIZE); + repository.initMasterKey(buf, (short)0, KMRepository.MASTER_KEY_SIZE); + } KMType.initialize(); encoder = new KMEncoder(); decoder = new KMDecoder(); - register(); } /** @@ -206,7 +208,7 @@ protected KMKeymasterApplet() { * @param bLength the length in bytes of the parameter data in bArray */ public static void install(byte[] bArray, short bOffset, byte bLength) { - new KMKeymasterApplet(); + new KMKeymasterApplet().register(bArray, (short) (bOffset + 1), bArray[bOffset]); } /** @@ -3965,4 +3967,52 @@ private void add(byte[] buf, short op1, short op2, short result) { index--; } } + + @Override + public void onCleanup() { + } + + @Override + public void onConsolidate() { + } + + @Override + public void onRestore(Element element) { + element.initRead(); + provisionStatus = element.readByte(); + keymasterState = element.readByte(); + repository.onRestore(element); + seProvider.onRestore(element); + } + + @Override + public Element onSave() { + // SEProvider count + short primitiveCount = seProvider.getBackupPrimitiveByteCount(); + short objectCount = seProvider.getBackupObjectCount(); + //Repository count + primitiveCount += repository.getBackupPrimitiveByteCount(); + objectCount += repository.getBackupObjectCount(); + //KMKeymasterApplet count + primitiveCount += computePrimitveDataSize(); + objectCount += computeObjectCount(); + + // Create element. + Element element = UpgradeManager.createElement(Element.TYPE_SIMPLE, + primitiveCount, objectCount); + element.write(provisionStatus); + element.write(keymasterState); + repository.onSave(element); + seProvider.onSave(element); + return element; + } + + private short computePrimitveDataSize() { + // provisionStatus + keymasterState + return (short) 2; + } + + private short computeObjectCount() { + return (short) 0; + } } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java index 168b6a2b..dcc34f43 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java @@ -16,6 +16,8 @@ package com.android.javacard.keymaster; +import org.globalplatform.upgrade.Element; + import javacard.framework.ISO7816; import javacard.framework.ISOException; import javacard.framework.JCSystem; @@ -25,7 +27,7 @@ * KMRepository class manages persistent and volatile memory usage by the applet. Note the repository * is only used by applet and it is not intended to be used by seProvider. */ -public class KMRepository { +public class KMRepository implements KMUpgradable { // Data table configuration public static final short DATA_INDEX_SIZE = 31; public static final short DATA_INDEX_ENTRY_SIZE = 4; @@ -99,8 +101,8 @@ public static KMRepository instance() { return repository; } - public KMRepository() { - newDataTable(); + public KMRepository(boolean isUpgrading) { + newDataTable(isUpgrading); heap = JCSystem.makeTransientByteArray(HEAP_SIZE, JCSystem.CLEAR_ON_RESET); heapIndex = 0; operationStateTable = new Object[MAX_OPS]; @@ -275,10 +277,12 @@ private short dataAlloc(short length) { } - private void newDataTable(){ - if(dataTable == null) { - dataTable = new byte[DATA_MEM_SIZE]; - dataIndex = (short)(DATA_INDEX_SIZE*DATA_INDEX_ENTRY_SIZE); + private void newDataTable(boolean isUpgrading){ + if (!isUpgrading) { + if (dataTable == null) { + dataTable = new byte[DATA_MEM_SIZE]; + dataIndex = (short) (DATA_INDEX_SIZE * DATA_INDEX_ENTRY_SIZE); + } } } @@ -649,4 +653,28 @@ public short getKeyBlobCount(){ } return count; } + + @Override + public void onSave(Element ele) { + ele.write(dataIndex); + ele.write(dataTable); + } + + @Override + public void onRestore(Element ele) { + dataIndex = ele.readShort(); + dataTable = (byte[]) ele.readObject(); + } + + @Override + public short getBackupPrimitiveByteCount() { + // dataIndex + return (short) 2; + } + + @Override + public short getBackupObjectCount() { + // dataTable + return (short) 1; + } } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java b/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java index 8202fe12..e0ee49dc 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java @@ -1,12 +1,14 @@ package com.android.javacard.keymaster; +import org.globalplatform.upgrade.Element; + /** * KMSEProvider is facade to use SE specific methods. The main intention of this interface is to * abstract the cipher, signature and backup and restore related functions. The instance of this * interface is created by the singleton KMSEProviderImpl class for each provider. At a time there * can be only one provider in the applet package. */ -public interface KMSEProvider { +public interface KMSEProvider extends KMUpgradable { /** * Create a symmetric key instance. If the algorithm and/or keysize are not supported then it * should throw a CryptoException. diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMUpgradable.java b/Applet/Applet/src/com/android/javacard/keymaster/KMUpgradable.java new file mode 100644 index 00000000..e3958a67 --- /dev/null +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMUpgradable.java @@ -0,0 +1,14 @@ +package com.android.javacard.keymaster; + +import org.globalplatform.upgrade.Element; + +public interface KMUpgradable { + void onSave(Element ele); + + void onRestore(Element ele); + + short getBackupPrimitiveByteCount(); + + short getBackupObjectCount(); + +} diff --git a/Applet/lib/gpapi-upgrade.jar b/Applet/lib/gpapi-upgrade.jar new file mode 100644 index 0000000000000000000000000000000000000000..e4814bde4b6b21982103c55f9b1a3a4a58f0b807 GIT binary patch literal 12638 zcmbul1yEi~w=IghySuwPgy8P(?(XjHF2UV`gkZtl-Q6KTa3|P<{mahIIXCxKy-7hW zinRvon>~B>izz?0X><$9HtpU3AhEfMm-{hYJV5zg}VnH-}a5?OzDJ zeZRj16ac{6i+L*l^Aljd{nggNl-|_J)Ys zA%jv|s@$PcJ>vU-=zypxIr)I79gt(CMRqYETXUFxgZHlPZdORPeTeAd3ak!pNs7$ zDsU3PfnzxpG(K@0n3_<~R*^JWQ&-Asd;ug~h*%8s?6!<ulJT_AFDwM;coA!sJVdE!jlhf z3Vp9$(%m-{W3W{3Oq>@qRU+0OlYx|sXGdt$V#n|)eGaB7O@?@rhz24mLrnK8rjJ<7 zby1W0Xz|GyaU-XEKg_cXO5ej}###IG&!R*>rDqbNdC}zDx>##9AcZAuOrh318><7Z zQouxNYyD^!JZe^Whz>BcyK9C^{HPABl-^`2iQ)pH1|i*bE%1<4L)R-vXQ4U~;#YoL z=_Lv(6@Z9RvC^ zgUUJs5>8=Lv`?0$!%I3|1BSdF%9~xHtX^Uf8mG9MZs@Ll zG7eI#xJy%$AS5E^$M)MVPcT#5@*ClHDS$ zv_TZ015iVNiIWnw^b|@h;l7P&BJd1M9r6OF>nFFkQ?iQnwM_$677`gRiUq7%l8c}y z21=PfqV*aPOLs{?6#45Z9IV|n=~Q}!6Z(!nLH-XeKhTP`3HR~a(IEo11Z=lD>gmAh zK(SCAdK;gN_D6lTmMoohe4ker&ae|*I-gH%>Ud81{czplOzZBi;d}_krq#L{y350v zPo-aoN?NbHv7416#xs-;g@-@6v>6(Qo3H+Kx0DL@UC(URq&AO9<&n>LmWa_=X^jFN520gYRTy@W(MBwmQbqNs3AY-Mb1Y~%D7Q5LC4 z+wQRaMU-jz;42>qvNYq-s2XY(U)y`&%}JLvz$*b) zkVxCv@oi1i7+;3jAQY?f=ZU zS<`5{Q&$9%s%xn1LW>@t@>xpfqljzr<2>bUI>i{8DhdrGP@)AD28)IjgGC^{3S9jc zmIrYMk9Bv!(&iJOO&CJk7&P^aNBBXOYZ44=Kiklx^gN=V)w4?;wBthM%?Am&nB9i- zN+{JW5`7$pDc}z6-K(NH=Wn@J!Kf`NUeNClUXEK(Cge~TzO6RzLZ;e;rHANfY%*Mz zRZ$+C?VO$SR|m5+tF%79()dOp&ycf}(dMk2uKZ3LYPEZKyc>3uWJbLc^01A;k_iLcI2qM z@~ramR`TfxBrKk74}O=5L+@4-6>!FRNHk-S=Ql*DKt*q??<8_{W{PM~EqvmXgo{Lu zl=fv5C+Iz|Sg^qA_0ai|BZ!)f{Ky;Rk>#2YaUF9u>p6JHe>STofbp~ZZfTg%u)$W0 zo`bHeD5*c#CL}P8lR7~ z7x-cy?Gdq}x^2okGmZL(O{RYI+RR2viTI&CObn#XfxCS#pIj{7@w~` z3^5^cAZ4fNdEWVj>6YaB@WFm=t!W3!z2b1Ww(EFd!}rnHWNDNEu&A!o_A+^~-vED6 z;SqgzFA`3s-Y+jZd*bl0W9XoYqIn0C^RqabNi2r3NQ=@yoKqZ9T^lk|g?Z@7rIU)4 zRZfY>WOv_pLU1>n+}Fw*;ut^ta~^0fp0=%NI1^oLZDl7@Rc@_wg1Wo~;AIBXg7~u; z*wvE@;rc~xM&^~($TQ(P!RZDJksnnC5mWn3t%;>{-pT5_ACqsAS8z3n55a^b>Gds! zH~#AA^0%*IP~PY!73NpEDg2FY$p1_?zY@)fhV@%VhV+6*@Txxrgg%6@OU57B($9Fr z0e6&N7R}LDbXTMnPaTe)Fmg&)SsMKMI5tA}jf7O#-a%TsmmeWRYkYK^`D*kyE?H`Q zFc@i>rZ`e-!boRtdaRzZ*twp8Njdgxqs8~^d~@@K*PcK|=%kj%(K0?+CjFaKQfZ|` z@Ju(R`tmm>1EalqB%3k`{Uqn*Qbw9anUor?WEm)4a&vK5SLi&`SLN`pM3vGibU`S| z?8BM_pKIA>_O460`oFi5W|at=1k-4;dcZk6MUbS<%LuV4E4GIDhNllZf8%$SN#tQ@ zoXVK(FP+}AR11-8#XVGNRjT<23Pp3;Wa>*aqQLDI0+Nrc5N`r@>QBIFzzF22m9K|x^5S`IEQlt^ztG8aybO0wW#v=EmVhZ>4X>5oE+(zs%1$D{b z5CltgkbRv;IY33d3c3^g35^A|E^5#=9hqADd)X##gak0jS1r&x_gqa~3{u=qcs-m0JeVYrBtdl=raw>35au(@L>8K?JTxQYRqL^vexsTs zv@R8h>%LxNVON+czj8dx$*{#H~frD8+}T(F-$ ztSA}#6V=OjH2*|lpOcHm2=cTLlH=75=QE8F)wpDyemG!b21FOO#d zmg$(qcVLHUEcwB517-qMjXSr{1TnW_VmL`IZg_O90k zVCzh&Us74=Wc2k)HQmGZ*f%w)Mz0O3W7ECVpf_gGyAL~=IJ10>WaykHhQTn9xL{MGC(YGN(H&L?P%c-n1&L(1O4DVwhWIIrap-ktK zt|(dXZ0jslRtjYMNM`b#N`0sy+UzbieXY67@*W=W{s)t}; zth!;HTdL8z*(-`iockO;k^p5uK{Y{amO7e~Wl4$9W)2iwz}hB3hImVYf-jugv{i@T z74?H)LxRO8z~g&9|GX&`)pjX4$ii5jjG8u7PcMfeN?NXk99tgv08 zGizp;-2|sd_La{z3?IRd!FR2$UGFm1puw}&S<{Mf>b3EqfrEDk*YRjQfFj-bWP*s@ z5SuIN3E|Nj!*QL>fgnBqk&;PiUotll>l3yRh^AAHZkk=$C)1)cb3ssZ33O)jKzuZ5 zNmRIPkeaN?cxoa256P4@-|TO-S@@-q$_5Ds;$sPABc;>vNMZAJ`8gJwHv`w{p!>w6 z(G}@61vKQ>OLq%Q0gS&#P7U@94$_)(UTGj}R)9rm zP!MMe<;w(sN*`p!i^*uFV0b9a%Zt7)gYke%qWvbtnv%cpptZitL;*#JnNi4&shE-2gyDNj%yjl}DXnc^bY?9hexKG#Dv*W#G95|aXZ)8Geq$NRd#I53i zJS;cQI>p|w9+$C+mdlNT6Q|Q{jwwlt(@KDXU|KAX0)e>EQQt*_Z!_(&LUfs7If^xV zW?m!f=bw=_l#=d7ls4CYFc>;80N-)J(ogNMrg;%tz0Mbk-$B8!$@D{ekX1X3a^Mxy zHGQHXsmi8uczCo8WFQtRbA^wLy7~rtFA_A`L?VwQXyyDVe9I#F>SG0EubomLiLich zu9Vf|y7p-4Mli%&ai_}*4w8UAF%SM}5pN6-qy9w>F(?2z&^*{vWDl_!-%nAE&u)$^ zrBxKr>;wm@%_JT-ZSZl+Og zG)`VnHV%XazuX6& zK}X%kqsV4M@OVe}CG@FX)oh4OSKq=*jf18 zjO;B{tA3}a^X19lH`?m3*VS}1vnnxcuks?diGhKbda`iY9h zyJ+AEbQ*PXz%Qn_Sc1*Uo0Sl{=foSsA`k&_){`N9(GI-{hkU|+&l05;NFRLU|M?c= zL5W0;kwHl|BlE+ZZAf znt5LH%1t_f-KH~}<6_PgErf0T!9#R@&sqpEvkPMvA*LoQvh~A>YcbL158;J<1>1Ho zHX%vr5usSPcn@$lt)9yRJ$yD8=ihoB@5(*E#?)qKSc{^Fj?XvwTQwYk%kN{XVli5gd1>9))a`RL{Ttp* zsA{{)UE_!O62mUH6E}SemRO`ma0vo9saAVl%_{`RWI_*tMBp*h{|@eGKlf?a_T9x1!}q$!4%u2CDNH>sVTv zCp4oLUt3$xSu=-;@7)i2nln4eee&4HTM0No7k3vide%rkVuY!7UD>4|dFU@4)7Fa^ z`VcZt!luHC&Q#(QzTD#!`9@Og5!9_h*uu?jX{N1&{E&<3JGanv7pDK_@T5_A=-JkE z&pOb~$O>bk&6c;!J}CNi2JUBpHhsM35%8vOd?(!5)^jQmg}o)uovV3E-s+OvfOQU0 zoT0JmOPf)})WlCPz)*cMyX(pe+T8oC>pje%Pl3AT_aU~Bg`2Tk_q-R}Ga=-90`P~= zPGt$~*E)%O`-gX9PxWJ-4Eo4av@*EiDp60=SM~S9zC1g+V>d}|?${k-osGbRez*Ir zlONen!RFN6B4cvSybX#CZGdBu6M2oRqi_8`pWuCf(ur=G&^v)fYqG*G+{QaHD&Gtg$7@th4gLS(@?6txj ztvM8@d=bj*f+M>03Y~Gv&M#D@4BCvir~*9o>kc>)pwA% z1aZ9oHISF7)^PgdS?ws=TOmtfV%+veW0bBFUH z#Cb^g5UrjM2L7I=c%$$Gk&U_y_<3iFP{@$zJ(3gma8Jw$J@mCOL;Y3Ri1qkGi}$wh z3HB?#AsGU8-OcXh5TIG}Tq?KZ9v=AJ2Y5ekxChs%$HougujcI=XR|)wS@_clAEwKm;PR&)jxS!?G9K?3xRkl0ld;Xeh4DGnlb97YgePCW4SoBLQ@D^T0NMx?bLcvX$$WD>zha7T zjtC|3VLtM~7T1(QJ{oRUb3~M}oSr2zQ&&?{(;}Tg(J2at_9fQ-liR=@l4Skps)Wa(Fa>e_+{O9nXqBBn~WN|FSdoUoS zVPrq?fw-DsNNYh9m2&v+ni6>Zm%d zuLN%j9Zr>h5dJhTj9?-Y#0>Ks$pPUJXyss_vq)eh&`E0TBozT60jDGXol4s>od~3P zhSkZtnS2UDCfmbRiEj%7y*tJyBuFVa15bvqoNk8rc3iYwqDu9a=3sIsR@MHz3?x(B ztqiMI^^5c7Nj^smsF!>|Wz%3XHFn7K#A1Y)M6NdG1(YTd^2jol69n_yi* z3~i~D-jR4Y3;NwC3V%IUsn*v{tFjUu@zY{eeFpo~PxVH?4J4d8c!Q2w5UTq;;pe0FyGor=ae*u(PT)okp~HS8L60WT&Sdp#W%Bv#*A@az-6Hi0lq_ueujpu3u8-Uno%BI zY5JJ8Z#A8cA~@4OduD|a#lDCIC^+J+jxpj!KG!h6AF~dJL1aQ0MGl=AG~-VjOMU)| zCGD5!cIHI@+#wE4-{?EGyfV6cM(fDk2n96zQly`G= z+#)MWt*d81j~mj329&tj1IO#xOpgr&U>td_bt&dZObwdr9?UpOE{au**_INYhxR2Q zSPf(ALF7`d^wyk6l(OW>vDd*?S#0`4c4U4^Afivp>_#gy^lBvX&-x*5GvF`hBIcig z9UWgJrAg`SZ>3MqQ)gz6(=4^^H`cB>+-(AouRz_`NmX&~KGmJ$N9lT>dZ^KW1!Nd#mhFw|2uak=0$*s7coymJ^H&~t~gzqP`AlvLj4B@UC9-F>BV88R@MP!D3*PA%i z`wuM~@VDbenm_ZSoxY*v+j$|axs8eKUs5=0ETc^i1B|dMa67OmJRFm$c}adosE%I> zMMfA6RN?mZee$f)(-S^?Y^pgHc$%I(=Tah|fE>>Or3X0VCef#Q$IH&LI4~zxDq))4 zJcy*M&3JZU**Ikj%d7)RyYfT=D3@F`yV7+%;R;ppb5!HLCMCHn9KCcLa2GYTgt4p( z`vi^X^RHk1(eF4YlG{tY9EUBFAGF&2iRzDZor-W}(JF_eaM8C#oB5cNpM&-_zyTAip~ImJD&gUzd~LPiN`> zoUY#vSq-i99UY?;ByDH-5wh!NLU<%r>f|(Z_D%r011#l0%|8k_;CIIXqlQK^+c!A7 zRE}{WJ(0oL32b-5Z;BH3!wZW?K=F+pk9%#fb2Go(JPybLxIw{}>-DTLty1@RgGEjR zqnL#HpRjPlNVJrP!ldvLUJziq$an0lg%QEZg7O^M(N23J(xm%iFuLth;x_9SHuFRf z+x(P(Un7BIJ?c~7N@Ur3miCxFc#ncMQ-RI47>#7Bo_~olsRZZ zj~GMGjw{st!6f$M5~t1MiBjKw{y-;}jiP4x27aD?XIKkH9?X~@U6MK!i$h>F5l%h{ z|BU&g&s8fNlo|EOouZU=b-xBoFrwk=PRQdnbDu@IXMq2bvN+W;h66IptvimPt%CW$ zh0J|g3u0=XXIhu$ceLy+Mfc)q-pnbz8lq$#vHSztTloT*1KuApSGI%Y)kwITmhn}# z)-LR_3SPJpHT;SXXVD5b4_w!Y>esPFy6G|`5OpBU-*zz{f(Gh1Zzj?OiZS*RW+m1_t72wvVXkTad*laU?@z_w$~ zm}a|STk!7BJZ%@fb?I-u`m1wMV^uMPd$S|Jyv@$P&+~sTHHtr%+J9u@f7MvRhzt-T zMzHM1Q}heE^}dxF`|a^w)B_A@IS4_98b(m67);Yq4l^%SbUr_LV=Ku40y?9co6Hy9 zla1S}AJ4#@h;o|dZbK1z}2~Y+4k^mvu(k(_^>qF z;n*hXeLj0<7JC>nhL^sR6E=L=o4g;CJfN}X-!8XSETdcPf~U6dA>HoKDV2*oKeYD8 zaugSce&ryy%7^jSE}J9_t?k-^x1U^302r3`B+qSj?M&t4GFZHD}AYIZ##*P+mG{16J?j z^PfBkdOM^++=CeVl!d&AgucZ@A8;%{lK765^gDS74KOnIVe_NKWvYx)j*E>O$T;ZO zf3%mkha5?8|14HzAnl+%W~-;@AbDur7qA^e@L{HkXJ(!KomBW|9vze32*nuqPb2+* zac=zcJo2yc4vyo6>gGoX-snBBP(rx?Q4!xUAXl?Q{c;YHVWbU{fp4(AMZ@D4ip1XA z51|1AY|F=ocjdNz3ZR0)%mE`9f~cQw^bOseu0RlBq=sZvdm^?^*^XABFT=^OQxaRN zWh3*uY4Em$ssH3Rv^`2{B%Qr-g!o-eTIBS3rtfLW!W6Eiw2)s#9^2_G$-ADn9yTFo zT%fzReIxPw_0kX1a@5$mM9>*pz)g?@I>s5@0N-=rPk^H$Srei(pt!bK-%|_R(PFuiut#l0T>F-Qi=X?_l(cW$1T=|I2FjUxa^~kLZlu?D~`}6=(QS zcvn;@tj+kT0`67BP%CZaz2py~M(gU>!hn7BQfiX;7iU@eE;jBxpAcUVIu6$Aj3tym z=VW?uw2-?_tb3lGZa*&A(gZBPl+{OD*pFyXs!9rjspw6n@+`qL!OVYKL6QgfjIE;c zStW8LB7&i?GI?xUB~O786WJ$V^R@G0>OBtUj#5@Q8qIJZWS9fV0-KBq@JORB(1wzVFcR0} zCRbP9OjU7uqR}8wI$Pbx=2|(!zX4ANSvR;mN4iR@KI*KG7uw<=R<=b@rLibd> zBkxFd%&U)o{j9B}ZZbIv4_c8M6J(>f0z4%iPiTtv`D5(!A|d>78*)2S>(fGuodItd z)^uV8?LuX^_7=2xqB!Kmm%cSJ!CTjDCE-()=a^7qx-yU2bIzXGoF3z7kRtjd5dC^)Af|dSh*88DBpi|9`T>qeBL<-jc)E8mx{yZ)AhQiLSkE!he1P6biK9VmVdQNoE(80Op#T5Q z6AMHA6IE^76*d%a6~8BNJ}&wcBXVghTj1^a9-zf~{cn_?ctPr%PHOVRqYKwygkK-& zgok7@;T5$fPYB@(?*+fF_wp%|y+3@Ms^$Dd6 zhZo1m!fTL?g&S&F530+*H}bXhtxli04jK0sV}<{&B||yE$;w=Yw#Ae~{R!})p#z=maSnCI*~oSP_pz7EbM;GJAerW_0;VO%JxL(a)P}GpISXNw!+4s- z9~JacBzPRHC^V^yv#O*E{7H#pcf}}2mm|V{!Gl!)Ln&d0EG1L*x|F^Rl=bkY?W={hWgGaZ zQfRJrZ`;Y;2E4r31)#lQnmTkpGr`0scVCjVDI@jC((!2j9)`!_=O+vOkB%U@sR z-46V#{q4P}{5u}sF8=`Z+rIUE;r|u;-9Y!N*X7+n_ji!Kapxbf|JlC&4*hPH`Blk% zH_QATNpDH|1N49PK)-{&i@?9iAMYaY-+_qnN6`P-V*U>QuA%%Y7rbjIe+MJ(AL0Lp zqVj8^-}ivO?hfA@w7)|S?~lm84dP#o@$cZjZb;rYn19Cz!5_i@lj{E!_1D(^pLJJH z^heZx*2e#e{cA7$zB%|ix`_XX{XfU?zxe-|e7~>r?;Z8uas2k{AByk2D*oMH|IH=u zh`;s}{~SO%(*HNaU;6D|2k;&IR}%XtxXRmj{=dBLf56|G6gf%Ix48=d0RQ#{1_}Tm I@K+`Of52({3;+NC literal 0 HcmV?d00001 From f0a812ded571cf37db1051ccb9fe63fc6687e6c1 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Thu, 26 Nov 2020 01:00:37 +0000 Subject: [PATCH 31/42] made provision to send long bytes in getCertificateChain --- .../com/android/javacard/keymaster/KMKeymasterApplet.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index e6f0e55c..b61c25f4 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -602,7 +602,10 @@ private void processGetCertChainCmd(APDU apdu) { seProvider.readCertificateChain(buffer, (short) (bufferStartOffset + 2)); // Encode cert chain. encoder.encodeCertChain(buffer, bufferStartOffset, bufferLength); - sendOutgoing(apdu); + // Send data + apdu.setOutgoing(); + apdu.setOutgoingLength(bufferLength); + apdu.sendBytesLong(buffer, bufferStartOffset, bufferLength); } From 61db4640b86ad443c4c8519892de6aa85bebcfa4 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Thu, 26 Nov 2020 01:01:50 +0000 Subject: [PATCH 32/42] Removed KMKeymasterStore.java file --- .../com/android/javacard/keymaster/KMKeymasterStore.java | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterStore.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterStore.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterStore.java deleted file mode 100644 index ed9286f6..00000000 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterStore.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.android.javacard.keymaster; - -public interface KMKeymasterStore { - short getMasterKeySecret(byte[] buf, short start); - void createDocument(byte documentId, byte[]buf, short start, short len); - void updateData(byte documentId, short keyId, byte[]buf, short start, short len); - short getData(byte documentId, short keyId, byte[] buf, short start); - short getDocument(byte documentId, byte[] buf, short start); -} From 34c5c2cf5a5c95d4dc8f1ce11b7f2d2b42d35769 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Thu, 26 Nov 2020 18:44:31 +0000 Subject: [PATCH 33/42] Added vendorPatchLevel and BootPatchLevel to SetBootParams Included vendorPatchLevel and bootPatchLevel in KeyCharateristics. Added check for vendorPatchLevel and bootPatchLevel in upgradeKeyCmd --- .../keymaster/KMAttestationCertImpl.java | 13 +- .../javacard/keymaster/KMKeyParameters.java | 11 +- .../javacard/keymaster/KMKeymasterApplet.java | 124 +++++++++++------- .../javacard/keymaster/KMRepository.java | 64 +++++++-- 4 files changed, 137 insertions(+), 75 deletions(-) diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java index 401cfc18..0e0335c9 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -478,6 +478,7 @@ private static void pushKeyDescription() { pushSequenceHeader((short) (last - stackPtr)); } + //TODO refactor following method private static void pushSWParams() { short last = stackPtr; // ATTESTATION_APPLICATION_ID 709 is softwareEnforced. @@ -487,27 +488,21 @@ private static void pushSWParams() { }; byte index = 0; do { - /* - if(tagIds[index] == KMType.ATTESTATION_APPLICATION_ID) { - pushAttIds(tagIds[index]); - continue; - } - */ pushParams(swParams, swParamsIndex, tagIds[index]); } while (++index < tagIds.length); pushSequenceHeader((short) (last - stackPtr)); } + //TODO refactor following method private static void pushHWParams() { short last = stackPtr; - // Attestation ids are not included. As per VTS attestation ids are not supported currenlty. + // Attestation IDs are not included. As per VTS Attestation IDs are not supported currently. short[] tagIds = { - 706, 705, 704, 703, 702, 701, 601, 600, 509, 508, 507, 506, 505, 504, 503, 402, 401, 400, 303, + 719, 718, 706, 705, 704, 703, 702, 701, 601, 600, 509, 508, 507, 506, 505, 504, 503, 402, 401, 400, 303, 200, 10, 6, 5, 3, 2, 1 }; byte index = 0; do { - // if(pushAttIds(tagIds[index])) continue; if (tagIds[index] == KMType.ROOT_OF_TRUST) { pushRoT(); continue; diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java index 64fa3db2..ae759ffc 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java @@ -102,8 +102,9 @@ public short findTag(short tagType, short tagKey){ } // KDF, ECIES_SINGLE_HASH_MODE missing from types.hal - public static short makeHwEnforced( - short keyParamsPtr, byte origin, short osVersionObjPtr, short osPatchObjPtr, byte[] scratchPad) { + public static short makeHwEnforced(short keyParamsPtr, byte origin, + short osVersionObjPtr, short osPatchObjPtr, short vendorPatchObjPtr, + short bootPatchObjPtr, byte[] scratchPad) { final short[] hwEnforcedTagArr = { // HW Enforced KMType.ENUM_TAG, KMType.ORIGIN, @@ -166,6 +167,12 @@ public static short makeHwEnforced( short osPatchTag = KMIntegerTag.instance(KMType.UINT_TAG, KMType.OS_PATCH_LEVEL, osPatchObjPtr); Util.setShort(scratchPad, arrInd, osPatchTag); arrInd += 2; + short vendorPatchTag = KMIntegerTag.instance(KMType.UINT_TAG, KMType.VENDOR_PATCH_LEVEL, vendorPatchObjPtr); + Util.setShort(scratchPad, arrInd, vendorPatchTag); + arrInd += 2; + short bootPatchTag = KMIntegerTag.instance(KMType.UINT_TAG, KMType.BOOT_PATCH_LEVEL, bootPatchObjPtr); + Util.setShort(scratchPad, arrInd, bootPatchTag); + arrInd += 2; return createKeyParameters(scratchPad, (short) (arrInd / 2)); } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index b61c25f4..2bfcef59 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -1052,7 +1052,6 @@ private void processUpgradeKeyCmd(APDU apdu) { // parse existing key blob parseEncryptedKeyBlob(scratchPad); // validate characteristics to be upgraded. - // TODO currently only os version and os patch level are upgraded. tmpVariables[0] = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.OS_VERSION, data[HW_PARAMETERS]); tmpVariables[0] = KMIntegerTag.cast(tmpVariables[0]).getValue(); @@ -1079,6 +1078,33 @@ private void processUpgradeKeyCmd(APDU apdu) { tmpVariables[5] = KMError.INVALID_ARGUMENT; } } + //Compare vendor patch levels + tmpVariables[1] = + KMKeyParameters.findTag(KMType.UINT_TAG, KMType.VENDOR_PATCH_LEVEL, data[HW_PARAMETERS]); + tmpVariables[1] = KMIntegerTag.cast(tmpVariables[1]).getValue(); + tmpVariables[2] = repository.getVendorPatchLevel(); + if (tmpVariables[1] != KMType.INVALID_VALUE) { + // The key characteristics should have had vendor patch level < vendor patch level stored in javacard + // then only upgrade is allowed. + if (KMInteger.compare(tmpVariables[1], tmpVariables[2]) != -1) { + // Key Should not be upgraded, but error code should be OK, As per VTS. + tmpVariables[5] = KMError.INVALID_ARGUMENT; + } + } + //Compare boot patch levels + tmpVariables[1] = + KMKeyParameters.findTag(KMType.UINT_TAG, KMType.BOOT_PATCH_LEVEL, data[HW_PARAMETERS]); + tmpVariables[1] = KMIntegerTag.cast(tmpVariables[1]).getValue(); + tmpVariables[2] = repository.getBootPatchLevel(); + if (tmpVariables[1] != KMType.INVALID_VALUE) { + // The key characteristics should have had boot patch level < boot patch level stored in javacard + // then only upgrade is allowed. + if (KMInteger.compare(tmpVariables[1], tmpVariables[2]) != -1) { + // Key Should not be upgraded, but error code should be OK, As per VTS. + tmpVariables[5] = KMError.INVALID_ARGUMENT; + } + } + boolean blobPersisted = false; if (tmpVariables[5] != KMError.INVALID_ARGUMENT) { if (repository.validateAuthTag(data[AUTH_TAG])) { @@ -3195,26 +3221,32 @@ private void processSetBootParamsCmd(APDU apdu) { // Argument 2 OS Patch level // short osPatchExp = KMIntegerTag.exp(KMType.UINT_TAG); tmpVariables[1] = KMInteger.exp(); - // Argument 3 Verified Boot Key + // Argument 3 Vendor Patch level + tmpVariables[2] = KMInteger.exp(); + // Argument 4 Boot Patch level + tmpVariables[3] = KMInteger.exp(); + // Argument 5 Verified Boot Key // short bootKeyExp = KMByteBlob.exp(); - tmpVariables[2] = KMByteBlob.exp(); - // Argument 4 Verified Boot Hash + tmpVariables[4] = KMByteBlob.exp(); + // Argument 6 Verified Boot Hash // short bootHashExp = KMByteBlob.exp(); - tmpVariables[3] = KMByteBlob.exp(); - // Argument 5 Verified Boot State + tmpVariables[5] = KMByteBlob.exp(); + // Argument 7 Verified Boot State // short bootStateExp = KMEnum.instance(KMType.VERIFIED_BOOT_STATE); - tmpVariables[4] = KMEnum.instance(KMType.VERIFIED_BOOT_STATE); - // Argument 6 Device Locked + tmpVariables[6] = KMEnum.instance(KMType.VERIFIED_BOOT_STATE); + // Argument 8 Device Locked // short deviceLockedExp = KMEnum.instance(KMType.DEVICE_LOCKED); - tmpVariables[5] = KMEnum.instance(KMType.DEVICE_LOCKED); + tmpVariables[7] = KMEnum.instance(KMType.DEVICE_LOCKED); // Array of expected arguments - short argsProto = KMArray.instance((short) 6); + short argsProto = KMArray.instance((short) 8); KMArray.cast(argsProto).add((short) 0, tmpVariables[0]); KMArray.cast(argsProto).add((short) 1, tmpVariables[1]); KMArray.cast(argsProto).add((short) 2, tmpVariables[2]); KMArray.cast(argsProto).add((short) 3, tmpVariables[3]); KMArray.cast(argsProto).add((short) 4, tmpVariables[4]); KMArray.cast(argsProto).add((short) 5, tmpVariables[5]); + KMArray.cast(argsProto).add((short) 6, tmpVariables[6]); + KMArray.cast(argsProto).add((short) 7, tmpVariables[7]); // Decode the arguments // System.out.println("Process boot params buffer: "+byteArrayToHexString(buffer)); short args = decoder.decode(argsProto, buffer, bufferStartOffset, bufferLength); @@ -3222,22 +3254,25 @@ private void processSetBootParamsCmd(APDU apdu) { tmpVariables[0] = KMArray.cast(args).get((short) 0); // short osPatchTagPtr = KMArray.cast(args).get((short) 1); tmpVariables[1] = KMArray.cast(args).get((short) 1); - // short verifiedBootKeyPtr = KMArray.cast(args).get((short) 2); + // short vendorPatchTagPtr = KMArray.cast(args).get((short) 2); tmpVariables[2] = KMArray.cast(args).get((short) 2); - // short verifiedBootHashPtr = KMArray.cast(args).get((short) 3); + // short BootPatchTagPtr = KMArray.cast(args).get((short) 3); tmpVariables[3] = KMArray.cast(args).get((short) 3); - // short verifiedBootStatePtr = KMArray.cast(args).get((short) 4); + // short verifiedBootKeyPtr = KMArray.cast(args).get((short) 4); tmpVariables[4] = KMArray.cast(args).get((short) 4); - // short deviceLockedPtr = KMArray.cast(args).get((short) 5); + // short verifiedBootHashPtr = KMArray.cast(args).get((short) 5); tmpVariables[5] = KMArray.cast(args).get((short) 5); - if (KMByteBlob.cast(tmpVariables[2]).length() > KMRepository.BOOT_KEY_MAX_SIZE) { + // short verifiedBootStatePtr = KMArray.cast(args).get((short) 6); + tmpVariables[6] = KMArray.cast(args).get((short) 6); + // short deviceLockedPtr = KMArray.cast(args).get((short) 7); + tmpVariables[7] = KMArray.cast(args).get((short) 7); + if (KMByteBlob.cast(tmpVariables[4]).length() > KMRepository.BOOT_KEY_MAX_SIZE) { KMException.throwIt(KMError.INVALID_ARGUMENT); } - if (KMByteBlob.cast(tmpVariables[3]).length() > KMRepository.BOOT_HASH_MAX_SIZE) { + if (KMByteBlob.cast(tmpVariables[5]).length() > KMRepository.BOOT_HASH_MAX_SIZE) { KMException.throwIt(KMError.INVALID_ARGUMENT); } - // Begin transaction - // JCSystem.beginTransaction(); + repository.setOsVersion( KMInteger.cast(tmpVariables[0]).getBuffer(), KMInteger.cast(tmpVariables[0]).getStartOff(), @@ -3246,46 +3281,31 @@ private void processSetBootParamsCmd(APDU apdu) { KMInteger.cast(tmpVariables[1]).getBuffer(), KMInteger.cast(tmpVariables[1]).getStartOff(), KMInteger.cast(tmpVariables[1]).length()); - // KMInteger.cast(tmpVariables[0]).value(repository.osVersion, (short) 0); - // KMInteger.cast(tmpVariables[1]).value(repository.osPatch, (short) 0); - // KMInteger.cast(valPtr).getValue(repository.osVersion, (short) 0, (short) 4); - // valPtr = KMIntegerTag.cast(tmpVariables[1]).getValue(); - // KMInteger.cast(valPtr).getValue(repository.osPatch, (short) 0, (short) 4); + repository.setVendorPatchLevel( + KMInteger.cast(tmpVariables[2]).getBuffer(), + KMInteger.cast(tmpVariables[2]).getStartOff(), + KMInteger.cast(tmpVariables[2]).length()); + + repository.setBootPatchLevel( + KMInteger.cast(tmpVariables[3]).getBuffer(), + KMInteger.cast(tmpVariables[3]).getStartOff(), + KMInteger.cast(tmpVariables[3]).length()); - // repository.actualBootKeyLength = KMByteBlob.cast(tmpVariables[2]).length(); - // KMByteBlob.cast(tmpVariables[2]) - // .getValue(repository.verifiedBootKey, (short) 0, repository.actualBootKeyLength); repository.setVerifiedBootKey( - KMByteBlob.cast(tmpVariables[2]).getBuffer(), - KMByteBlob.cast(tmpVariables[2]).getStartOff(), - KMByteBlob.cast(tmpVariables[2]).length()); + KMByteBlob.cast(tmpVariables[4]).getBuffer(), + KMByteBlob.cast(tmpVariables[4]).getStartOff(), + KMByteBlob.cast(tmpVariables[4]).length()); - // repository.actualBootHashLength = KMByteBlob.cast(tmpVariables[3]).length(); - // KMByteBlob.cast(tmpVariables[3]) - // .getValue(repository.verifiedBootHash, (short) 0, repository.actualBootHashLength); repository.setVerifiedBootHash( - KMByteBlob.cast(tmpVariables[3]).getBuffer(), - KMByteBlob.cast(tmpVariables[3]).getStartOff(), - KMByteBlob.cast(tmpVariables[3]).length()); + KMByteBlob.cast(tmpVariables[5]).getBuffer(), + KMByteBlob.cast(tmpVariables[5]).getStartOff(), + KMByteBlob.cast(tmpVariables[5]).length()); - byte enumVal = KMEnum.cast(tmpVariables[4]).getVal(); + byte enumVal = KMEnum.cast(tmpVariables[6]).getVal(); repository.setBootState(enumVal); - /* - if (enumVal == KMTag.SELF_SIGNED_BOOT) { - repository.selfSignedBootFlag = true; - repository.verifiedBootFlag = false; - } else if(enumVal == KMType.VERIFIED_BOOT) { - repository.selfSignedBootFlag = false; - repository.verifiedBootFlag = true; - }else { - repository.selfSignedBootFlag = false; - repository.verifiedBootFlag = false; - } - */ - enumVal = KMEnum.cast(tmpVariables[5]).getVal(); - // repository.deviceLockedFlag = (enumVal == KMType.DEVICE_LOCKED_TRUE); + enumVal = KMEnum.cast(tmpVariables[7]).getVal(); repository.setDeviceLock(enumVal == KMType.DEVICE_LOCKED_TRUE); // Clear the Computed SharedHmac and Hmac nonce from persistent memory. @@ -3664,12 +3684,16 @@ private void checkVersionAndPatchLevel(byte[] scratchPad) { private static void makeKeyCharacteristics(byte[] scratchPad) { tmpVariables[0] = repository.getOsPatch(); tmpVariables[1] = repository.getOsVersion(); + tmpVariables[2] = repository.getVendorPatchLevel(); + tmpVariables[3] = repository.getBootPatchLevel(); data[HW_PARAMETERS] = KMKeyParameters.makeHwEnforced( data[KEY_PARAMETERS], (byte) data[ORIGIN], tmpVariables[1], tmpVariables[0], + tmpVariables[2], + tmpVariables[3], scratchPad); data[SW_PARAMETERS] = KMKeyParameters.makeSwEnforced(data[KEY_PARAMETERS], scratchPad); data[KEY_CHARACTERISTICS] = KMKeyCharacteristics.instance(); diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java index dcc34f43..fb717985 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java @@ -29,7 +29,7 @@ */ public class KMRepository implements KMUpgradable { // Data table configuration - public static final short DATA_INDEX_SIZE = 31; + public static final short DATA_INDEX_SIZE = 33; public static final short DATA_INDEX_ENTRY_SIZE = 4; public static final short DATA_MEM_SIZE = 2048; public static final short HEAP_SIZE = 10000; @@ -55,19 +55,21 @@ public class KMRepository implements KMUpgradable { public static final byte CERT_EXPIRY_TIME = 15; public static final byte BOOT_OS_VERSION = 16; public static final byte BOOT_OS_PATCH = 17; - public static final byte BOOT_VERIFIED_BOOT_KEY = 18; - public static final byte BOOT_VERIFIED_BOOT_HASH = 19; - public static final byte BOOT_VERIFIED_BOOT_STATE = 20; - public static final byte BOOT_DEVICE_LOCKED_STATUS = 21; - public static final byte BOOT_DEVICE_LOCKED_TIME = 22; - public static final byte AUTH_TAG_1 = 23; - public static final byte AUTH_TAG_2 = 24; - public static final byte AUTH_TAG_3 = 25; - public static final byte AUTH_TAG_4 = 26; - public static final byte AUTH_TAG_5 = 27; - public static final byte AUTH_TAG_6 = 28; - public static final byte AUTH_TAG_7 = 29; - public static final byte AUTH_TAG_8 = 30; + public static final byte VENDOR_PATCH_LEVEL = 18; + public static final byte BOOT_PATCH_LEVEL = 19; + public static final byte BOOT_VERIFIED_BOOT_KEY = 20; + public static final byte BOOT_VERIFIED_BOOT_HASH = 21; + public static final byte BOOT_VERIFIED_BOOT_STATE = 22; + public static final byte BOOT_DEVICE_LOCKED_STATUS = 23; + public static final byte BOOT_DEVICE_LOCKED_TIME = 24; + public static final byte AUTH_TAG_1 = 25; + public static final byte AUTH_TAG_2 = 26; + public static final byte AUTH_TAG_3 = 27; + public static final byte AUTH_TAG_4 = 28; + public static final byte AUTH_TAG_5 = 29; + public static final byte AUTH_TAG_6 = 30; + public static final byte AUTH_TAG_7 = 31; + public static final byte AUTH_TAG_8 = 32; // Data Item sizes public static final short MASTER_KEY_SIZE = 16; @@ -76,6 +78,8 @@ public class KMRepository implements KMUpgradable { public static final short COMPUTED_HMAC_KEY_SIZE = 32; public static final short OS_VERSION_SIZE = 4; public static final short OS_PATCH_SIZE = 4; + public static final short VENDOR_PATCH_SIZE = 4; + public static final short BOOT_PATCH_SIZE = 4; public static final short DEVICE_LOCK_TS_SIZE = 8; public static final short DEVICE_LOCK_FLAG_SIZE = 1; public static final short BOOT_STATE_SIZE = 1; @@ -551,6 +555,26 @@ public short getOsVersion(){ } } + public short getVendorPatchLevel(){ + short blob = readData(VENDOR_PATCH_LEVEL); + if (blob != 0) { + return KMInteger.uint_32( + KMByteBlob.cast(blob).getBuffer(), KMByteBlob.cast(blob).getStartOff()); + }else{ + return KMInteger.uint_32(zero,(short)0); + } + } + + public short getBootPatchLevel(){ + short blob = readData(BOOT_PATCH_LEVEL); + if (blob != 0) { + return KMInteger.uint_32( + KMByteBlob.cast(blob).getBuffer(), KMByteBlob.cast(blob).getStartOff()); + }else{ + return KMInteger.uint_32(zero,(short)0); + } + } + public short getOsPatch(){ short blob = readData(BOOT_OS_PATCH); if (blob != 0) { @@ -599,6 +623,18 @@ public void setOsVersion(byte[] buf, short start, short len){ writeDataEntry(BOOT_OS_VERSION,buf,start,len); } + public void setVendorPatchLevel(byte[] buf, short start, short len) { + if (len != VENDOR_PATCH_SIZE) + KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + writeDataEntry(VENDOR_PATCH_LEVEL, buf, start, len); + } + + public void setBootPatchLevel(byte[] buf, short start, short len) { + if (len != BOOT_PATCH_SIZE) + KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + writeDataEntry(BOOT_PATCH_LEVEL, buf, start, len); + } + public void setDeviceLock(boolean flag){ short start = alloc(DEVICE_LOCK_FLAG_SIZE); if(flag) (getHeap())[start] = (byte)((getHeap())[start] | 0x01); From 23abfa7b9d030d550670719dad14e5c4d2c7d3d0 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Sat, 28 Nov 2020 18:24:30 +0000 Subject: [PATCH 34/42] Added reclaimable memory and getAvailable memroy functions in Repository class. Modified applet code to use these functions whereever necessary. --- .../javacard/keymaster/KMKeymasterApplet.java | 161 +++++++++++++----- .../javacard/keymaster/KMRepository.java | 35 +++- 2 files changed, 153 insertions(+), 43 deletions(-) diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 2bfcef59..c286d4a2 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -40,7 +40,6 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe private static final byte CLA_ISO7816_NO_SM_NO_CHAN = (byte) 0x80; private static final short KM_HAL_VERSION = (short) 0x4000; private static final short MAX_AUTH_DATA_SIZE = (short) 512; - private static final short MAX_IO_LENGTH = 0x600; // "Keymaster HMAC Verification" - used for HMAC key verification. public static final byte[] sharingCheck = { @@ -209,6 +208,7 @@ protected KMKeymasterApplet() { */ public static void install(byte[] bArray, short bOffset, byte bLength) { new KMKeymasterApplet().register(bArray, (short) (bOffset + 1), bArray[bOffset]); + //new KMKeymasterApplet().register(); } /** @@ -266,40 +266,39 @@ private short mapISOErrorToKMError(short reason) { */ @Override public void process(APDU apdu) { - repository.onProcess(); - // Verify whether applet is in correct state. - if ((keymasterState == KMKeymasterApplet.INIT_STATE) - || (keymasterState == KMKeymasterApplet.ILLEGAL_STATE)) { - ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); - } - // If this is select applet apdu which is selecting this applet then return - if (apdu.isISOInterindustryCLA()) { - if (selectingApplet()) { - return; - } - } - // Read the apdu header and buffer. - byte[] apduBuffer = apdu.getBuffer(); - byte apduClass = apduBuffer[ISO7816.OFFSET_CLA]; - byte apduIns = apduBuffer[ISO7816.OFFSET_INS]; - short P1P2 = Util.getShort(apduBuffer, ISO7816.OFFSET_P1); - buffer = repository.getHeap(); - bufferStartOffset = repository.alloc(MAX_IO_LENGTH); - // Validate APDU Header. - if ((apduClass != CLA_ISO7816_NO_SM_NO_CHAN)) { - ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED); - } - - if (P1P2 != KMKeymasterApplet.KM_HAL_VERSION) { - ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); - } - // Validate whether INS can be supported - if (!(apduIns > INS_BEGIN_KM_CMD && apduIns < INS_END_KM_CMD)) { - ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); - } - // Process the apdu try { + repository.onProcess(); + // Verify whether applet is in correct state. + if ((keymasterState == KMKeymasterApplet.INIT_STATE) + || (keymasterState == KMKeymasterApplet.ILLEGAL_STATE)) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } + // If this is select applet apdu which is selecting this applet then + // return + if (apdu.isISOInterindustryCLA()) { + if (selectingApplet()) { + return; + } + } + // Read the apdu header and buffer. + byte[] apduBuffer = apdu.getBuffer(); + byte apduClass = apduBuffer[ISO7816.OFFSET_CLA]; + byte apduIns = apduBuffer[ISO7816.OFFSET_INS]; + short P1P2 = Util.getShort(apduBuffer, ISO7816.OFFSET_P1); + buffer = repository.getHeap(); + // Validate APDU Header. + if ((apduClass != CLA_ISO7816_NO_SM_NO_CHAN)) { + ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED); + } + if (P1P2 != KMKeymasterApplet.KM_HAL_VERSION) { + ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); + } + // Validate whether INS can be supported + if (!(apduIns > INS_BEGIN_KM_CMD && apduIns < INS_END_KM_CMD)) { + ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); + } + // Process the apdu if (keymasterState == KMKeymasterApplet.IN_PROVISION_STATE) { switch (apduIns) { case INS_PROVISION_ATTESTATION_KEY_CMD: @@ -487,6 +486,9 @@ private void processDeviceLockedCmd(APDU apdu) { KMArray.cast(tmpVariables[0]).add((short) 1, tmpVariables[1]); // Decode the arguments tmpVariables[0] = decoder.decode(tmpVariables[0], buffer, bufferStartOffset, bufferLength); + //reclaim memory + repository.reclaimMemory(bufferLength); + tmpVariables[1] = KMArray.cast(tmpVariables[0]).get((short) 0); tmpVariables[1] = KMInteger.cast(tmpVariables[1]).getByte(); data[VERIFICATION_TOKEN] = KMArray.cast(tmpVariables[0]).get((short) 1); @@ -516,7 +518,8 @@ private void resetData() { } /** Sends a response, may be extended response, as requested by the command. */ public static void sendOutgoing(APDU apdu) { - if (bufferLength > MAX_IO_LENGTH) { + if (((short) (bufferLength + bufferStartOffset)) > ((short) repository + .getHeap().length)) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } // Send data @@ -532,11 +535,9 @@ public static void receiveIncoming(APDU apdu) { short recvLen = apdu.setIncomingAndReceive(); short srcOffset = apdu.getOffsetCdata(); bufferLength = apdu.getIncomingLength(); + bufferStartOffset = repository.allocReclaimableMemory(bufferLength); short index = bufferStartOffset; - // Receive data - if (bufferLength > MAX_IO_LENGTH) { - ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); - } + while (recvLen > 0 && ((short) (index - bufferStartOffset) < bufferLength)) { Util.arrayCopyNonAtomic(srcBuffer, srcOffset, buffer, index, recvLen); index += recvLen; @@ -561,6 +562,8 @@ private void processGetHwInfoCmd(APDU apdu) { KMByteBlob.instance( JavacardKeymasterDevice, (short) 0, (short) JavacardKeymasterDevice.length)); resp.add((short) 2, KMByteBlob.instance(Google, (short) 0, (short) Google.length)); + + bufferStartOffset = repository.allocAvailableMemory(); // Encode the response - actual bufferLength is 86 bufferLength = encoder.encode(respPtr, buffer, bufferStartOffset); // send buffer to master @@ -578,6 +581,10 @@ private void processAddRngEntropyCmd(APDU apdu) { KMArray.cast(argsProto).add((short) 0, KMByteBlob.exp()); // Decode the argument short args = decoder.decode(argsProto, buffer, bufferStartOffset, bufferLength); + //reclaim memory + repository.reclaimMemory(bufferLength); + + // Process KMByteBlob blob = KMByteBlob.cast(KMArray.cast(args).get((short) 0)); // Maximum 2KiB of seed is allowed. @@ -602,10 +609,7 @@ private void processGetCertChainCmd(APDU apdu) { seProvider.readCertificateChain(buffer, (short) (bufferStartOffset + 2)); // Encode cert chain. encoder.encodeCertChain(buffer, bufferStartOffset, bufferLength); - // Send data - apdu.setOutgoing(); - apdu.setOutgoingLength(bufferLength); - apdu.sendBytesLong(buffer, bufferStartOffset, bufferLength); + sendOutgoing(apdu); } @@ -619,6 +623,9 @@ private void processProvisionAttestationCertParams(APDU apdu) { KMArray.cast(argsProto).add((short) 2, blob); // Cert - Auth Key Id // Decode the argument. short args = decoder.decode(argsProto, buffer, bufferStartOffset, bufferLength); + //reclaim memory + repository.reclaimMemory(bufferLength); + // save issuer - DER Encoded tmpVariables[0] = KMArray.cast(args).get((short) 0); @@ -647,6 +654,7 @@ private void processProvisionAttestationCertChainCmd(APDU apdu) { short recvLen = apdu.setIncomingAndReceive(); short srcOffset = apdu.getOffsetCdata(); bufferLength = apdu.getIncomingLength(); + bufferStartOffset = repository.alloc(bufferLength); short bytesRead = 0; Util.arrayCopyNonAtomic(srcBuffer, srcOffset, buffer, bufferStartOffset, recvLen); @@ -682,6 +690,9 @@ private void processProvisionAttestationKey(APDU apdu) { // Decode the argument short args = decoder.decode(argsProto, buffer, bufferStartOffset, bufferLength); + //reclaim memory + repository.reclaimMemory(bufferLength); + // key params should have os patch, os version and verified root of trust data[KEY_PARAMETERS] = KMArray.cast(args).get((short) 0); tmpVariables[0] = KMArray.cast(args).get((short) 1); @@ -735,6 +746,9 @@ private void processProvisionAttestIdsCmd(APDU apdu) { KMArray.cast(argsProto).add((short) 0, keyparams); // Decode the argument. short args = decoder.decode(argsProto, buffer, bufferStartOffset, bufferLength); + //reclaim memory + repository.reclaimMemory(bufferLength); + data[KEY_PARAMETERS] = KMArray.cast(args).get((short) 0); // persist attestation Ids - if any is missing then exception occurs saveAttId(KMType.ATTESTATION_ID_BRAND); @@ -755,6 +769,8 @@ private void processProvisionSharedSecretCmd(APDU apdu) { KMArray.cast(argsProto).add((short) 0, blob); // Decode the argument. short args = decoder.decode(argsProto, buffer, bufferStartOffset, bufferLength); + //reclaim memory + repository.reclaimMemory(bufferLength); tmpVariables[0] = KMArray.cast(args).get((short) 0); if (tmpVariables[0] != KMType.INVALID_VALUE @@ -772,6 +788,8 @@ private void processGetProvisionStatusCmd(APDU apdu) { tmpVariables[0] = KMArray.instance((short) 2); KMArray.cast(tmpVariables[0]).add((short) 0, KMInteger.uint_16(KMError.OK)); KMArray.cast(tmpVariables[0]).add((short) 1, KMInteger.uint_16(provisionStatus)); + + bufferStartOffset = repository.allocAvailableMemory(); bufferLength = encoder.encode(tmpVariables[0], buffer, bufferStartOffset); sendOutgoing(apdu); } @@ -825,6 +843,9 @@ private void processGetKeyCharacteristicsCmd(APDU apdu) { KMArray.cast(tmpVariables[0]).add((short) 2, KMByteBlob.exp()); // Decode the arguments tmpVariables[0] = decoder.decode(tmpVariables[0], buffer, bufferStartOffset, bufferLength); + //reclaim memory + repository.reclaimMemory(bufferLength); + data[KEY_BLOB] = KMArray.cast(tmpVariables[0]).get((short) 0); data[APP_ID] = KMArray.cast(tmpVariables[0]).get((short) 1); data[APP_DATA] = KMArray.cast(tmpVariables[0]).get((short) 2); @@ -842,6 +863,8 @@ private void processGetKeyCharacteristicsCmd(APDU apdu) { tmpVariables[0] = KMArray.instance((short) 2); KMArray.cast(tmpVariables[0]).add((short) 0, KMInteger.uint_16(KMError.OK)); KMArray.cast(tmpVariables[0]).add((short) 1, data[KEY_CHARACTERISTICS]); + + bufferStartOffset = repository.allocAvailableMemory(); // Encode the response bufferLength = encoder.encode(tmpVariables[0], buffer, bufferStartOffset); sendOutgoing(apdu); @@ -857,6 +880,8 @@ private void processGetHmacSharingParamCmd(APDU apdu) { tmpVariables[3] = KMArray.instance((short) 2); KMArray.cast(tmpVariables[3]).add((short) 0, KMInteger.uint_16(KMError.OK)); KMArray.cast(tmpVariables[3]).add((short) 1, tmpVariables[2]); + + bufferStartOffset = repository.allocAvailableMemory(); // Encode the response bufferLength = encoder.encode(tmpVariables[3], buffer, bufferStartOffset); sendOutgoing(apdu); @@ -880,6 +905,9 @@ private void processDeleteKeyCmd(APDU apdu) { KMArray.cast(argsProto).add((short) 0, KMByteBlob.exp()); // Decode the argument short args = decoder.decode(argsProto, buffer, bufferStartOffset, bufferLength); + //reclaim memory + repository.reclaimMemory(bufferLength); + // Process data[KEY_BLOB] = KMArray.cast(args).get((short) 0); tmpVariables[0] = KMByteBlob.cast(data[KEY_BLOB]).getStartOff(); @@ -920,6 +948,9 @@ private void processComputeSharedHmacCmd(APDU apdu) { KMArray.cast(tmpVariables[2]).add((short) 0, tmpVariables[0]); // Vector of hmac params // Decode the arguments tmpVariables[0] = decoder.decode(tmpVariables[2], buffer, bufferStartOffset, bufferLength); + //reclaim memory + repository.reclaimMemory(bufferLength); + data[HMAC_SHARING_PARAMS] = KMArray.cast(tmpVariables[0]).get((short) 0); // Concatenate HMAC Params tmpVariables[0] = KMArray.cast(data[HMAC_SHARING_PARAMS]).length(); // total number of params @@ -1022,6 +1053,8 @@ private void processComputeSharedHmacCmd(APDU apdu) { tmpVariables[0] = KMArray.instance((short) 2); KMArray.cast(tmpVariables[0]).add((short) 0, KMInteger.uint_16(KMError.OK)); KMArray.cast(tmpVariables[0]).add((short) 1, tmpVariables[1]); + + bufferStartOffset = repository.allocAvailableMemory(); // Encode the response bufferLength = encoder.encode(tmpVariables[0], buffer, bufferStartOffset); sendOutgoing(apdu); @@ -1037,6 +1070,9 @@ private void processUpgradeKeyCmd(APDU apdu) { KMArray.cast(tmpVariables[1]).add((short) 1, tmpVariables[2]); // Key Params // Decode the arguments tmpVariables[2] = decoder.decode(tmpVariables[1], buffer, bufferStartOffset, bufferLength); + //reclaim memory + repository.reclaimMemory(bufferLength); + data[KEY_BLOB] = KMArray.cast(tmpVariables[2]).get((short) 0); data[KEY_PARAMETERS] = KMArray.cast(tmpVariables[2]).get((short) 1); tmpVariables[0] = @@ -1125,6 +1161,8 @@ private void processUpgradeKeyCmd(APDU apdu) { tmpVariables[0] = KMArray.instance((short) 2); KMArray.cast(tmpVariables[0]).add((short) 0, KMInteger.uint_16(KMError.OK)); KMArray.cast(tmpVariables[0]).add((short) 1, data[KEY_BLOB]); + + bufferStartOffset = repository.allocAvailableMemory(); // Encode the response bufferLength = encoder.encode(tmpVariables[0], buffer, bufferStartOffset); sendOutgoing(apdu); @@ -1156,6 +1194,8 @@ private void processImportWrappedKeyCmd(APDU apdu) { KMArray.cast(tmpVariables[1]).add((short) 11, KMInteger.exp()); // Biometric Sid // Decode the arguments short args = decoder.decode(tmpVariables[1], buffer, bufferStartOffset, bufferLength); + //reclaim memory + repository.reclaimMemory(bufferLength); // Step -0 - check whether the key format and algorithm supported // read algorithm @@ -1307,6 +1347,9 @@ private void processAttestKeyCmd(APDU apdu) { // Decode the argument short args = decoder.decode(argsProto, buffer, bufferStartOffset, bufferLength); + //reclaim memory + repository.reclaimMemory(bufferLength); + data[KEY_BLOB] = KMArray.cast(args).get((short) 0); data[KEY_PARAMETERS] = KMArray.cast(args).get((short) 1); @@ -1512,6 +1555,9 @@ private void processAbortOperationCmd(APDU apdu) { tmpVariables[1] = KMArray.instance((short) 1); KMArray.cast(tmpVariables[1]).add((short) 0, KMInteger.exp()); tmpVariables[2] = decoder.decode(tmpVariables[1], buffer, bufferStartOffset, bufferLength); + //reclaim memory + repository.reclaimMemory(bufferLength); + data[OP_HANDLE] = KMArray.cast(tmpVariables[2]).get((short) 0); tmpVariables[1] = KMInteger.cast(data[OP_HANDLE]).getShort(); KMOperationState op = repository.findOperation(tmpVariables[1]); @@ -1538,6 +1584,9 @@ private void processFinishOperationCmd(APDU apdu) { KMArray.cast(tmpVariables[1]).add((short) 5, tmpVariables[4]); // Decode the arguments tmpVariables[2] = decoder.decode(tmpVariables[1], buffer, bufferStartOffset, bufferLength); + //reclaim memory + repository.reclaimMemory(bufferLength); + data[OP_HANDLE] = KMArray.cast(tmpVariables[2]).get((short) 0); data[KEY_PARAMETERS] = KMArray.cast(tmpVariables[2]).get((short) 1); data[INPUT_DATA] = KMArray.cast(tmpVariables[2]).get((short) 2); @@ -1579,6 +1628,8 @@ private void processFinishOperationCmd(APDU apdu) { KMArray.cast(tmpVariables[2]).add((short) 1, tmpVariables[1]); KMArray.cast(tmpVariables[2]).add((short) 2, data[OUTPUT_DATA]); + + bufferStartOffset = repository.allocAvailableMemory(); // Encode the response bufferLength = encoder.encode(tmpVariables[2], buffer, bufferStartOffset); sendOutgoing(apdu); @@ -2029,6 +2080,9 @@ private void processUpdateOperationCmd(APDU apdu) { KMArray.cast(tmpVariables[1]).add((short) 4, tmpVariables[4]); // Decode the arguments tmpVariables[2] = decoder.decode(tmpVariables[1], buffer, bufferStartOffset, bufferLength); + //reclaim memory + repository.reclaimMemory(bufferLength); + data[OP_HANDLE] = KMArray.cast(tmpVariables[2]).get((short) 0); data[KEY_PARAMETERS] = KMArray.cast(tmpVariables[2]).get((short) 1); data[INPUT_DATA] = KMArray.cast(tmpVariables[2]).get((short) 2); @@ -2136,6 +2190,8 @@ private void processUpdateOperationCmd(APDU apdu) { KMArray.cast(tmpVariables[2]).add((short) 1, KMInteger.uint_16(tmpVariables[3])); KMArray.cast(tmpVariables[2]).add((short) 2, tmpVariables[1]); KMArray.cast(tmpVariables[2]).add((short) 3, data[OUTPUT_DATA]); + + bufferStartOffset = repository.allocAvailableMemory(); // Encode the response bufferLength = encoder.encode(tmpVariables[2], buffer, bufferStartOffset); sendOutgoing(apdu); @@ -2166,6 +2222,9 @@ private void processBeginOperationCmd(APDU apdu) { KMArray.cast(tmpVariables[1]).add((short) 3, tmpVariables[3]); // Decode the arguments args = decoder.decode(tmpVariables[1], buffer, bufferStartOffset, bufferLength); + //reclaim memory + repository.reclaimMemory(bufferLength); + data[KEY_PARAMETERS] = KMArray.cast(args).get((short) 2); data[KEY_BLOB] = KMArray.cast(args).get((short) 1); // Check for app id and app data. @@ -2235,6 +2294,8 @@ private void processBeginOperationCmd(APDU apdu) { KMArray.cast(tmpVariables[0]).add((short) 0, KMInteger.uint_16(KMError.OK)); KMArray.cast(tmpVariables[0]).add((short) 1, tmpVariables[1]); KMArray.cast(tmpVariables[0]).add((short) 2, data[OP_HANDLE]); + + bufferStartOffset = repository.allocAvailableMemory(); // Encode the response bufferLength = encoder.encode(tmpVariables[0], buffer, bufferStartOffset); sendOutgoing(apdu); @@ -2832,6 +2893,9 @@ private void processImportKeyCmd(APDU apdu) { KMArray.cast(tmpVariables[1]).add((short) 2, KMByteBlob.exp()); // Decode the arguments tmpVariables[2] = decoder.decode(tmpVariables[1], buffer, bufferStartOffset, bufferLength); + //reclaim memory + repository.reclaimMemory(bufferLength); + data[KEY_PARAMETERS] = KMArray.cast(tmpVariables[2]).get((short) 0); tmpVariables[3] = KMArray.cast(tmpVariables[2]).get((short) 1); data[IMPORTED_KEY_BLOB] = KMArray.cast(tmpVariables[2]).get((short) 2); @@ -2901,6 +2965,8 @@ private void importKey(APDU apdu, byte[] scratchPad) { KMArray.cast(tmpVariables[0]).add((short) 0, KMInteger.uint_16(KMError.OK)); KMArray.cast(tmpVariables[0]).add((short) 1, data[KEY_BLOB]); KMArray.cast(tmpVariables[0]).add((short) 2, data[KEY_CHARACTERISTICS]); + + bufferStartOffset = repository.allocAvailableMemory(); // Encode the response bufferLength = encoder.encode(tmpVariables[0], buffer, bufferStartOffset); sendOutgoing(apdu); @@ -3250,6 +3316,9 @@ private void processSetBootParamsCmd(APDU apdu) { // Decode the arguments // System.out.println("Process boot params buffer: "+byteArrayToHexString(buffer)); short args = decoder.decode(argsProto, buffer, bufferStartOffset, bufferLength); + //reclaim memory + repository.reclaimMemory(bufferLength); + // short osVersionTagPtr = KMArray.cast(args).get((short) 0); tmpVariables[0] = KMArray.cast(args).get((short) 0); // short osPatchTagPtr = KMArray.cast(args).get((short) 1); @@ -3329,6 +3398,9 @@ private static void processGenerateKey(APDU apdu) { KMArray.cast(tmpVariables[1]).add((short) 0, tmpVariables[0]); // Decode the argument tmpVariables[2] = decoder.decode(tmpVariables[1], buffer, bufferStartOffset, bufferLength); + //reclaim memory + repository.reclaimMemory(bufferLength); + data[KEY_PARAMETERS] = KMArray.cast(tmpVariables[2]).get((short) 0); // Check if EarlyBootEnded tag is present. tmpVariables[0] = @@ -3400,6 +3472,8 @@ private static void processGenerateKey(APDU apdu) { KMArray.cast(tmpVariables[0]).add((short) 0, KMInteger.uint_16(KMError.OK)); KMArray.cast(tmpVariables[0]).add((short) 1, data[KEY_BLOB]); KMArray.cast(tmpVariables[0]).add((short) 2, data[KEY_CHARACTERISTICS]); + + bufferStartOffset = repository.allocAvailableMemory(); // Encode the response bufferLength = encoder.encode(tmpVariables[0], buffer, bufferStartOffset); @@ -3720,6 +3794,8 @@ private static void createEncryptedKeyBlob(byte[] scratchPad) { KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_AUTH_TAG, data[AUTH_TAG]); KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_NONCE, data[NONCE]); KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_KEYCHAR, data[KEY_CHARACTERISTICS]); + + // allocate reclaimable memory. tmpVariables[0] = repository.alloc((short) 1024); tmpVariables[1] = encoder.encode(data[KEY_BLOB], repository.getHeap(), tmpVariables[0]); data[KEY_BLOB] = KMByteBlob.instance(repository.getHeap(), tmpVariables[0], tmpVariables[1]); @@ -3957,6 +4033,7 @@ private static short deriveKey(byte[] scratchPad) { } private static void sendError(APDU apdu, short err) { + bufferStartOffset = repository.alloc((short) 2); bufferLength = encoder.encodeError(err, buffer, bufferStartOffset, (short) 5); sendOutgoing(apdu); } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java index fb717985..b8dc8b8d 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java @@ -97,6 +97,7 @@ public class KMRepository implements KMUpgradable { private short heapIndex; private byte[] dataTable; private short dataIndex; + private short reclaimIndex; // Singleton instance private static KMRepository repository; @@ -109,6 +110,7 @@ public KMRepository(boolean isUpgrading) { newDataTable(isUpgrading); heap = JCSystem.makeTransientByteArray(HEAP_SIZE, JCSystem.CLEAR_ON_RESET); heapIndex = 0; + reclaimIndex = HEAP_SIZE; operationStateTable = new Object[MAX_OPS]; // create and initialize operation state table. byte index = 0; @@ -252,6 +254,7 @@ public void onProcess() {} public void clean() { Util.arrayFillNonAtomic(heap, (short) 0, heapIndex, (byte) 0); heapIndex = 0; + reclaimIndex = HEAP_SIZE; } public void onDeselect() {} @@ -264,8 +267,38 @@ public short getMasterKeySecret() { return readData(MASTER_KEY); } + // This function uses memory from the back of the heap(transient memory). Call + // reclaimMemory function immediately after the use. + public short allocReclaimableMemory(short length) { + // TODO Verify the below condition (HEAP_SIZE/2) + if ((((short) (reclaimIndex - length)) <= heapIndex) + || (length >= HEAP_SIZE / 2)) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } + reclaimIndex -= length; + return reclaimIndex; + } + + // Reclaims the memory back. + public void reclaimMemory(short length) { + if (reclaimIndex < heapIndex) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } + reclaimIndex += length; + } + + public short allocAvailableMemory() { + if (heapIndex >= heap.length) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } + short index = heapIndex; + heapIndex = (short) heap.length; + return index; + } + public short alloc(short length) { - if (((short) (heapIndex + length)) > heap.length) { + if ((((short) (heapIndex + length)) > heap.length) || + (((short) (heapIndex + length)) > reclaimIndex)) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } heapIndex += length; From 0fe6b2f61e78368a1648616848458b9409c39510 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Sat, 28 Nov 2020 18:29:21 +0000 Subject: [PATCH 35/42] Modified KMFunctionalTest code as per latest provision changes. --- .../android/javacard/keymaster/KMEncoder.java | 2 +- .../javacard/test/KMFunctionalTest.java | 719 +++++++++++++----- 2 files changed, 548 insertions(+), 173 deletions(-) diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMEncoder.java b/Applet/Applet/src/com/android/javacard/keymaster/KMEncoder.java index 273149ee..72f906bf 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMEncoder.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMEncoder.java @@ -343,7 +343,7 @@ private void writeMajorTypeWithLength(byte majorType, short len) { } private void writeBytes(byte[] buf, short start, short len){ - Util.arrayCopy(buf, start, buffer, startOff, len); + Util.arrayCopyNonAtomic(buf, start, buffer, startOff, len); incrementStartOff(len); } private void writeShort(short val){ diff --git a/Applet/Applet/test/com/android/javacard/test/KMFunctionalTest.java b/Applet/Applet/test/com/android/javacard/test/KMFunctionalTest.java index c9eb7c1f..450e7a60 100644 --- a/Applet/Applet/test/com/android/javacard/test/KMFunctionalTest.java +++ b/Applet/Applet/test/com/android/javacard/test/KMFunctionalTest.java @@ -17,7 +17,8 @@ package com.android.javacard.test; import com.android.javacard.keymaster.KMArray; -import com.android.javacard.keymaster.KMBackupStoreApplet; +import com.android.javacard.keymaster.KMAttestationCert; +import com.android.javacard.keymaster.KMAttestationCertImpl; import com.android.javacard.keymaster.KMBoolTag; import com.android.javacard.keymaster.KMByteBlob; import com.android.javacard.keymaster.KMByteTag; @@ -43,22 +44,359 @@ import com.licel.jcardsim.utils.AIDUtil; import javacard.framework.AID; import javacard.framework.Util; + +import java.security.spec.PKCS8EncodedKeySpec; + import javax.smartcardio.CommandAPDU; import javax.smartcardio.ResponseAPDU; import org.junit.Assert; import org.junit.Test; public class KMFunctionalTest { - private static final byte[] X509Issuer = { - 0x30, 0x76, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, - 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0C, 0x0A, 0x43, 0x61, 0x6C, 0x69, 0x66, 0x6F, - 0x72, 0x6E, 0x69, 0x61, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x0C, 0x47, - 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x2C, 0x20, 0x49, 0x6E, 0x63, 0x2E, 0x31, 0x10, 0x30, 0x0E, 0x06, - 0x03, 0x55, 0x04, 0x0B, 0x0C, 0x07, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x31, 0x29, 0x30, - 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x20, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x20, - 0x53, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, - 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x4B, 0x65, 0x79 - }; + private static final byte INS_BEGIN_KM_CMD = 0x00; + private static final byte INS_PROVISION_ATTESTATION_KEY_CMD = INS_BEGIN_KM_CMD + 1; //0x01 + private static final byte INS_PROVISION_ATTESTATION_CERT_CHAIN_CMD = INS_BEGIN_KM_CMD + 2; //0x02 + private static final byte INS_PROVISION_ATTESTATION_CERT_PARAMS_CMD = INS_BEGIN_KM_CMD + 3; //0x03 + private static final byte INS_PROVISION_ATTEST_IDS_CMD = INS_BEGIN_KM_CMD + 4; //0x04 + private static final byte INS_PROVISION_SHARED_SECRET_CMD = INS_BEGIN_KM_CMD + 5; //0x05 + private static final byte INS_SET_BOOT_PARAMS_CMD = INS_BEGIN_KM_CMD + 6; //0x06 + private static final byte INS_LOCK_PROVISIONING_CMD = INS_BEGIN_KM_CMD + 7; //0x07 + private static final byte INS_GET_PROVISION_STATUS_CMD = INS_BEGIN_KM_CMD + 8; //0x08 + // Top 32 commands are reserved for provisioning. + private static final byte INS_END_KM_PROVISION_CMD = 0x20; + + private static final byte INS_GENERATE_KEY_CMD = INS_END_KM_PROVISION_CMD + 1; //0x21 + private static final byte INS_IMPORT_KEY_CMD = INS_END_KM_PROVISION_CMD + 2; //0x22 + private static final byte INS_IMPORT_WRAPPED_KEY_CMD = INS_END_KM_PROVISION_CMD + 3; //0x23 + private static final byte INS_EXPORT_KEY_CMD = INS_END_KM_PROVISION_CMD + 4; //0x24 + private static final byte INS_ATTEST_KEY_CMD = INS_END_KM_PROVISION_CMD + 5; //0x25 + private static final byte INS_UPGRADE_KEY_CMD = INS_END_KM_PROVISION_CMD + 6; //0x26 + private static final byte INS_DELETE_KEY_CMD = INS_END_KM_PROVISION_CMD + 7; //0x27 + private static final byte INS_DELETE_ALL_KEYS_CMD = INS_END_KM_PROVISION_CMD + 8; //0x28 + private static final byte INS_ADD_RNG_ENTROPY_CMD = INS_END_KM_PROVISION_CMD + 9; //0x29 + private static final byte INS_COMPUTE_SHARED_HMAC_CMD = INS_END_KM_PROVISION_CMD + 10; //0x2A + private static final byte INS_DESTROY_ATT_IDS_CMD = INS_END_KM_PROVISION_CMD + 11; //0x2B + private static final byte INS_VERIFY_AUTHORIZATION_CMD = INS_END_KM_PROVISION_CMD + 12; //0x2C + private static final byte INS_GET_HMAC_SHARING_PARAM_CMD = INS_END_KM_PROVISION_CMD + 13; //0x2D + private static final byte INS_GET_KEY_CHARACTERISTICS_CMD = INS_END_KM_PROVISION_CMD + 14; //0x2E + private static final byte INS_GET_HW_INFO_CMD = INS_END_KM_PROVISION_CMD + 15; //0x2F + private static final byte INS_BEGIN_OPERATION_CMD = INS_END_KM_PROVISION_CMD + 16; //0x30 + private static final byte INS_UPDATE_OPERATION_CMD = INS_END_KM_PROVISION_CMD + 17; //0x31 + private static final byte INS_FINISH_OPERATION_CMD = INS_END_KM_PROVISION_CMD + 18; //0x32 + private static final byte INS_ABORT_OPERATION_CMD = INS_END_KM_PROVISION_CMD + 19; //0x33 + private static final byte INS_DEVICE_LOCKED_CMD = INS_END_KM_PROVISION_CMD + 20;//0x34 + private static final byte INS_EARLY_BOOT_ENDED_CMD = INS_END_KM_PROVISION_CMD + 21; //0x35 + private static final byte INS_GET_CERT_CHAIN_CMD = INS_END_KM_PROVISION_CMD + 22; //0x36 + + private static final byte[] kEcPrivKey = { + (byte) 0x21, (byte) 0xe0, (byte) 0x86, (byte) 0x43, (byte) 0x2a, + (byte) 0x15, (byte) 0x19, (byte) 0x84, (byte) 0x59, (byte) 0xcf, + (byte) 0x36, (byte) 0x3a, (byte) 0x50, (byte) 0xfc, (byte) 0x14, + (byte) 0xc9, (byte) 0xda, (byte) 0xad, (byte) 0xf9, (byte) 0x35, + (byte) 0xf5, (byte) 0x27, (byte) 0xc2, (byte) 0xdf, (byte) 0xd7, + (byte) 0x1e, (byte) 0x4d, (byte) 0x6d, (byte) 0xbc, (byte) 0x42, + (byte) 0xe5, (byte) 0x44 }; + private static final byte[] kEcPubKey = { + (byte) 0x04, (byte) 0xeb, (byte) 0x9e, (byte) 0x79, (byte) 0xf8, + (byte) 0x42, (byte) 0x63, (byte) 0x59, (byte) 0xac, (byte) 0xcb, + (byte) 0x2a, (byte) 0x91, (byte) 0x4c, (byte) 0x89, (byte) 0x86, + (byte) 0xcc, (byte) 0x70, (byte) 0xad, (byte) 0x90, (byte) 0x66, + (byte) 0x93, (byte) 0x82, (byte) 0xa9, (byte) 0x73, (byte) 0x26, + (byte) 0x13, (byte) 0xfe, (byte) 0xac, (byte) 0xcb, (byte) 0xf8, + (byte) 0x21, (byte) 0x27, (byte) 0x4c, (byte) 0x21, (byte) 0x74, + (byte) 0x97, (byte) 0x4a, (byte) 0x2a, (byte) 0xfe, (byte) 0xa5, + (byte) 0xb9, (byte) 0x4d, (byte) 0x7f, (byte) 0x66, (byte) 0xd4, + (byte) 0xe0, (byte) 0x65, (byte) 0x10, (byte) 0x66, (byte) 0x35, + (byte) 0xbc, (byte) 0x53, (byte) 0xb7, (byte) 0xa0, (byte) 0xa3, + (byte) 0xa6, (byte) 0x71, (byte) 0x58, (byte) 0x3e, (byte) 0xdb, + (byte) 0x3e, (byte) 0x11, (byte) 0xae, (byte) 0x10, (byte) 0x14 }; + + private static final byte[] kEcAttestCert = { + 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x78, (byte) 0x30, (byte) 0x82, + (byte) 0x02, (byte) 0x1e, (byte) 0xa0, (byte) 0x03, (byte) 0x02, + (byte) 0x01, (byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x10, 0x01, + (byte) 0x30, (byte) 0x0a, (byte) 0x06, (byte) 0x08, (byte) 0x2a, + (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x04, + (byte) 0x03, (byte) 0x02, (byte) 0x30, (byte) 0x81, (byte) 0x98, 0x31, + (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, + (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, + (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x13, (byte) 0x30, 0x11, + (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08, + (byte) 0x0c, (byte) 0x0a, (byte) 0x43, (byte) 0x61, (byte) 0x6c, + (byte) 0x69, (byte) 0x66, (byte) 0x6f, (byte) 0x72, (byte) 0x6e, 0x69, + (byte) 0x61, (byte) 0x31, (byte) 0x16, (byte) 0x30, (byte) 0x14, + (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x07, + (byte) 0x0c, (byte) 0x0d, (byte) 0x4d, (byte) 0x6f, (byte) 0x75, 0x6e, + (byte) 0x74, (byte) 0x61, (byte) 0x69, (byte) 0x6e, (byte) 0x20, + (byte) 0x56, (byte) 0x69, (byte) 0x65, (byte) 0x77, (byte) 0x31, + (byte) 0x15, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x03, 0x55, + (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x0c, (byte) 0x47, + (byte) 0x6f, (byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65, + (byte) 0x2c, (byte) 0x20, (byte) 0x49, (byte) 0x6e, (byte) 0x63, 0x2e, + (byte) 0x31, (byte) 0x10, (byte) 0x30, (byte) 0x0e, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0b, (byte) 0x0c, + (byte) 0x07, (byte) 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, 0x6f, + (byte) 0x69, (byte) 0x64, (byte) 0x31, (byte) 0x33, (byte) 0x30, + (byte) 0x31, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, + (byte) 0x03, (byte) 0x0c, (byte) 0x2a, (byte) 0x41, (byte) 0x6e, 0x64, + (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x20, + (byte) 0x4b, (byte) 0x65, (byte) 0x79, (byte) 0x73, (byte) 0x74, + (byte) 0x6f, (byte) 0x72, (byte) 0x65, (byte) 0x20, (byte) 0x53, 0x6f, + (byte) 0x66, (byte) 0x74, (byte) 0x77, (byte) 0x61, (byte) 0x72, + (byte) 0x65, (byte) 0x20, (byte) 0x41, (byte) 0x74, (byte) 0x74, + (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x61, (byte) 0x74, 0x69, + (byte) 0x6f, (byte) 0x6e, (byte) 0x20, (byte) 0x52, (byte) 0x6f, + (byte) 0x6f, (byte) 0x74, (byte) 0x30, (byte) 0x1e, (byte) 0x17, + (byte) 0x0d, (byte) 0x31, (byte) 0x36, (byte) 0x30, (byte) 0x31, 0x31, + (byte) 0x31, (byte) 0x30, (byte) 0x30, (byte) 0x34, (byte) 0x36, + (byte) 0x30, (byte) 0x39, (byte) 0x5a, (byte) 0x17, (byte) 0x0d, + (byte) 0x32, (byte) 0x36, (byte) 0x30, (byte) 0x31, (byte) 0x30, 0x38, + (byte) 0x30, (byte) 0x30, (byte) 0x34, (byte) 0x36, (byte) 0x30, + (byte) 0x39, (byte) 0x5a, (byte) 0x30, (byte) 0x81, (byte) 0x88, + (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, 0x03, + (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, + (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x13, (byte) 0x30, + (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, 0x08, + (byte) 0x0c, (byte) 0x0a, (byte) 0x43, (byte) 0x61, (byte) 0x6c, + (byte) 0x69, (byte) 0x66, (byte) 0x6f, (byte) 0x72, (byte) 0x6e, + (byte) 0x69, (byte) 0x61, (byte) 0x31, (byte) 0x15, (byte) 0x30, 0x13, + (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, + (byte) 0x0c, (byte) 0x0c, (byte) 0x47, (byte) 0x6f, (byte) 0x6f, + (byte) 0x67, (byte) 0x6c, (byte) 0x65, (byte) 0x2c, (byte) 0x20, 0x49, + (byte) 0x6e, (byte) 0x63, (byte) 0x2e, (byte) 0x31, (byte) 0x10, + (byte) 0x30, (byte) 0x0e, (byte) 0x06, (byte) 0x03, (byte) 0x55, + (byte) 0x04, (byte) 0x0b, (byte) 0x0c, (byte) 0x07, (byte) 0x41, 0x6e, + (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, + (byte) 0x31, (byte) 0x3b, (byte) 0x30, (byte) 0x39, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x0c, 0x32, + (byte) 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, + (byte) 0x69, (byte) 0x64, (byte) 0x20, (byte) 0x4b, (byte) 0x65, + (byte) 0x79, (byte) 0x73, (byte) 0x74, (byte) 0x6f, (byte) 0x72, 0x65, + (byte) 0x20, (byte) 0x53, (byte) 0x6f, (byte) 0x66, (byte) 0x74, + (byte) 0x77, (byte) 0x61, (byte) 0x72, (byte) 0x65, (byte) 0x20, + (byte) 0x41, (byte) 0x74, (byte) 0x74, (byte) 0x65, (byte) 0x73, 0x74, + (byte) 0x61, (byte) 0x74, (byte) 0x69, (byte) 0x6f, (byte) 0x6e, + (byte) 0x20, (byte) 0x49, (byte) 0x6e, (byte) 0x74, (byte) 0x65, + (byte) 0x72, (byte) 0x6d, (byte) 0x65, (byte) 0x64, (byte) 0x69, 0x61, + (byte) 0x74, (byte) 0x65, (byte) 0x30, (byte) 0x59, (byte) 0x30, + (byte) 0x13, (byte) 0x06, (byte) 0x07, (byte) 0x2a, (byte) 0x86, + (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x02, (byte) 0x01, 0x06, + (byte) 0x08, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0xce, + (byte) 0x3d, (byte) 0x03, (byte) 0x01, (byte) 0x07, (byte) 0x03, + (byte) 0x42, (byte) 0x00, (byte) 0x04, (byte) 0xeb, (byte) 0x9e, 0x79, + (byte) 0xf8, (byte) 0x42, (byte) 0x63, (byte) 0x59, (byte) 0xac, + (byte) 0xcb, (byte) 0x2a, (byte) 0x91, (byte) 0x4c, (byte) 0x89, + (byte) 0x86, (byte) 0xcc, (byte) 0x70, (byte) 0xad, (byte) 0x90, 0x66, + (byte) 0x93, (byte) 0x82, (byte) 0xa9, (byte) 0x73, (byte) 0x26, + (byte) 0x13, (byte) 0xfe, (byte) 0xac, (byte) 0xcb, (byte) 0xf8, + (byte) 0x21, (byte) 0x27, (byte) 0x4c, (byte) 0x21, (byte) 0x74, + (byte) 0x97, (byte) 0x4a, (byte) 0x2a, (byte) 0xfe, (byte) 0xa5, + (byte) 0xb9, (byte) 0x4d, (byte) 0x7f, (byte) 0x66, (byte) 0xd4, + (byte) 0xe0, (byte) 0x65, (byte) 0x10, (byte) 0x66, (byte) 0x35, + (byte) 0xbc, 0x53, (byte) 0xb7, (byte) 0xa0, (byte) 0xa3, (byte) 0xa6, + (byte) 0x71, (byte) 0x58, (byte) 0x3e, (byte) 0xdb, (byte) 0x3e, + (byte) 0x11, (byte) 0xae, (byte) 0x10, (byte) 0x14, (byte) 0xa3, + (byte) 0x66, 0x30, (byte) 0x64, (byte) 0x30, (byte) 0x1d, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e, (byte) 0x04, + (byte) 0x16, (byte) 0x04, (byte) 0x14, (byte) 0x3f, (byte) 0xfc, + (byte) 0xac, (byte) 0xd6, (byte) 0x1a, (byte) 0xb1, (byte) 0x3a, + (byte) 0x9e, (byte) 0x81, (byte) 0x20, (byte) 0xb8, (byte) 0xd5, + (byte) 0x25, (byte) 0x1c, (byte) 0xc5, (byte) 0x65, (byte) 0xbb, + (byte) 0x1e, (byte) 0x91, (byte) 0xa9, (byte) 0x30, (byte) 0x1f, + (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x23, + (byte) 0x04, (byte) 0x18, (byte) 0x30, (byte) 0x16, (byte) 0x80, + (byte) 0x14, (byte) 0xc8, (byte) 0xad, (byte) 0xe9, (byte) 0x77, + (byte) 0x4c, (byte) 0x45, (byte) 0xc3, (byte) 0xa3, (byte) 0xcf, + (byte) 0x0d, (byte) 0x16, (byte) 0x10, (byte) 0xe4, (byte) 0x79, + (byte) 0x43, (byte) 0x3a, (byte) 0x21, (byte) 0x5a, 0x30, (byte) 0xcf, + (byte) 0x30, (byte) 0x12, (byte) 0x06, (byte) 0x03, (byte) 0x55, + (byte) 0x1d, (byte) 0x13, (byte) 0x01, (byte) 0x01, (byte) 0xff, + (byte) 0x04, (byte) 0x08, (byte) 0x30, (byte) 0x06, 0x01, (byte) 0x01, + (byte) 0xff, (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x30, + (byte) 0x0e, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, + (byte) 0x0f, (byte) 0x01, (byte) 0x01, (byte) 0xff, 0x04, (byte) 0x04, + (byte) 0x03, (byte) 0x02, (byte) 0x02, (byte) 0x84, (byte) 0x30, + (byte) 0x0a, (byte) 0x06, (byte) 0x08, (byte) 0x2a, (byte) 0x86, + (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x04, 0x03, (byte) 0x02, + (byte) 0x03, (byte) 0x48, (byte) 0x00, (byte) 0x30, (byte) 0x45, + (byte) 0x02, (byte) 0x20, (byte) 0x4b, (byte) 0x8a, (byte) 0x9b, + (byte) 0x7b, (byte) 0xee, (byte) 0x82, (byte) 0xbc, (byte) 0xc0, + (byte) 0x33, (byte) 0x87, (byte) 0xae, (byte) 0x2f, (byte) 0xc0, + (byte) 0x89, (byte) 0x98, (byte) 0xb4, (byte) 0xdd, (byte) 0xc3, + (byte) 0x8d, (byte) 0xab, (byte) 0x27, (byte) 0x2a, (byte) 0x45, + (byte) 0x9f, (byte) 0x69, (byte) 0x0c, (byte) 0xc7, (byte) 0xc3, + (byte) 0x92, (byte) 0xd4, (byte) 0x0f, (byte) 0x8e, (byte) 0x02, + (byte) 0x21, (byte) 0x00, (byte) 0xee, (byte) 0xda, (byte) 0x01, + (byte) 0x5d, (byte) 0xb6, (byte) 0xf4, (byte) 0x32, (byte) 0xe9, + (byte) 0xd4, (byte) 0x84, (byte) 0x3b, (byte) 0x62, (byte) 0x4c, + (byte) 0x94, (byte) 0x04, (byte) 0xef, (byte) 0x3a, (byte) 0x7c, + (byte) 0xcc, (byte) 0xbd, 0x5e, (byte) 0xfb, (byte) 0x22, (byte) 0xbb, + (byte) 0xe7, (byte) 0xfe, (byte) 0xb9, (byte) 0x77, (byte) 0x3f, + (byte) 0x59, (byte) 0x3f, (byte) 0xfb, }; + + private static final byte[] kEcAttestRootCert = { + 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x8b, (byte) 0x30, + (byte) 0x82, (byte) 0x02, (byte) 0x32, (byte) 0xa0, (byte) 0x03, + (byte) 0x02, (byte) 0x01, (byte) 0x02, (byte) 0x02, (byte) 0x09, + (byte) 0x00, (byte) 0xa2, (byte) 0x05, (byte) 0x9e, (byte) 0xd1, + (byte) 0x0e, (byte) 0x43, (byte) 0x5b, (byte) 0x57, (byte) 0x30, + (byte) 0x0a, (byte) 0x06, (byte) 0x08, (byte) 0x2a, (byte) 0x86, + (byte) 0x48, (byte) 0xce, 0x3d, (byte) 0x04, (byte) 0x03, + (byte) 0x02, (byte) 0x30, (byte) 0x81, (byte) 0x98, (byte) 0x31, + (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, + (byte) 0x55, (byte) 0x04, (byte) 0x06, 0x13, (byte) 0x02, + (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x13, (byte) 0x30, + (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, + (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x43, 0x61, + (byte) 0x6c, (byte) 0x69, (byte) 0x66, (byte) 0x6f, (byte) 0x72, + (byte) 0x6e, (byte) 0x69, (byte) 0x61, (byte) 0x31, (byte) 0x16, + (byte) 0x30, (byte) 0x14, (byte) 0x06, (byte) 0x03, (byte) 0x55, + 0x04, (byte) 0x07, (byte) 0x0c, (byte) 0x0d, (byte) 0x4d, + (byte) 0x6f, (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61, + (byte) 0x69, (byte) 0x6e, (byte) 0x20, (byte) 0x56, (byte) 0x69, + (byte) 0x65, 0x77, (byte) 0x31, (byte) 0x15, (byte) 0x30, + (byte) 0x13, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, + (byte) 0x0a, (byte) 0x0c, (byte) 0x0c, (byte) 0x47, (byte) 0x6f, + (byte) 0x6f, (byte) 0x67, 0x6c, (byte) 0x65, (byte) 0x2c, + (byte) 0x20, (byte) 0x49, (byte) 0x6e, (byte) 0x63, (byte) 0x2e, + (byte) 0x31, (byte) 0x10, (byte) 0x30, (byte) 0x0e, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x04, 0x0b, (byte) 0x0c, + (byte) 0x07, (byte) 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, + (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x31, (byte) 0x33, + (byte) 0x30, (byte) 0x31, (byte) 0x06, (byte) 0x03, 0x55, + (byte) 0x04, (byte) 0x03, (byte) 0x0c, (byte) 0x2a, (byte) 0x41, + (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, + (byte) 0x64, (byte) 0x20, (byte) 0x4b, (byte) 0x65, (byte) 0x79, + 0x73, (byte) 0x74, (byte) 0x6f, (byte) 0x72, (byte) 0x65, + (byte) 0x20, (byte) 0x53, (byte) 0x6f, (byte) 0x66, (byte) 0x74, + (byte) 0x77, (byte) 0x61, (byte) 0x72, (byte) 0x65, (byte) 0x20, + (byte) 0x41, 0x74, (byte) 0x74, (byte) 0x65, (byte) 0x73, + (byte) 0x74, (byte) 0x61, (byte) 0x74, (byte) 0x69, (byte) 0x6f, + (byte) 0x6e, (byte) 0x20, (byte) 0x52, (byte) 0x6f, (byte) 0x6f, + (byte) 0x74, (byte) 0x30, 0x1e, (byte) 0x17, (byte) 0x0d, + (byte) 0x31, (byte) 0x36, (byte) 0x30, (byte) 0x31, (byte) 0x31, + (byte) 0x31, (byte) 0x30, (byte) 0x30, (byte) 0x34, (byte) 0x33, + (byte) 0x35, (byte) 0x30, (byte) 0x5a, 0x17, (byte) 0x0d, + (byte) 0x33, (byte) 0x36, (byte) 0x30, (byte) 0x31, (byte) 0x30, + (byte) 0x36, (byte) 0x30, (byte) 0x30, (byte) 0x34, (byte) 0x33, + (byte) 0x35, (byte) 0x30, (byte) 0x5a, (byte) 0x30, (byte) 0x81, + (byte) 0x98, (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, + (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, + (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31, + 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, + (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x0a, + (byte) 0x43, (byte) 0x61, (byte) 0x6c, (byte) 0x69, (byte) 0x66, + (byte) 0x6f, 0x72, (byte) 0x6e, (byte) 0x69, (byte) 0x61, + (byte) 0x31, (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x07, (byte) 0x0c, + (byte) 0x0d, (byte) 0x4d, 0x6f, (byte) 0x75, (byte) 0x6e, + (byte) 0x74, (byte) 0x61, (byte) 0x69, (byte) 0x6e, (byte) 0x20, + (byte) 0x56, (byte) 0x69, (byte) 0x65, (byte) 0x77, (byte) 0x31, + (byte) 0x15, (byte) 0x30, (byte) 0x13, 0x06, (byte) 0x03, + (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x0c, + (byte) 0x47, (byte) 0x6f, (byte) 0x6f, (byte) 0x67, (byte) 0x6c, + (byte) 0x65, (byte) 0x2c, (byte) 0x20, (byte) 0x49, 0x6e, + (byte) 0x63, (byte) 0x2e, (byte) 0x31, (byte) 0x10, (byte) 0x30, + (byte) 0x0e, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, + (byte) 0x0b, (byte) 0x0c, (byte) 0x07, (byte) 0x41, (byte) 0x6e, + 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, + (byte) 0x31, (byte) 0x33, (byte) 0x30, (byte) 0x31, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x0c, + (byte) 0x2a, 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, + (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x20, (byte) 0x4b, + (byte) 0x65, (byte) 0x79, (byte) 0x73, (byte) 0x74, (byte) 0x6f, + (byte) 0x72, (byte) 0x65, 0x20, (byte) 0x53, (byte) 0x6f, + (byte) 0x66, (byte) 0x74, (byte) 0x77, (byte) 0x61, (byte) 0x72, + (byte) 0x65, (byte) 0x20, (byte) 0x41, (byte) 0x74, (byte) 0x74, + (byte) 0x65, (byte) 0x73, (byte) 0x74, 0x61, (byte) 0x74, + (byte) 0x69, (byte) 0x6f, (byte) 0x6e, 0x77, (byte) 0x1f, + (byte) 0x44, (byte) 0x22, (byte) 0x6d, (byte) 0xbd, (byte) 0xb1, + (byte) 0xaf, (byte) 0xfa, (byte) 0x16, (byte) 0xcb, (byte) 0xc7, + (byte) 0xad, (byte) 0xc5, (byte) 0x77, (byte) 0xd2, (byte) 0x20, + (byte) 0x52, (byte) 0x6f, (byte) 0x6f, (byte) 0x74, (byte) 0x30, + (byte) 0x59, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x07, + 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x3d, + (byte) 0x02, (byte) 0x01, (byte) 0x06, (byte) 0x08, (byte) 0x2a, + (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x03, + (byte) 0x01, 0x07, (byte) 0x03, (byte) 0x42, (byte) 0x00, + (byte) 0x04, (byte) 0xee, (byte) 0x5d, (byte) 0x5e, (byte) 0xc7, + (byte) 0xe1, (byte) 0xc0, (byte) 0xdb, (byte) 0x6d, (byte) 0x03, + (byte) 0xa6, (byte) 0x7e, (byte) 0xe6, (byte) 0xb6, (byte) 0x1b, + (byte) 0xec, (byte) 0x4d, (byte) 0x6a, (byte) 0x5d, (byte) 0x6a, + (byte) 0x68, (byte) 0x2e, (byte) 0x0f, (byte) 0xff, (byte) 0x7f, + (byte) 0x49, (byte) 0x0e, (byte) 0x7d, 0x56, (byte) 0x9c, + (byte) 0xaa, (byte) 0xb7, (byte) 0xb0, (byte) 0x2d, (byte) 0x54, + (byte) 0x01, (byte) 0x5d, (byte) 0x3e, (byte) 0x43, (byte) 0x2b, + (byte) 0x2a, (byte) 0x8e, (byte) 0xd7, (byte) 0x4e, (byte) 0xec, + (byte) 0x48, (byte) 0x75, (byte) 0x41, (byte) 0xa4, (byte) 0xa3, + (byte) 0x63, (byte) 0x30, (byte) 0x61, (byte) 0x30, (byte) 0x1d, + (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e, + 0x04, (byte) 0x16, (byte) 0x04, (byte) 0x14, (byte) 0xc8, + (byte) 0xad, (byte) 0xe9, (byte) 0x77, (byte) 0x4c, (byte) 0x45, + (byte) 0xc3, (byte) 0xa3, (byte) 0xcf, (byte) 0x0d, (byte) 0x16, + (byte) 0x10, (byte) 0xe4, (byte) 0x79, (byte) 0x43, (byte) 0x3a, + (byte) 0x21, (byte) 0x5a, (byte) 0x30, (byte) 0xcf, (byte) 0x30, + (byte) 0x1f, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, + (byte) 0x23, (byte) 0x04, 0x18, (byte) 0x30, (byte) 0x16, + (byte) 0x80, (byte) 0x14, (byte) 0xc8, (byte) 0xad, (byte) 0xe9, + (byte) 0x77, (byte) 0x4c, (byte) 0x45, (byte) 0xc3, (byte) 0xa3, + (byte) 0xcf, (byte) 0x0d, (byte) 0x16, 0x10, (byte) 0xe4, + (byte) 0x79, (byte) 0x43, (byte) 0x3a, (byte) 0x21, (byte) 0x5a, + (byte) 0x30, (byte) 0xcf, (byte) 0x30, (byte) 0x0f, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x13, 0x01, + (byte) 0x01, (byte) 0xff, (byte) 0x04, (byte) 0x05, (byte) 0x30, + (byte) 0x03, (byte) 0x01, (byte) 0x01, (byte) 0xff, (byte) 0x30, + (byte) 0x0e, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, + 0x0f, (byte) 0x01, (byte) 0x01, (byte) 0xff, (byte) 0x04, + (byte) 0x04, (byte) 0x03, (byte) 0x02, (byte) 0x02, (byte) 0x84, + (byte) 0x30, (byte) 0x0a, (byte) 0x06, (byte) 0x08, (byte) 0x2a, + (byte) 0x86, 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x04, + (byte) 0x03, (byte) 0x02, (byte) 0x03, (byte) 0x47, (byte) 0x00, + (byte) 0x30, (byte) 0x44, (byte) 0x02, (byte) 0x20, (byte) 0x35, + (byte) 0x21, (byte) 0xa3, (byte) 0xef, (byte) 0x8b, (byte) 0x34, + (byte) 0x46, (byte) 0x1e, (byte) 0x9c, (byte) 0xd5, (byte) 0x60, + (byte) 0xf3, (byte) 0x1d, (byte) 0x58, (byte) 0x89, (byte) 0x20, + (byte) 0x6a, (byte) 0xdc, (byte) 0xa3, 0x65, (byte) 0x41, + (byte) 0xf6, (byte) 0x0d, (byte) 0x9e, (byte) 0xce, (byte) 0x8a, + (byte) 0x19, (byte) 0x8c, (byte) 0x66, (byte) 0x48, (byte) 0x60, + (byte) 0x7b, (byte) 0x02, (byte) 0x20, (byte) 0x4d, 0x0b, + (byte) 0xf3, (byte) 0x51, (byte) 0xd9, (byte) 0x30, (byte) 0x7c, + (byte) 0x7d, (byte) 0x5b, (byte) 0xda, (byte) 0x35, (byte) 0x34, + (byte) 0x1d, (byte) 0xa8, (byte) 0x47, (byte) 0x1b, (byte) 0x63, + (byte) 0xa5, (byte) 0x85, (byte) 0x65, (byte) 0x3c, (byte) 0xad, + (byte) 0x4f, (byte) 0x24, (byte) 0xa7, (byte) 0xe7, (byte) 0x4d, + (byte) 0xaf, (byte) 0x41, (byte) 0x7d, (byte) 0xf1, + (byte) 0xbf, }; + + private static final byte[] X509Issuer = { + (byte) 0x30, (byte) 0x81, (byte) 0x88, (byte) 0x31, (byte) 0x0b, + (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, + (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x55, + (byte) 0x53, (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11, + (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08, + (byte) 0x0c, (byte) 0x0a, (byte) 0x43, (byte) 0x61, (byte) 0x6c, + (byte) 0x69, (byte) 0x66, (byte) 0x6f, (byte) 0x72, (byte) 0x6e, + (byte) 0x69, (byte) 0x61, (byte) 0x31, (byte) 0x15, (byte) 0x30, + (byte) 0x13, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, + (byte) 0x0a, (byte) 0x0c, (byte) 0x0c, (byte) 0x47, (byte) 0x6f, + (byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65, (byte) 0x2c, + (byte) 0x20, (byte) 0x49, (byte) 0x6e, (byte) 0x63, (byte) 0x2e, + (byte) 0x31, (byte) 0x10, (byte) 0x30, (byte) 0x0e, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0b, (byte) 0x0c, + (byte) 0x07, (byte) 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, + (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x31, (byte) 0x3b, + (byte) 0x30, (byte) 0x39, (byte) 0x06, (byte) 0x03, (byte) 0x55, + (byte) 0x04, (byte) 0x03, (byte) 0x0c, (byte) 0x32, (byte) 0x41, + (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, + (byte) 0x64, (byte) 0x20, (byte) 0x4b, (byte) 0x65, (byte) 0x79, + (byte) 0x73, (byte) 0x74, (byte) 0x6f, (byte) 0x72, (byte) 0x65, + (byte) 0x20, (byte) 0x53, (byte) 0x6f, (byte) 0x66, (byte) 0x74, + (byte) 0x77, (byte) 0x61, (byte) 0x72, (byte) 0x65, (byte) 0x20, + (byte) 0x41, (byte) 0x74, (byte) 0x74, (byte) 0x65, (byte) 0x73, + (byte) 0x74, (byte) 0x61, (byte) 0x74, (byte) 0x69, (byte) 0x6f, + (byte) 0x6e, (byte) 0x20, (byte) 0x49, (byte) 0x6e, (byte) 0x74, + (byte) 0x65, (byte) 0x72, (byte) 0x6d, (byte) 0x65, (byte) 0x64, + (byte) 0x69, (byte) 0x61, (byte) 0x74, (byte) 0x65 }; // AttestationApplicationId ::= SEQUENCE { // * packageInfoRecords SET OF PackageInfoRecord, // * signatureDigests SET OF OCTET_STRING, @@ -71,8 +409,8 @@ public class KMFunctionalTest { private static final byte[] attAppId = {0x30, 0x10, 0x31, 0x0B, 0x30, 0x04, 0x05, 'A', 'B', 'C', 'D', 'E', 0x02, 0x01, 0x01, 0x31, 0x02, 0x04, 0x00}; private static final byte[] attChallenge = {'c','h','a','l','l','e','n','g','e'}; - private static final byte[] expiryTime = {0x32,0x30,0x35,0x37,0x30,0x31,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5A}; - private static final byte[] authKeyId = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2}; + private static final byte[] expiryTime = {(byte)0x32, (byte)0x36, (byte)0x30, (byte)0x31, (byte)0x30, (byte)0x38, (byte)0x30, (byte)0x30, (byte)0x34, (byte)0x36, (byte)0x30, (byte)0x39, (byte)0x5a}; + private static final byte[] authKeyId = { (byte)0x80, (byte)0x14, (byte)0xc8, (byte)0xad, (byte)0xe9, (byte)0x77, (byte)0x4c, (byte)0x45, (byte)0xc3, (byte)0xa3, (byte)0xcf, (byte)0x0d, (byte)0x16, (byte)0x10, (byte)0xe4, (byte)0x79, (byte)0x43, (byte)0x3a, (byte)0x21, (byte)0x5a, (byte)0x30, (byte)0xcf}; private KMSEProvider sim; private CardSimulator simulator; @@ -81,8 +419,8 @@ public class KMFunctionalTest { private KMSEProvider cryptoProvider; public KMFunctionalTest(){ - cryptoProvider = KMSEProviderImpl.instance(); - sim = KMSEProviderImpl.instance(); + cryptoProvider = KMSEProviderImpl.instance(false); + sim = KMSEProviderImpl.instance(false); simulator = new CardSimulator(); encoder = new KMEncoder(); decoder = new KMDecoder(); @@ -96,153 +434,203 @@ private void init(){ simulator.selectApplet(appletAID); // provision attest key provisionCmd(simulator); - // set bootup parameters - setBootParams(simulator,(short)1,(short)1); - } - - private void initBackUpStore(){ - // Create simulator - AID appletAID2 = AIDUtil.create("A000000063"); - simulator.installApplet(appletAID2, KMBackupStoreApplet.class); - //simulator.selectApplet(appletAID2); } - private void setBootParams(CardSimulator simulator, short osVersion, short osPatchLevel){ + private void setBootParams(CardSimulator simulator, short osVersion, + short osPatchLevel, short vendorPatchLevel, short bootPatchLevel) { // Argument 1 OS Version short versionPtr = KMInteger.uint_16(osVersion); -// short versionTagPtr = KMIntegerTag.instance(KMType.UINT_TAG, KMType.OS_VERSION,versionPatchPtr); + // short versionTagPtr = KMIntegerTag.instance(KMType.UINT_TAG, + // KMType.OS_VERSION,versionPatchPtr); // Argument 2 OS Patch level short patchPtr = KMInteger.uint_16(osPatchLevel); + short vendorpatchPtr = KMInteger.uint_16((short) vendorPatchLevel); + short bootpatchPtr = KMInteger.uint_16((short) bootPatchLevel); // Argument 3 Verified Boot Key byte[] bootKeyHash = "00011122233344455566677788899900".getBytes(); - short bootKeyPtr = KMByteBlob.instance(bootKeyHash,(short)0, (short)bootKeyHash.length); + short bootKeyPtr = KMByteBlob.instance(bootKeyHash, (short) 0, + (short) bootKeyHash.length); // Argument 4 Verified Boot Hash - short bootHashPtr = KMByteBlob.instance(bootKeyHash,(short)0, (short)bootKeyHash.length); + short bootHashPtr = KMByteBlob.instance(bootKeyHash, (short) 0, + (short) bootKeyHash.length); // Argument 5 Verified Boot State - short bootStatePtr = KMEnum.instance(KMType.VERIFIED_BOOT_STATE,KMType.VERIFIED_BOOT); + short bootStatePtr = KMEnum.instance(KMType.VERIFIED_BOOT_STATE, + KMType.VERIFIED_BOOT); // Argument 6 Device Locked - short deviceLockedPtr = KMEnum.instance(KMType.DEVICE_LOCKED, KMType.DEVICE_LOCKED_FALSE); + short deviceLockedPtr = KMEnum.instance(KMType.DEVICE_LOCKED, + KMType.DEVICE_LOCKED_FALSE); // Arguments - short arrPtr = KMArray.instance((short) 6); + short arrPtr = KMArray.instance((short) 8); KMArray vals = KMArray.cast(arrPtr); - vals.add((short)0, versionPtr); + vals.add((short) 0, versionPtr); vals.add((short) 1, patchPtr); - vals.add((short) 2, bootKeyPtr); - vals.add((short) 3, bootHashPtr); - vals.add((short) 4, bootStatePtr); - vals.add((short) 5, deviceLockedPtr); - CommandAPDU apdu = encodeApdu((byte)0x24, arrPtr); + vals.add((short) 2, vendorpatchPtr); + vals.add((short) 3, bootpatchPtr); + vals.add((short) 4, bootKeyPtr); + vals.add((short) 5, bootHashPtr); + vals.add((short) 6, bootStatePtr); + vals.add((short) 7, deviceLockedPtr); + CommandAPDU apdu = encodeApdu((byte) INS_SET_BOOT_PARAMS_CMD, arrPtr); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); Assert.assertEquals(0x9000, response.getSW()); } - //TODO change this - private void provisionCmd(CardSimulator simulator) { -/* // Argument 1 - short arrPtr = KMArray.instance((short) 1); - KMArray vals = KMArray.cast(arrPtr); - vals.add((short) 0, KMEnumTag.instance(KMType.ALGORITHM, KMType.RSA)); - short keyparamsPtr = KMKeyParameters.instance(arrPtr); - // Argument 2 - short keyFormatPtr = KMEnum.instance(KMType.KEY_FORMAT, KMType.X509); - // Argument 3 - byte[] byteBlob = new byte[48]; - for (short i = 0; i < 48; i++) { - byteBlob[i] = (byte) i; - } - short keyBlobPtr = KMByteBlob.instance(byteBlob, (short) 0, (short)byteBlob.length); - // Array of expected arguments - short argPtr = KMArray.instance((short) 3); - KMArray arg = KMArray.cast(argPtr); - arg.add((short) 0, keyparamsPtr); - arg.add((short) 1, keyFormatPtr); - arg.add((short) 2, keyBlobPtr); - CommandAPDU apdu = encodeApdu((byte)0x23, argPtr); + private void provisionSigningCertificate(CardSimulator simulator) { + short byteBlobPtr = KMByteBlob.instance( + (short) (kEcAttestCert.length + kEcAttestRootCert.length)); + Util.arrayCopyNonAtomic(kEcAttestCert, (short) 0, + KMByteBlob.cast(byteBlobPtr).getBuffer(), + KMByteBlob.cast(byteBlobPtr).getStartOff(), + (short) kEcAttestCert.length); + Util.arrayCopyNonAtomic(kEcAttestRootCert, (short) 0, + KMByteBlob.cast(byteBlobPtr).getBuffer(), + (short) (KMByteBlob.cast(byteBlobPtr).getStartOff() + + kEcAttestCert.length), + (short) kEcAttestRootCert.length); + CommandAPDU apdu = encodeApdu( + (byte) INS_PROVISION_ATTESTATION_CERT_CHAIN_CMD, byteBlobPtr); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); Assert.assertEquals(0x9000, response.getSW()); -*/ -/* KeyPair rsaKeyPair = cryptoProvider.createRsaKeyPair(); - byte[] pub = new byte[4]; - short len = ((RSAPublicKey)rsaKeyPair.getPublic()).getExponent(pub,(short)1); - byte[] priv = new byte[256]; - byte[] mod = new byte[256]; - len = ((RSAPrivateKey)rsaKeyPair.getPrivate()).getModulus(mod,(short)0); - len = ((RSAPrivateKey)rsaKeyPair.getPrivate()).getExponent(priv,(short)0); -*/ - byte[] sharedKeySecret = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - byte[] pub = new byte[]{0x00,0x01,0x00,0x01}; - byte[] mod = new byte[256]; - byte[] priv = new byte[256]; - short[] lengths = new short[2]; - cryptoProvider.createAsymmetricKey(KMType.RSA,priv,(short)0,(short)256,mod,(short)0, (short)256,lengths); - short arrPtr = KMArray.instance((short)15); - short boolTag = KMBoolTag.instance(KMType.NO_AUTH_REQUIRED); - short keySize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, KMInteger.uint_16((short)2048)); - short byteBlob = KMByteBlob.instance((short)1); - KMByteBlob.cast(byteBlob).add((short)0, KMType.SHA2_256); + } + + private void provisionSigningKey(CardSimulator simulator) { + // KeyParameters. + short arrPtr = KMArray.instance((short) 4); + short ecCurve = KMEnumTag.instance(KMType.ECCURVE, KMType.P_256); + short byteBlob = KMByteBlob.instance((short) 1); + KMByteBlob.cast(byteBlob).add((short) 0, KMType.SHA2_256); short digest = KMEnumArrayTag.instance(KMType.DIGEST, byteBlob); - short rsaPubExpTag = KMIntegerTag.instance(KMType.ULONG_TAG,KMType.RSA_PUBLIC_EXPONENT, KMInteger.uint_32(pub, (short)0)); - short byteBlob1 = KMByteBlob.instance((short)1); - KMByteBlob.cast(byteBlob1).add((short)0, KMType.RSA_PKCS1_1_5_SIGN); - short padding = KMEnumArrayTag.instance(KMType.PADDING, byteBlob1); - short byteBlob2 = KMByteBlob.instance((short)1); - KMByteBlob.cast(byteBlob2).add((short)0, KMType.ATTEST_KEY); + short byteBlob2 = KMByteBlob.instance((short) 1); + KMByteBlob.cast(byteBlob2).add((short) 0, KMType.ATTEST_KEY); short purpose = KMEnumArrayTag.instance(KMType.PURPOSE, byteBlob2); - KMArray.cast(arrPtr).add((short)0, boolTag); - KMArray.cast(arrPtr).add((short)1, keySize); - KMArray.cast(arrPtr).add((short)2, digest); - KMArray.cast(arrPtr).add((short)3, rsaPubExpTag); - KMArray.cast(arrPtr).add((short)4, KMEnumTag.instance(KMType.ALGORITHM, KMType.RSA)); - KMArray.cast(arrPtr).add((short)5, padding); - KMArray.cast(arrPtr).add((short)6, purpose); + KMArray.cast(arrPtr).add((short) 0, ecCurve); + KMArray.cast(arrPtr).add((short) 1, digest); + KMArray.cast(arrPtr).add((short) 2, + KMEnumTag.instance(KMType.ALGORITHM, KMType.EC)); + KMArray.cast(arrPtr).add((short) 3, purpose); + short keyParams = KMKeyParameters.instance(arrPtr); + // Note: VTS uses PKCS8 KeyFormat RAW + short keyFormatPtr = KMEnum.instance(KMType.KEY_FORMAT, KMType.RAW); + + // Key + short signKeyPtr = KMArray.instance((short) 2); + KMArray.cast(signKeyPtr).add((short) 0, KMByteBlob.instance(kEcPrivKey, + (short) 0, (short) kEcPrivKey.length)); + KMArray.cast(signKeyPtr).add((short) 1, KMByteBlob.instance(kEcPubKey, + (short) 0, (short) kEcPubKey.length)); + byte[] keyBuf = new byte[120]; + short len = encoder.encode(signKeyPtr, keyBuf, (short) 0); + short signKeyBstr = KMByteBlob.instance(keyBuf, (short) 0, len); + + short finalArrayPtr = KMArray.instance((short) 3); + KMArray.cast(finalArrayPtr).add((short) 0, keyParams); + KMArray.cast(finalArrayPtr).add((short) 1, keyFormatPtr); + KMArray.cast(finalArrayPtr).add((short) 2, signKeyBstr); + + CommandAPDU apdu = encodeApdu((byte) INS_PROVISION_ATTESTATION_KEY_CMD, + finalArrayPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + Assert.assertEquals(0x9000, response.getSW()); + } + + private void provisionCertificateParams(CardSimulator simulator) { + + short arrPtr = KMArray.instance((short) 3); + short byteBlob1 = KMByteBlob.instance(X509Issuer, (short) 0, + (short) X509Issuer.length); + KMArray.cast(arrPtr).add((short) 0, byteBlob1); + short byteBlob2 = KMByteBlob.instance(expiryTime, (short) 0, + (short) expiryTime.length); + KMArray.cast(arrPtr).add((short) 1, byteBlob2); + short byteBlob3 = KMByteBlob.instance(authKeyId, (short) 0, + (short) authKeyId.length); + KMArray.cast(arrPtr).add((short) 2, byteBlob3); + + CommandAPDU apdu = encodeApdu( + (byte) INS_PROVISION_ATTESTATION_CERT_PARAMS_CMD, arrPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + Assert.assertEquals(0x9000, response.getSW()); + } + + private void provisionSharedSecret(CardSimulator simulator) { + byte[] sharedKeySecret = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + short arrPtr = KMArray.instance((short) 1); + short byteBlob = KMByteBlob.instance(sharedKeySecret, (short) 0, + (short) sharedKeySecret.length); + KMArray.cast(arrPtr).add((short) 0, byteBlob); + + CommandAPDU apdu = encodeApdu((byte) INS_PROVISION_SHARED_SECRET_CMD, + arrPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + Assert.assertEquals(0x9000, response.getSW()); + } + + private void provisionAttestIds(CardSimulator simulator) { + short arrPtr = KMArray.instance((short) 8); + byte[] buf = "Attestation Id".getBytes(); - //Attestatation Ids. - KMArray.cast(arrPtr).add((short)7, KMByteTag.instance(KMType.ATTESTATION_ID_BRAND, - KMByteBlob.instance(buf,(short)0, (short)buf.length))); - KMArray.cast(arrPtr).add((short)8, KMByteTag.instance(KMType.ATTESTATION_ID_PRODUCT, - KMByteBlob.instance(buf,(short)0, (short)buf.length))); - KMArray.cast(arrPtr).add((short)9, KMByteTag.instance(KMType.ATTESTATION_ID_DEVICE, - KMByteBlob.instance(buf,(short)0, (short)buf.length))); - KMArray.cast(arrPtr).add((short)10, KMByteTag.instance(KMType.ATTESTATION_ID_MODEL, - KMByteBlob.instance(buf,(short)0, (short)buf.length))); - KMArray.cast(arrPtr).add((short)11, KMByteTag.instance(KMType.ATTESTATION_ID_IMEI, - KMByteBlob.instance(buf,(short)0, (short)buf.length))); - KMArray.cast(arrPtr).add((short)12, KMByteTag.instance(KMType.ATTESTATION_ID_MEID, - KMByteBlob.instance(buf,(short)0, (short)buf.length))); - KMArray.cast(arrPtr).add((short)13, KMByteTag.instance(KMType.ATTESTATION_ID_MANUFACTURER, - KMByteBlob.instance(buf,(short)0, (short)buf.length))); - KMArray.cast(arrPtr).add((short)14, KMByteTag.instance(KMType.ATTESTATION_ID_SERIAL, - KMByteBlob.instance(buf,(short)0, (short)buf.length))); + + KMArray.cast(arrPtr).add((short) 0, + KMByteTag.instance(KMType.ATTESTATION_ID_BRAND, + KMByteBlob.instance(buf, (short) 0, (short) buf.length))); + KMArray.cast(arrPtr).add((short) 1, + KMByteTag.instance(KMType.ATTESTATION_ID_PRODUCT, + KMByteBlob.instance(buf, (short) 0, (short) buf.length))); + KMArray.cast(arrPtr).add((short) 2, + KMByteTag.instance(KMType.ATTESTATION_ID_DEVICE, + KMByteBlob.instance(buf, (short) 0, (short) buf.length))); + KMArray.cast(arrPtr).add((short) 3, + KMByteTag.instance(KMType.ATTESTATION_ID_MODEL, + KMByteBlob.instance(buf, (short) 0, (short) buf.length))); + KMArray.cast(arrPtr).add((short) 4, + KMByteTag.instance(KMType.ATTESTATION_ID_IMEI, + KMByteBlob.instance(buf, (short) 0, (short) buf.length))); + KMArray.cast(arrPtr).add((short) 5, + KMByteTag.instance(KMType.ATTESTATION_ID_MEID, + KMByteBlob.instance(buf, (short) 0, (short) buf.length))); + KMArray.cast(arrPtr).add((short) 6, + KMByteTag.instance(KMType.ATTESTATION_ID_MANUFACTURER, + KMByteBlob.instance(buf, (short) 0, (short) buf.length))); + KMArray.cast(arrPtr).add((short) 7, + KMByteTag.instance(KMType.ATTESTATION_ID_SERIAL, + KMByteBlob.instance(buf, (short) 0, (short) buf.length))); short keyParams = KMKeyParameters.instance(arrPtr); - short keyFormatPtr = KMEnum.instance(KMType.KEY_FORMAT, KMType.RAW);// Note: VTS uses PKCS8 - short keyBlob = KMArray.instance((short)2); - KMArray.cast(keyBlob).add((short)0, KMByteBlob.instance(priv,(short)0,(short)256)); - KMArray.cast(keyBlob).add((short)1, KMByteBlob.instance(mod,(short)0,(short)256)); - byte[] blob = new byte[620]; - short len = encoder.encode(keyBlob,blob,(short)0); - keyBlob = KMByteBlob.instance(blob, (short)0, len); - arrPtr = KMArray.instance((short)7); - KMArray arg = KMArray.cast(arrPtr); - arg.add((short) 0, keyParams); - arg.add((short)1, keyFormatPtr); - arg.add((short)2, keyBlob); - short byteBlob3 = KMByteBlob.instance(X509Issuer, (short)0, (short)X509Issuer.length); - arg.add((short)3, byteBlob3); - short byteBlob4 = KMByteBlob.instance(expiryTime, (short)0, (short)expiryTime.length); - arg.add((short)4, byteBlob4); - short byteBlob5 = KMByteBlob.instance(authKeyId, (short)0, (short)authKeyId.length); - arg.add((short)5, byteBlob5); - short byteBlob6 = KMByteBlob.instance(sharedKeySecret, (short)0, (short)sharedKeySecret.length); - arg.add((short)6, byteBlob6); - CommandAPDU apdu = encodeApdu((byte)0x23, arrPtr); + short outerArrPtr = KMArray.instance((short) 1); + KMArray.cast(outerArrPtr).add((short) 0, keyParams); + CommandAPDU apdu = encodeApdu((byte) INS_PROVISION_ATTEST_IDS_CMD, + outerArrPtr); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); Assert.assertEquals(0x9000, response.getSW()); } + private void provisionLocked(CardSimulator simulator) { + CommandAPDU commandAPDU = new CommandAPDU(0x80, INS_LOCK_PROVISIONING_CMD, + 0x40, 0x00); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(commandAPDU); + Assert.assertEquals(0x9000, response.getSW()); + } + + private void provisionCmd(CardSimulator simulator) { + provisionSigningKey(simulator); + provisionSigningCertificate(simulator); + provisionCertificateParams(simulator); + provisionSharedSecret(simulator); + provisionAttestIds(simulator); + // set bootup parameters + setBootParams(simulator,(short)1,(short)1, (short)0, (short)0); + provisionLocked(simulator); + } + private void cleanUp(){ AID appletAID = AIDUtil.create("A000000062"); // Delete i.e. uninstall applet @@ -255,7 +643,7 @@ private void cleanUpBkUpStore(){ simulator.deleteApplet(appletAID); } private CommandAPDU encodeApdu(byte ins, short cmd){ - byte[] buf = new byte[2048]; + byte[] buf = new byte[2500]; buf[0] = (byte)0x80; buf[1] = ins; buf[2] = (byte)0x40; @@ -269,19 +657,6 @@ private CommandAPDU encodeApdu(byte ins, short cmd){ return new CommandAPDU(apdu); } - @Test - public void testBackupRestore(){ - init(); - initBackUpStore(); - CommandAPDU commandAPDU = new CommandAPDU(0x80, 0x27, 0x40, 0x00); - ResponseAPDU response = simulator.transmitCommand(commandAPDU); - byte[] data = response.getBytes(); - Assert.assertEquals(data[0], KMError.OK); - commandAPDU = new CommandAPDU(0x80, 0x28, 0x40, 0x00); - response = simulator.transmitCommand(commandAPDU); - data = response.getBytes(); - Assert.assertEquals(data[0], KMError.OK); - } @Test public void testAesImportKeySuccess() { init(); @@ -312,7 +687,7 @@ public void testAesImportKeySuccess() { arg.add((short) 0, keyParams); arg.add((short)1, keyFormatPtr); arg.add((short)2, keyBlob); - CommandAPDU apdu = encodeApdu((byte)0x11, arrPtr); + CommandAPDU apdu = encodeApdu((byte)INS_IMPORT_KEY_CMD, arrPtr); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); short ret = KMArray.instance((short) 3); @@ -373,7 +748,7 @@ public void testHmacImportKeySuccess() { arg.add((short) 0, keyParams); arg.add((short)1, keyFormatPtr); arg.add((short)2, keyBlob); - CommandAPDU apdu = encodeApdu((byte)0x11, arrPtr); + CommandAPDU apdu = encodeApdu((byte)INS_IMPORT_KEY_CMD, arrPtr); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); short ret = KMArray.instance((short) 3); @@ -454,7 +829,7 @@ public void testRsaImportKeySuccess() { arg.add((short) 0, keyParams); arg.add((short)1, keyFormatPtr); arg.add((short)2, keyBlob); - CommandAPDU apdu = encodeApdu((byte)0x11, arrPtr); + CommandAPDU apdu = encodeApdu((byte)INS_IMPORT_KEY_CMD, arrPtr); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); short ret = KMArray.instance((short) 3); @@ -602,7 +977,7 @@ private void deviceLock(short verToken) { short req = KMArray.instance((short)2); KMArray.cast(req).add((short)0, KMInteger.uint_8((byte)1)); KMArray.cast(req).add((short)1, verToken); - CommandAPDU apdu = encodeApdu((byte)0x25,req); + CommandAPDU apdu = encodeApdu((byte)INS_DEVICE_LOCKED_CMD,req); ResponseAPDU response = simulator.transmitCommand(apdu); short ret = KMArray.instance((short) 1); KMArray.cast(ret).add((short) 0, KMInteger.exp()); @@ -706,7 +1081,7 @@ public void testEcImportKeySuccess() { arg.add((short) 0, keyParams); arg.add((short)1, keyFormatPtr); arg.add((short)2, keyBlob); - CommandAPDU apdu = encodeApdu((byte)0x11, arrPtr); + CommandAPDU apdu = encodeApdu((byte)INS_IMPORT_KEY_CMD, arrPtr); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); short ret = KMArray.instance((short) 3); @@ -837,7 +1212,7 @@ private short generateRsaKey(byte[] clientId, byte[] appData){ arrPtr = KMArray.instance((short)1); KMArray arg = KMArray.cast(arrPtr); arg.add((short) 0, keyParams); - CommandAPDU apdu = encodeApdu((byte)0x10, arrPtr); + CommandAPDU apdu = encodeApdu((byte)INS_GENERATE_KEY_CMD, arrPtr); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); Assert.assertEquals(0x9000, response.getSW()); @@ -890,7 +1265,7 @@ private short generateAttestationKey(){ arrPtr = KMArray.instance((short)1); KMArray arg = KMArray.cast(arrPtr); arg.add((short) 0, keyParams); - CommandAPDU apdu = encodeApdu((byte)0x10, arrPtr); + CommandAPDU apdu = encodeApdu((byte)INS_GENERATE_KEY_CMD, arrPtr); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); Assert.assertEquals(0x9000, response.getSW()); @@ -957,7 +1332,7 @@ public short generateEcKey(byte[] clientId, byte[] appData) { arrPtr = KMArray.instance((short)1); KMArray arg = KMArray.cast(arrPtr); arg.add((short) 0, keyParams); - CommandAPDU apdu = encodeApdu((byte)0x10, arrPtr); + CommandAPDU apdu = encodeApdu((byte)INS_GENERATE_KEY_CMD, arrPtr); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); Assert.assertEquals(0x9000, response.getSW()); @@ -1024,7 +1399,7 @@ public short generateHmacKey(byte[] clientId, byte[] appData){ arrPtr = KMArray.instance((short)1); KMArray arg = KMArray.cast(arrPtr); arg.add((short) 0, keyParams); - CommandAPDU apdu = encodeApdu((byte)0x10, arrPtr); + CommandAPDU apdu = encodeApdu((byte)INS_GENERATE_KEY_CMD, arrPtr); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); short ret = KMArray.instance((short) 3); @@ -1078,7 +1453,7 @@ public short generateAesDesKey(byte alg, short keysize, byte[] clientId, byte[] arrPtr = KMArray.instance((short)1); KMArray arg = KMArray.cast(arrPtr); arg.add((short) 0, keyParams); - CommandAPDU apdu = encodeApdu((byte)0x10, arrPtr); + CommandAPDU apdu = encodeApdu((byte)INS_GENERATE_KEY_CMD, arrPtr); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); short ret = KMArray.instance((short) 3); @@ -1129,7 +1504,7 @@ public short generateAesGcmKey(short keysize, byte[] clientId, byte[] appData) { arrPtr = KMArray.instance((short)1); KMArray arg = KMArray.cast(arrPtr); arg.add((short) 0, keyParams); - CommandAPDU apdu = encodeApdu((byte)0x10, arrPtr); + CommandAPDU apdu = encodeApdu((byte)INS_GENERATE_KEY_CMD, arrPtr); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); short ret = KMArray.instance((short) 3); @@ -1183,7 +1558,7 @@ public void testComputeHmacParams(){ KMArray.cast(arr).add((short)1,params2); short arrPtr = KMArray.instance((short)1); KMArray.cast(arrPtr).add((short)0,arr); - CommandAPDU apdu = encodeApdu((byte)0x19, arrPtr); + CommandAPDU apdu = encodeApdu((byte)INS_COMPUTE_SHARED_HMAC_CMD, arrPtr); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); Assert.assertEquals(0x9000, response.getSW()); @@ -1202,7 +1577,7 @@ public void testComputeHmacParams(){ @Test public void testGetHmacSharingParams(){ init(); - CommandAPDU commandAPDU = new CommandAPDU(0x80, 0x1C, 0x40, 0x00); + CommandAPDU commandAPDU = new CommandAPDU(0x80, INS_GET_HMAC_SHARING_PARAM_CMD, 0x40, 0x00); //print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(commandAPDU); KMDecoder dec = new KMDecoder(); @@ -1225,7 +1600,7 @@ public void testGetHmacSharingParams(){ cleanUp(); } public short getHmacSharingParams(){ - CommandAPDU commandAPDU = new CommandAPDU(0x80, 0x1C, 0x40, 0x00); + CommandAPDU commandAPDU = new CommandAPDU(0x80, INS_GET_HMAC_SHARING_PARAM_CMD, 0x40, 0x00); //print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(commandAPDU); KMDecoder dec = new KMDecoder(); @@ -1319,7 +1694,7 @@ public void testImportWrappedKey(){ KMArray.cast(arr).add((short) 9, KMByteBlob.instance(authData,(short)0,(short)authData.length)); // Wrapped Key ASSOCIATED AUTH DATA KMArray.cast(arr).add((short) 10, KMInteger.uint_8((byte)0)); // Password Sid KMArray.cast(arr).add((short) 11, KMInteger.uint_8((byte)0)); // Biometric Sid - CommandAPDU apdu = encodeApdu((byte)0x12, arr); + CommandAPDU apdu = encodeApdu((byte)INS_IMPORT_WRAPPED_KEY_CMD, arr); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); ret = KMArray.instance((short) 3); @@ -1366,7 +1741,7 @@ public void testGetKeyCharacteristicsWithIdDataSuccess() { KMArray.cast(arrPtr).add((short)0, keyBlob); KMArray.cast(arrPtr).add((short)1, KMByteBlob.instance(clientId,(short)0, (short)clientId.length)); KMArray.cast(arrPtr).add((short)2, KMByteBlob.instance(appData,(short)0, (short)appData.length)); - CommandAPDU apdu = encodeApdu((byte)0x1D, arrPtr); + CommandAPDU apdu = encodeApdu((byte)INS_GET_KEY_CHARACTERISTICS_CMD, arrPtr); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); ret = KMArray.instance((short) 2); @@ -1393,7 +1768,7 @@ public void testGetKeyCharacteristicsSuccess() { KMArray.cast(arrPtr).add((short)0, keyBlob); KMArray.cast(arrPtr).add((short)1, KMByteBlob.instance((short)0)); KMArray.cast(arrPtr).add((short)2, KMByteBlob.instance((short)0)); - CommandAPDU apdu = encodeApdu((byte)0x1D, arrPtr); + CommandAPDU apdu = encodeApdu((byte)INS_GET_KEY_CHARACTERISTICS_CMD, arrPtr); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); ret = KMArray.instance((short) 2); @@ -1439,7 +1814,7 @@ public void testDeleteAllKeySuccess() { keyBlobPtr = KMArray.cast(ret2).get((short)1); byte[] keyBlob2 = new byte[KMByteBlob.cast(keyBlobPtr).length()]; len = KMByteBlob.cast(keyBlobPtr).getValues(keyBlob2, (short)0); - CommandAPDU apdu = new CommandAPDU(0x80, 0x17, 0x40, 0x00); + CommandAPDU apdu = new CommandAPDU(0x80, INS_DELETE_ALL_KEYS_CMD, 0x40, 0x00); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); byte[] respBuf = response.getBytes(); @@ -1458,7 +1833,7 @@ public void testDeleteAllKeySuccess() { private short deleteKey(short keyBlob) { short arrPtr = KMArray.instance((short)1); KMArray.cast(arrPtr).add((short)0, keyBlob); - CommandAPDU apdu = encodeApdu((byte)0x16, arrPtr); + CommandAPDU apdu = encodeApdu((byte)INS_DELETE_KEY_CMD, arrPtr); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); byte[] respBuf = response.getBytes(); @@ -1468,7 +1843,7 @@ private short deleteKey(short keyBlob) { private short abort(short opHandle) { short arrPtr = KMArray.instance((short)1); KMArray.cast(arrPtr).add((short)0, opHandle); - CommandAPDU apdu = encodeApdu((byte)0x22, arrPtr); + CommandAPDU apdu = encodeApdu((byte)INS_ABORT_OPERATION_CMD, arrPtr); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); byte[] respBuf = response.getBytes(); @@ -1480,7 +1855,7 @@ public short getKeyCharacteristics(short keyBlob){ KMArray.cast(arrPtr).add((short)0, keyBlob); KMArray.cast(arrPtr).add((short)1, KMByteBlob.instance((short)0)); KMArray.cast(arrPtr).add((short)2, KMByteBlob.instance((short)0)); - CommandAPDU apdu = encodeApdu((byte)0x1D, arrPtr); + CommandAPDU apdu = encodeApdu((byte)INS_GET_KEY_CHARACTERISTICS_CMD, arrPtr); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); short ret = KMArray.instance((short) 2); @@ -1764,7 +2139,7 @@ public void testAttestKey(byte[] keyBlob){ short args = KMArray.instance((short)2); KMArray.cast(args).add((short)0, KMByteBlob.instance(keyBlob,(short)0,(short)keyBlob.length)); KMArray.cast(args).add((short)1, keyParams); - CommandAPDU apdu = encodeApdu((byte)0x14, args); + CommandAPDU apdu = encodeApdu((byte)INS_ATTEST_KEY_CMD, args); //print(apdu.getBytes(),(short)0,(short)apdu.getBytes().length); ResponseAPDU response = simulator.transmitCommand(apdu); short ret = KMArray.instance((short) 2); @@ -1800,7 +2175,7 @@ public void testUpgradeKey(){ osPatch = KMIntegerTag.cast(osPatch).getValue(); Assert.assertEquals(KMInteger.cast(osVersion).getShort(), 1); Assert.assertEquals(KMInteger.cast(osPatch).getShort(), 1); - setBootParams(simulator,(short) 2,(short)2); + setBootParams(simulator,(short) 2,(short)2, (short)1, (short)1); ret = upgradeKey(KMByteBlob.instance(keyBlob, (short)0, (short)keyBlob.length),null, null); keyBlobPtr = KMArray.cast(ret).get((short)1); ret = getKeyCharacteristics(keyBlobPtr); @@ -1818,7 +2193,7 @@ public void testUpgradeKey(){ @Test public void testDestroyAttIds(){ init(); - CommandAPDU commandAPDU = new CommandAPDU(0x80, 0x1A, 0x40, 0x00); + CommandAPDU commandAPDU = new CommandAPDU(0x80, INS_DESTROY_ATT_IDS_CMD, 0x40, 0x00); ResponseAPDU response = simulator.transmitCommand(commandAPDU); byte[] respBuf = response.getBytes(); Assert.assertEquals(respBuf[0], 0); @@ -1841,7 +2216,7 @@ private short upgradeKey(short keyBlobPtr, byte[] clientId, byte[] appData){ short arr = KMArray.instance((short)2); KMArray.cast(arr).add((short)0,keyBlobPtr); KMArray.cast(arr).add((short)1,keyParams); - CommandAPDU apdu = encodeApdu((byte)0x15, arr); + CommandAPDU apdu = encodeApdu((byte)INS_UPGRADE_KEY_CMD, arr); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); short ret = KMArray.instance((short) 2); @@ -2216,7 +2591,7 @@ public short begin(byte keyPurpose, short keyBlob, short keyParmas, short hwToke hwToken = KMHardwareAuthToken.instance(); } KMArray.cast(arrPtr).add((short)3, hwToken); - CommandAPDU apdu = encodeApdu((byte)0x1F, arrPtr); + CommandAPDU apdu = encodeApdu((byte)INS_BEGIN_OPERATION_CMD, arrPtr); //print(apdu.getBytes(),(short)0,(short)apdu.getBytes().length); ResponseAPDU response = simulator.transmitCommand(apdu); short ret = KMArray.instance((short) 3); @@ -2261,7 +2636,7 @@ public short finish(short operationHandle, short data, byte[] signature, short i KMArray.cast(arrPtr).add((short)3, signatureTag); KMArray.cast(arrPtr).add((short)4, hwToken); KMArray.cast(arrPtr).add((short)5, verToken); - CommandAPDU apdu = encodeApdu((byte)0x21, arrPtr); + CommandAPDU apdu = encodeApdu((byte)INS_FINISH_OPERATION_CMD, arrPtr); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); short ret = KMArray.instance((short) 3); @@ -2293,7 +2668,7 @@ public short update(short operationHandle, short data, short inParams, short hwT KMArray.cast(arrPtr).add((short)2, data); KMArray.cast(arrPtr).add((short)3, hwToken); KMArray.cast(arrPtr).add((short)4, verToken); - CommandAPDU apdu = encodeApdu((byte)0x20, arrPtr); + CommandAPDU apdu = encodeApdu((byte)INS_UPDATE_OPERATION_CMD, arrPtr); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); short ret = KMArray.instance((short) 4); From 6bd852740230663db9796c5202d093adfbb7def3 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Sat, 28 Nov 2020 20:03:27 +0000 Subject: [PATCH 36/42] 1. Corrected the spelling in the function documentation. 2. Used Proper Tag names in KMAttetationCert class instead of hard-coding. --- .../keymaster/KMAttestationCertImpl.java | 25 +++++++++++-------- .../javacard/keymaster/KMAttestationCert.java | 22 ++++++++-------- .../javacard/keymaster/KMKeymasterApplet.java | 3 --- 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java index 0e0335c9..9e046264 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -478,14 +478,13 @@ private static void pushKeyDescription() { pushSequenceHeader((short) (last - stackPtr)); } - //TODO refactor following method private static void pushSWParams() { short last = stackPtr; - // ATTESTATION_APPLICATION_ID 709 is softwareEnforced. + // Below are the allowed softwareEnforced Authorization tags inside the attestation certificate's extension. short[] tagIds = { - 709, 706, 705, 704, 703, 702, 701, 601, 600, 509, 508, 507, 506, 505, 504, 503, 402, 401, 400, - 303, 200, 10, 6, 5, 3, 2, 1 - }; + KMType.ATTESTATION_APPLICATION_ID, KMType.CREATION_DATETIME, + KMType.USAGE_EXPIRE_DATETIME, KMType.ORIGINATION_EXPIRE_DATETIME, + KMType.ACTIVE_DATETIME, KMType.UNLOCKED_DEVICE_REQUIRED }; byte index = 0; do { pushParams(swParams, swParamsIndex, tagIds[index]); @@ -493,14 +492,20 @@ private static void pushSWParams() { pushSequenceHeader((short) (last - stackPtr)); } - //TODO refactor following method private static void pushHWParams() { short last = stackPtr; - // Attestation IDs are not included. As per VTS Attestation IDs are not supported currently. + // Below are the allowed hardwareEnforced Authorization tags inside the attestation certificate's extension. short[] tagIds = { - 719, 718, 706, 705, 704, 703, 702, 701, 601, 600, 509, 508, 507, 506, 505, 504, 503, 402, 401, 400, 303, - 200, 10, 6, 5, 3, 2, 1 - }; + KMType.BOOT_PATCH_LEVEL, KMType.VENDOR_PATCH_LEVEL, + KMType.OS_PATCH_LEVEL, KMType.OS_VERSION, KMType.ROOT_OF_TRUST, + KMType.ORIGIN, KMType.APPLICATION_ID, + KMType.TRUSTED_CONFIRMATION_REQUIRED, + KMType.TRUSTED_USER_PRESENCE_REQUIRED, KMType.ALLOW_WHILE_ON_BODY, + KMType.AUTH_TIMEOUT, KMType.USER_AUTH_TYPE, KMType.NO_AUTH_REQUIRED, + KMType.ROLLBACK_RESISTANCE, KMType.RSA_PUBLIC_EXPONENT, + KMType.ECCURVE, KMType.PADDING, KMType.DIGEST, KMType.KEYSIZE, + KMType.ALGORITHM, KMType.PURPOSE }; + byte index = 0; do { if (tagIds[index] == KMType.ROOT_OF_TRUST) { diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java b/Applet/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java index 67453706..f15fbfcb 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java @@ -11,7 +11,7 @@ public interface KMAttestationCert { /** * Set verified boot hash. * - * @param obj Ths is a KMByteBlob containing hash + * @param obj This is a KMByteBlob containing hash * @return instance of KMAttestationCert */ KMAttestationCert verifiedBootHash(short obj); @@ -19,7 +19,7 @@ public interface KMAttestationCert { /** * Set verified boot key received during booting up. * - * @param obj Ths is a KMByteBlob containing verified boot key. + * @param obj This is a KMByteBlob containing verified boot key. * @return instance of KMAttestationCert */ KMAttestationCert verifiedBootKey(short obj); @@ -27,7 +27,7 @@ public interface KMAttestationCert { /** * Set verified boot state received during booting up. * - * @param val Ths is a byte containing verified boot state value. + * @param val This is a byte containing verified boot state value. * @return instance of KMAttestationCert */ KMAttestationCert verifiedBootState(byte val); @@ -35,7 +35,7 @@ public interface KMAttestationCert { /** * Set authentication key Id from CA Certificate set during provisioning. * - * @param obj Ths is a KMByteBlob containing authentication Key Id. + * @param obj This is a KMByteBlob containing authentication Key Id. * @return instance of KMAttestationCert */ KMAttestationCert authKey(short obj); @@ -88,7 +88,7 @@ KMAttestationCert notAfter(short usageExpiryTimeObj, /** * Set device lock status received during booting time or due to device lock command. * - * @param val Ths is true if device is locked. + * @param val This is true if device is locked. * @return instance of KMAttestationCert */ KMAttestationCert deviceLocked(boolean val); @@ -96,7 +96,7 @@ KMAttestationCert notAfter(short usageExpiryTimeObj, /** * Set public key to be attested received from attestKey command. * - * @param obj Ths is KMByteBlob containing the public key. + * @param obj This is KMByteBlob containing the public key. * @return instance of KMAttestationCert */ KMAttestationCert publicKey(short obj); @@ -104,7 +104,7 @@ KMAttestationCert notAfter(short usageExpiryTimeObj, /** * Set attestation challenge received from attestKey command. * - * @param obj Ths is KMByteBlob containing the attestation challenge. + * @param obj This is KMByteBlob containing the attestation challenge. * @return instance of KMAttestationCert */ KMAttestationCert attestationChallenge(short obj); @@ -123,7 +123,7 @@ KMAttestationCert notAfter(short usageExpiryTimeObj, /** * Set ASN.1 encoded X509 issuer field received from attestation key CA cert. * - * @param obj Ths is KMByteBlob containing the issuer. + * @param obj This is KMByteBlob containing the issuer. * @return instance of KMAttestationCert */ KMAttestationCert issuer(short obj); @@ -131,9 +131,9 @@ KMAttestationCert notAfter(short usageExpiryTimeObj, /** * Set byte buffer to be used to generate certificate. * - * @param buf Ths is byte[] buffer. - * @param bufStart Ths is short start offset. - * @param maxLen Ths is short length of the buffer. + * @param buf This is byte[] buffer. + * @param bufStart This is short start offset. + * @param maxLen This is short length of the buffer. * @return instance of KMAttestationCert */ KMAttestationCert buffer(byte[] buf, short bufStart, short maxLen); diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index c286d4a2..cde5de0a 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -570,9 +570,6 @@ private void processGetHwInfoCmd(APDU apdu) { sendOutgoing(apdu); } - //TODO VTS 4.0 addLargeEntropy fails, as the input buffer is 2k - //TODO Need to fix this issue by introducing stackIndex which - //increase bottom to top on internal memory. private void processAddRngEntropyCmd(APDU apdu) { // Receive the incoming request fully from the master. receiveIncoming(apdu); From 66621448193b3f6ef4c337838dfd62b9d362e925 Mon Sep 17 00:00:00 2001 From: cpathak Date: Sat, 28 Nov 2020 15:22:21 -0800 Subject: [PATCH 37/42] Resructured code and related changes --- .../AndroidSE_3_0_5.opt} | 4 +- Applet/AndroidSEProvider/AndroidSE_3_1_0.opt | 5 + .../java/io/javacard/io.exp | Bin 0 -> 212 bytes .../java/lang/javacard/lang.exp | Bin 0 -> 881 bytes .../java/rmi/javacard/rmi.exp | Bin 0 -> 280 bytes .../javacard/framework/javacard/framework.exp | Bin 8396 -> 8344 bytes .../framework/service/javacard/service.exp | Bin 3002 -> 2901 bytes .../javacard/security/javacard/security.exp | Bin 14493 -> 14393 bytes .../javacardx/apdu/javacard/apdu.exp | Bin 0 -> 113 bytes .../javacardx/apdu/util/javacard/util.exp | Bin 336 -> 306 bytes .../javacardx/biometry/javacard/biometry.exp | Bin 2325 -> 2254 bytes .../biometry1toN/javacard/biometry1toN.exp | Bin 3158 -> 3084 bytes .../javacardx/crypto/javacard/crypto.exp | Bin 3657 -> 3588 bytes .../javacardx/external/javacard/external.exp | Bin 926 -> 857 bytes .../framework/math/javacard/math.exp | Bin 844 -> 812 bytes .../framework/string/javacard/string.exp | Bin 1562 -> 1494 bytes .../javacardx/framework/tlv/javacard/tlv.exp | Bin 3084 -> 3011 bytes .../framework/util/intx/javacard/intx.exp | Bin 0 -> 309 bytes .../framework/util/javacard/util.exp | Bin 913 -> 845 bytes .../javacardx/security/javacard/security.exp | Bin 433 -> 403 bytes .../upgrade/javacard/upgrade.exp | Bin 0 -> 1705 bytes .../upgrade/javacard/upgrade.jca | 245 + .../java/io/javacard/io.exp | Bin .../java/lang/javacard/lang.exp | Bin .../java/rmi/javacard/rmi.exp | Bin .../javacard/framework/javacard/framework.exp | Bin .../framework/service/javacard/service.exp | Bin .../javacard/security/javacard/security.exp | Bin .../javacardx/apdu/javacard/apdu.exp | Bin .../javacardx/apdu/util/javacard/util.exp | Bin .../javacardx/biometry/javacard/biometry.exp | Bin .../biometry1toN/javacard/biometry1toN.exp | Bin .../javacardx/crypto/javacard/crypto.exp | Bin .../javacardx/external/javacard/external.exp | Bin .../framework/event/javacard/event.exp | Bin .../framework/math/javacard/math.exp | Bin .../javacardx/framework/nio/javacard/nio.exp | Bin .../framework/string/javacard/string.exp | Bin .../framework/time/javacard/time.exp | Bin .../javacardx/framework/tlv/javacard/tlv.exp | Bin .../framework/util/intx/javacard/intx.exp | Bin .../framework/util/javacard/util.exp | Bin .../javacardx/security/cert/javacard/cert.exp | Bin .../derivation/javacard/derivation.exp | Bin .../javacardx/security/javacard/security.exp | Bin .../javacardx/security/util/javacard/util.exp | Bin Applet/AndroidSEProvider/build.xml | 77 + .../lib/gpapi-upgrade.jar | Bin .../javacard/keymaster/KMAndroidSEApplet.java | 71 + .../keymaster/KMAndroidSEProvider.java} | 8 +- .../keymaster/KMAttestationCertImpl.java | 4 +- .../KMEcdsa256NoDigestSignature.java | 16 +- .../javacard/keymaster/KMInstance.java | 0 .../javacard/keymaster/KMOperationImpl.java | 16 +- .../keymaster/KMRsa2048NoDigestSignature.java | 4 +- .../javacard/keymaster/KMRsaOAEPEncoding.java | 5 +- .../android/javacard/keymaster/KMUtils.java | 0 .../javacard/keymaster/KMSEProviderImpl.java | 8 - .../javacard/keymaster/KMSEProviderImpl.java | 9 - Applet/JCardSimProvider/build.xml | 56 + Applet/JCardSimProvider/lib/gpapi-upgrade.jar | Bin 0 -> 12638 bytes .../lib/hamcrest-core-1.3.jar | Bin .../lib/jcardsim-3.0.5-SNAPSHOT.jar | Bin .../{ => JCardSimProvider}/lib/junit-4.13.jar | Bin .../keymaster/KMAttestationCertImpl.java | 4 +- .../android/javacard/keymaster/KMCipher.java | 102 +- .../javacard/keymaster/KMCipherImpl.java | 440 +- .../KMEcdsa256NoDigestSignature.java | 0 .../javacard/keymaster/KMJCardSimApplet.java | 19 + .../javacard/keymaster/KMJCardSimulator.java} | 8 +- .../javacard/keymaster/KMOperationImpl.java | 0 .../keymaster/KMRsa2048NoDigestSignature.java | 240 +- .../android/javacard/keymaster/KMUtils.java | 0 .../javacard/test/KMFunctionalTest.java | 5475 ++++++++--------- Applet/JavaCardKeymaster.scr | 50 - Applet/README.md | 12 +- .../framework/util/intx/javacard/intx.exp | Bin 339 -> 0 bytes .../java/io/javacard/io.exp | Bin 242 -> 0 bytes .../java/lang/javacard/lang.exp | Bin 894 -> 0 bytes .../java/rmi/javacard/rmi.exp | Bin 337 -> 0 bytes .../javacardx/apdu/javacard/apdu.exp | Bin 143 -> 0 bytes Applet/build.xml | 196 +- Applet/default.output | 20 - Applet/powerdown.scr | 4 - Applet/powerup.scr | 9 - .../android/javacard/keymaster/KMArray.java | 0 .../javacard/keymaster/KMAttestationCert.java | 0 .../android/javacard/keymaster/KMBoolTag.java | 0 .../javacard/keymaster/KMByteBlob.java | 0 .../android/javacard/keymaster/KMByteTag.java | 0 .../android/javacard/keymaster/KMDecoder.java | 0 .../android/javacard/keymaster/KMEncoder.java | 0 .../android/javacard/keymaster/KMEnum.java | 0 .../javacard/keymaster/KMEnumArrayTag.java | 0 .../android/javacard/keymaster/KMEnumTag.java | 0 .../android/javacard/keymaster/KMError.java | 0 .../javacard/keymaster/KMException.java | 0 .../keymaster/KMHardwareAuthToken.java | 0 .../keymaster/KMHmacSharingParameters.java | 0 .../android/javacard/keymaster/KMInteger.java | 0 .../javacard/keymaster/KMIntegerArrayTag.java | 0 .../javacard/keymaster/KMIntegerTag.java | 0 .../keymaster/KMKeyCharacteristics.java | 0 .../javacard/keymaster/KMKeyParameters.java | 0 .../javacard/keymaster/KMKeymasterApplet.java | 58 +- .../javacard/keymaster/KMOperation.java | 0 .../javacard/keymaster/KMOperationState.java | 0 .../javacard/keymaster/KMRepository.java | 0 .../javacard/keymaster/KMSEProvider.java | 0 .../com/android/javacard/keymaster/KMTag.java | 0 .../android/javacard/keymaster/KMType.java | 0 .../javacard/keymaster/KMUpgradable.java | 0 .../keymaster/KMVerificationToken.java | 0 113 files changed, 3675 insertions(+), 3490 deletions(-) rename Applet/{JavaCardKeymaster.opt => AndroidSEProvider/AndroidSE_3_0_5.opt} (61%) create mode 100644 Applet/AndroidSEProvider/AndroidSE_3_1_0.opt create mode 100644 Applet/AndroidSEProvider/api_export_files_3.0.5/java/io/javacard/io.exp create mode 100644 Applet/AndroidSEProvider/api_export_files_3.0.5/java/lang/javacard/lang.exp create mode 100644 Applet/AndroidSEProvider/api_export_files_3.0.5/java/rmi/javacard/rmi.exp rename Applet/{ => AndroidSEProvider}/api_export_files_3.0.5/javacard/framework/javacard/framework.exp (76%) rename Applet/{ => AndroidSEProvider}/api_export_files_3.0.5/javacard/framework/service/javacard/service.exp (76%) rename Applet/{ => AndroidSEProvider}/api_export_files_3.0.5/javacard/security/javacard/security.exp (67%) create mode 100644 Applet/AndroidSEProvider/api_export_files_3.0.5/javacardx/apdu/javacard/apdu.exp rename Applet/{api_export_files_3.1.0 => AndroidSEProvider/api_export_files_3.0.5}/javacardx/apdu/util/javacard/util.exp (52%) rename Applet/{ => AndroidSEProvider}/api_export_files_3.0.5/javacardx/biometry/javacard/biometry.exp (60%) rename Applet/{ => AndroidSEProvider}/api_export_files_3.0.5/javacardx/biometry1toN/javacard/biometry1toN.exp (68%) rename Applet/{ => AndroidSEProvider}/api_export_files_3.0.5/javacardx/crypto/javacard/crypto.exp (92%) rename Applet/{ => AndroidSEProvider}/api_export_files_3.0.5/javacardx/external/javacard/external.exp (67%) rename Applet/{api_export_files_3.1.0 => AndroidSEProvider/api_export_files_3.0.5}/javacardx/framework/math/javacard/math.exp (63%) rename Applet/{ => AndroidSEProvider}/api_export_files_3.0.5/javacardx/framework/string/javacard/string.exp (67%) rename Applet/{ => AndroidSEProvider}/api_export_files_3.0.5/javacardx/framework/tlv/javacard/tlv.exp (72%) create mode 100644 Applet/AndroidSEProvider/api_export_files_3.0.5/javacardx/framework/util/intx/javacard/intx.exp rename Applet/{ => AndroidSEProvider}/api_export_files_3.0.5/javacardx/framework/util/javacard/util.exp (68%) rename Applet/{api_export_files_3.1.0 => AndroidSEProvider/api_export_files_3.0.5}/javacardx/security/javacard/security.exp (59%) create mode 100644 Applet/AndroidSEProvider/api_export_files_3.0.5/org/globalplatform/upgrade/javacard/upgrade.exp create mode 100644 Applet/AndroidSEProvider/api_export_files_3.0.5/org/globalplatform/upgrade/javacard/upgrade.jca rename Applet/{api_export_files_3.0.5 => AndroidSEProvider/api_export_files_3.1.0}/java/io/javacard/io.exp (100%) rename Applet/{api_export_files_3.0.5 => AndroidSEProvider/api_export_files_3.1.0}/java/lang/javacard/lang.exp (100%) rename Applet/{api_export_files_3.0.5 => AndroidSEProvider/api_export_files_3.1.0}/java/rmi/javacard/rmi.exp (100%) rename Applet/{ => AndroidSEProvider}/api_export_files_3.1.0/javacard/framework/javacard/framework.exp (100%) rename Applet/{ => AndroidSEProvider}/api_export_files_3.1.0/javacard/framework/service/javacard/service.exp (100%) rename Applet/{ => AndroidSEProvider}/api_export_files_3.1.0/javacard/security/javacard/security.exp (100%) rename Applet/{api_export_files_3.0.5 => AndroidSEProvider/api_export_files_3.1.0}/javacardx/apdu/javacard/apdu.exp (100%) rename Applet/{api_export_files_3.0.5 => AndroidSEProvider/api_export_files_3.1.0}/javacardx/apdu/util/javacard/util.exp (100%) rename Applet/{ => AndroidSEProvider}/api_export_files_3.1.0/javacardx/biometry/javacard/biometry.exp (100%) rename Applet/{ => AndroidSEProvider}/api_export_files_3.1.0/javacardx/biometry1toN/javacard/biometry1toN.exp (100%) rename Applet/{ => AndroidSEProvider}/api_export_files_3.1.0/javacardx/crypto/javacard/crypto.exp (100%) rename Applet/{ => AndroidSEProvider}/api_export_files_3.1.0/javacardx/external/javacard/external.exp (100%) rename Applet/{ => AndroidSEProvider}/api_export_files_3.1.0/javacardx/framework/event/javacard/event.exp (100%) rename Applet/{api_export_files_3.0.5 => AndroidSEProvider/api_export_files_3.1.0}/javacardx/framework/math/javacard/math.exp (100%) rename Applet/{ => AndroidSEProvider}/api_export_files_3.1.0/javacardx/framework/nio/javacard/nio.exp (100%) rename Applet/{ => AndroidSEProvider}/api_export_files_3.1.0/javacardx/framework/string/javacard/string.exp (100%) rename Applet/{ => AndroidSEProvider}/api_export_files_3.1.0/javacardx/framework/time/javacard/time.exp (100%) rename Applet/{ => AndroidSEProvider}/api_export_files_3.1.0/javacardx/framework/tlv/javacard/tlv.exp (100%) rename Applet/{ => AndroidSEProvider}/api_export_files_3.1.0/javacardx/framework/util/intx/javacard/intx.exp (100%) rename Applet/{ => AndroidSEProvider}/api_export_files_3.1.0/javacardx/framework/util/javacard/util.exp (100%) rename Applet/{ => AndroidSEProvider}/api_export_files_3.1.0/javacardx/security/cert/javacard/cert.exp (100%) rename Applet/{ => AndroidSEProvider}/api_export_files_3.1.0/javacardx/security/derivation/javacard/derivation.exp (100%) rename Applet/{api_export_files_3.0.5 => AndroidSEProvider/api_export_files_3.1.0}/javacardx/security/javacard/security.exp (100%) rename Applet/{ => AndroidSEProvider}/api_export_files_3.1.0/javacardx/security/util/javacard/util.exp (100%) create mode 100644 Applet/AndroidSEProvider/build.xml rename Applet/{ => AndroidSEProvider}/lib/gpapi-upgrade.jar (100%) create mode 100644 Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java rename Applet/{Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java => AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java} (99%) rename Applet/{Applet/AndroidSEProvider => AndroidSEProvider/src}/com/android/javacard/keymaster/KMAttestationCertImpl.java (99%) rename Applet/{Applet/AndroidSEProvider => AndroidSEProvider/src}/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java (86%) rename Applet/{Applet/AndroidSEProvider => AndroidSEProvider/src}/com/android/javacard/keymaster/KMInstance.java (100%) rename Applet/{Applet/AndroidSEProvider => AndroidSEProvider/src}/com/android/javacard/keymaster/KMOperationImpl.java (92%) rename Applet/{Applet/AndroidSEProvider => AndroidSEProvider/src}/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java (95%) rename Applet/{Applet/AndroidSEProvider => AndroidSEProvider/src}/com/android/javacard/keymaster/KMRsaOAEPEncoding.java (98%) rename Applet/{Applet/AndroidSEProvider => AndroidSEProvider/src}/com/android/javacard/keymaster/KMUtils.java (100%) delete mode 100644 Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMSEProviderImpl.java delete mode 100644 Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMSEProviderImpl.java create mode 100644 Applet/JCardSimProvider/build.xml create mode 100644 Applet/JCardSimProvider/lib/gpapi-upgrade.jar rename Applet/{ => JCardSimProvider}/lib/hamcrest-core-1.3.jar (100%) rename Applet/{ => JCardSimProvider}/lib/jcardsim-3.0.5-SNAPSHOT.jar (100%) rename Applet/{ => JCardSimProvider}/lib/junit-4.13.jar (100%) rename Applet/{Applet/JCardSimProvider => JCardSimProvider/src}/com/android/javacard/keymaster/KMAttestationCertImpl.java (99%) rename Applet/{Applet/JCardSimProvider => JCardSimProvider/src}/com/android/javacard/keymaster/KMCipher.java (97%) rename Applet/{Applet/JCardSimProvider => JCardSimProvider/src}/com/android/javacard/keymaster/KMCipherImpl.java (97%) rename Applet/{Applet/JCardSimProvider => JCardSimProvider/src}/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java (100%) create mode 100644 Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java rename Applet/{Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java => JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java} (99%) rename Applet/{Applet/JCardSimProvider => JCardSimProvider/src}/com/android/javacard/keymaster/KMOperationImpl.java (100%) rename Applet/{Applet/JCardSimProvider => JCardSimProvider/src}/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java (96%) rename Applet/{Applet/JCardSimProvider => JCardSimProvider/src}/com/android/javacard/keymaster/KMUtils.java (100%) rename Applet/{Applet => JCardSimProvider}/test/com/android/javacard/test/KMFunctionalTest.java (97%) delete mode 100644 Applet/JavaCardKeymaster.scr delete mode 100644 Applet/api_export_files_3.0.5/javacardx/framework/util/intx/javacard/intx.exp delete mode 100644 Applet/api_export_files_3.1.0/java/io/javacard/io.exp delete mode 100644 Applet/api_export_files_3.1.0/java/lang/javacard/lang.exp delete mode 100644 Applet/api_export_files_3.1.0/java/rmi/javacard/rmi.exp delete mode 100644 Applet/api_export_files_3.1.0/javacardx/apdu/javacard/apdu.exp delete mode 100644 Applet/default.output delete mode 100644 Applet/powerdown.scr delete mode 100644 Applet/powerup.scr rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMArray.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMAttestationCert.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMBoolTag.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMByteBlob.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMByteTag.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMDecoder.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMEncoder.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMEnum.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMEnumArrayTag.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMEnumTag.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMError.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMException.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMHardwareAuthToken.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMHmacSharingParameters.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMInteger.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMIntegerArrayTag.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMIntegerTag.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMKeyCharacteristics.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMKeyParameters.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMKeymasterApplet.java (99%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMOperation.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMOperationState.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMRepository.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMSEProvider.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMTag.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMType.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMUpgradable.java (100%) rename Applet/{Applet => }/src/com/android/javacard/keymaster/KMVerificationToken.java (100%) diff --git a/Applet/JavaCardKeymaster.opt b/Applet/AndroidSEProvider/AndroidSE_3_0_5.opt similarity index 61% rename from Applet/JavaCardKeymaster.opt rename to Applet/AndroidSEProvider/AndroidSE_3_0_5.opt index 77c1931e..ba998254 100644 --- a/Applet/JavaCardKeymaster.opt +++ b/Applet/AndroidSEProvider/AndroidSE_3_0_5.opt @@ -1,5 +1,5 @@ -out EXP JCA CAP --exportpath api_export_files_3.1.0 --applet 0xa0:0x0:0x0:0x0:0x62:0x3:0x1:0xc:0x1:0x1 com.android.javacard.keymaster.KMKeymasterApplet +-exportpath ../../AndroidSEProvider/api_export_files_3.0.5 +-applet 0xa0:0x0:0x0:0x0:0x62:0x3:0x1:0xc:0x1:0x1 com.android.javacard.keymaster.KMAndroidSEApplet com.android.javacard.keymaster 0xa0:0x0:0x0:0x0:0x62:0x3:0x1:0xc:0x1 1.0 diff --git a/Applet/AndroidSEProvider/AndroidSE_3_1_0.opt b/Applet/AndroidSEProvider/AndroidSE_3_1_0.opt new file mode 100644 index 00000000..3de07eb5 --- /dev/null +++ b/Applet/AndroidSEProvider/AndroidSE_3_1_0.opt @@ -0,0 +1,5 @@ +-out EXP JCA CAP +-exportpath ../../AndroidSEProvider/api_export_files_3.1.0 +-applet 0xa0:0x0:0x0:0x0:0x62:0x3:0x1:0xc:0x1:0x1 com.android.javacard.keymaster.KMAndroidSEApplet +com.android.javacard.keymaster +0xa0:0x0:0x0:0x0:0x62:0x3:0x1:0xc:0x1 1.0 diff --git a/Applet/AndroidSEProvider/api_export_files_3.0.5/java/io/javacard/io.exp b/Applet/AndroidSEProvider/api_export_files_3.0.5/java/io/javacard/io.exp new file mode 100644 index 0000000000000000000000000000000000000000..931133af56f823aa1846e3a8dab5097b4202ae0a GIT binary patch literal 212 zcmZShb?P1?69XS31Dj1|US^3MBLlOBW*Cs0T3DKxQ_RR9s^OEBSeB@tlbDyT@1K;F znp|S78O6vT3>MAI*Z1^ytw>HSD9OyvV`pGtWDr1C&d$IFQw}yHB%>(5JTWOJm7ReD zMFPnjE=C4+s0F-?3_J{s>}W(IZ!P6lqEC{Pe60>+F$HZuU5 Cc`vd6 literal 0 HcmV?d00001 diff --git a/Applet/AndroidSEProvider/api_export_files_3.0.5/java/lang/javacard/lang.exp b/Applet/AndroidSEProvider/api_export_files_3.0.5/java/lang/javacard/lang.exp new file mode 100644 index 0000000000000000000000000000000000000000..f34981865d8e0cab8c21ed73c4bae3ff537d147d GIT binary patch literal 881 zcmaLS%}&BV5C`xX3Y7ApDB=ew7d*g;2hf-x@nB-ai1FZUDJv`~t+rbPpT_6$A$$-| z4n*A*$u?=TyZ_(JPT}+Y0~1g~NS_K{$TI}1(Y&WEe~y_KA(R_eV>V?ikNLw^w?F2t zJZU~46jx7eNFtQf>D?#{URdAbHl+Uq7c-YXNfG!qWDqK<;x_iBm~bu6BGgrW=@0m< z8_VwFc@X=9NP~HVhJx)dWOIYwKsZ+Vnh%*2Q@*U~iC2AqB0^1*vFF_c!k0YM?%qZ? zRHoyxDC)3CYGMcBNQrhRaBa5b`vP*tSI-I&x|1N$pI=ns1`2=!qr2+nVh0!;;I zzX3oWs5TGuP0@~?#A3aCk=7Q{&i+YPvILzwgi<8_S6Y?B+5qNkk~VdEQtf7$dRZT#TS56o4f!3 literal 0 HcmV?d00001 diff --git a/Applet/AndroidSEProvider/api_export_files_3.0.5/java/rmi/javacard/rmi.exp b/Applet/AndroidSEProvider/api_export_files_3.0.5/java/rmi/javacard/rmi.exp new file mode 100644 index 0000000000000000000000000000000000000000..209cdf37f8ca4652fe85fc78ee82d9a6d17d75f5 GIT binary patch literal 280 zcmZ8cNeaS15Uid=CoVBAC_X_?d4S^0gCGP%Jb0UgK}WK<$)wiHBe-eBNHG=aFa!qv* jzXAwhp~280^Nwk3nEWw93ARBMxbSj{<*bcDK8oN^-L^l| literal 0 HcmV?d00001 diff --git a/Applet/api_export_files_3.0.5/javacard/framework/javacard/framework.exp b/Applet/AndroidSEProvider/api_export_files_3.0.5/javacard/framework/javacard/framework.exp similarity index 76% rename from Applet/api_export_files_3.0.5/javacard/framework/javacard/framework.exp rename to Applet/AndroidSEProvider/api_export_files_3.0.5/javacard/framework/javacard/framework.exp index f604261ab9fed54e27ecb373befde7fb62496b03..fd14eac73b233cbc5bd7a78bfb20d2967abf1535 100644 GIT binary patch delta 120 zcmV-;0Ehp~L6|`Z0Q$<_0RjO=u?V>o0Y#JF6c@Ai6kr0ASQi|Vbr&j=pchD!=@(H6 z0uBKHYXAWN1(QV>M3agbH?zVRaRHMw8nBb)8dj4$8&8vr8(XvJ8zKUe3m!F-K^|L^ aogO%o)*d;N5FekDupf?-KOjDnejrVudnpe9 delta 208 zcmbQ?c*c=~;n%5q%uI|P8##80m@;r?C6*=X=OpH(^D;2HF)*?(U|?WKVqj!+Wn^?0 z7h+>%U}j)sUSDHcXBwfTlfBGY6Gaal%&$)Vy}K(b!k14teh59DTG;$vjU25XtD zDB;4$HaS(ooRN9+9En0kM#jm!QX3eVC-0RCW8|DHEbR{zNs^9cW)b@U delta 161 zcmcaAwo9CY;n%5q%uEbr8#$J;$1^f;W+j#->gOcprSmc{6fiKdFJNF`NMc}QWDo+$ zBqtW7=%*DW=BAeC7i9yL6tO{-FaniufHfE8W&$Nj;Ch)E@|hV58HyQ7C$DE$VPu$m snSCRWY~fG^k}EmpFbYq0<=nw2GWjp34kP1aO|BY7*2zn`HZU>+04SR%d;kCd diff --git a/Applet/api_export_files_3.0.5/javacard/security/javacard/security.exp b/Applet/AndroidSEProvider/api_export_files_3.0.5/javacard/security/javacard/security.exp similarity index 67% rename from Applet/api_export_files_3.0.5/javacard/security/javacard/security.exp rename to Applet/AndroidSEProvider/api_export_files_3.0.5/javacard/security/javacard/security.exp index 9b2b8d44e2be09edadc03b0339ef17ec75dbef8a..39e57627c07c2de27b3281817dd8f2969a05242a 100644 GIT binary patch delta 186 zcmV;r07d_uak+2^0Q$<_0RjQuu?X=W0o{{4AS(p~1_1yKk|8IPl^{5i&LAw4`yecn zC?PnLVIgRf${}czGa`4Bt0Je9QzNI7`y)IB3I+iHMv^2glWHUi1sDba07#M~F9<{h z1OWg*06~+oBxsWxC1{g`C3KVdB}$V-CQ6f!COnhOCO@+bC)5Fx;V4LxDk(^lb16}i o#VL-HR4UQ4CM$Uclb|uBlSVQ@lZY~&vnMl>1e3ZqfRj5oVGhqgTn=Vf5L$H2(GfPsM_iGh)kK?o$1 zoLH2ipH`HZn_8Y=(oo@tU|~tc44`Bqn0%>N4rC`NEeDe9${=!`vJH@YrEJ5-AOY0sG1*?t z94L^a0@8E}Od6?{0NKk_y@2EgFlnU*(p08q&&aTOtJ)PtMz+bF8Xk=7lP`ivNzFh; zj>%b?eT>YLe`sE0WZ8UDtCEe8ak7))(#g*Zoq)ZxQA&k=VnIr&zH3EEYFw26s>;n%5qj7$vt6FJ^9G4M?mW3&VSUEK!0 delta 53 zcmdnQbb*P3;n%5q%uEb|6FJ_?Gcs^yC6*=X=OpH(^D;2-Gcd9*U|?WKVqj$8V`LDR J_|uY+5de+Z40Zqj diff --git a/Applet/api_export_files_3.0.5/javacardx/biometry/javacard/biometry.exp b/Applet/AndroidSEProvider/api_export_files_3.0.5/javacardx/biometry/javacard/biometry.exp similarity index 60% rename from Applet/api_export_files_3.0.5/javacardx/biometry/javacard/biometry.exp rename to Applet/AndroidSEProvider/api_export_files_3.0.5/javacardx/biometry/javacard/biometry.exp index f1779d016da9735f899862ec80f917983670c7cb..fb46fa306f4a42a95473efc641b5ca5ed90ee7db 100644 GIT binary patch delta 51 zcmV-30L=fD63!6_0Q$<_0RjMQu?UF;3<3cMpa1{>VgdpHYm?svaFb95Ym>YNQIie_ JjnI8}&);n%5q%uEag8#y{z{g@fq7cej|Br!2DGH_-kmL=-vB<7{_GBD&YKxG&h z85x8?GRcWWDf($eiMgre`9;}4C3$R6B|sI~ObodU`IG0e7BDhQ=4HzUk`-)$K=LG8 OA0zYTaQ1RWMn(X~;vNYA diff --git a/Applet/api_export_files_3.0.5/javacardx/biometry1toN/javacard/biometry1toN.exp b/Applet/AndroidSEProvider/api_export_files_3.0.5/javacardx/biometry1toN/javacard/biometry1toN.exp similarity index 68% rename from Applet/api_export_files_3.0.5/javacardx/biometry1toN/javacard/biometry1toN.exp rename to Applet/AndroidSEProvider/api_export_files_3.0.5/javacardx/biometry1toN/javacard/biometry1toN.exp index 057adb00a009505e43ecffe6a3ad0e83edb0d7bf..88527985087cd014f537d679fa0cf756e3b2eabd 100644 GIT binary patch delta 53 zcmV-50LuT?7>pPQ0Q$<_0RjMiu?YGH0swuJMhJeB#Rwyl=?HR@TnRdpmkD2!_X#Jn L9}0y5lcfu=53m!W delta 145 zcmeB?xF*5D@axn)W+sNFjU2z&T^JcSvl7b^^>Y&Q(s>ye>KGW=7cej|Brz~DG6;cW zk`s$k^wWwGb5qOni?V@A8rYypfGTR480r}sC$n(WaWgQoF*3+AFfvFpOy0*S$;dEy lDMt~I6z8-8l7XD@Kym}8IwQm8>zu8OjEs|GxHm8|0|1MgB1r%M diff --git a/Applet/api_export_files_3.0.5/javacardx/crypto/javacard/crypto.exp b/Applet/AndroidSEProvider/api_export_files_3.0.5/javacardx/crypto/javacard/crypto.exp similarity index 92% rename from Applet/api_export_files_3.0.5/javacardx/crypto/javacard/crypto.exp rename to Applet/AndroidSEProvider/api_export_files_3.0.5/javacardx/crypto/javacard/crypto.exp index b6f6b2f83da87606ab49df7ed07dad9429f5c6dd..e1ff132d004f074ac6ad0191ce7627df1421b50c 100644 GIT binary patch delta 37 tcmX>p(;~yc@axn)Mka=yjU09YzzvGbI%)@EQGTDhYZ1POr^#Jo940iwk delta 110 zcmZpXIVr=z@axn)W+sLS8#xwpI5RSEW+j#->gOcprSmc{^e`~8FJNF`NMc}QWDo?& zBqtW7=ohCZmlkD~R037>u|ZWZGBI>BG4wL@PhQI*%gC_#6o)AbBgf?bJYkHSlS6se HGx7ice|#LZ diff --git a/Applet/api_export_files_3.0.5/javacardx/external/javacard/external.exp b/Applet/AndroidSEProvider/api_export_files_3.0.5/javacardx/external/javacard/external.exp similarity index 67% rename from Applet/api_export_files_3.0.5/javacardx/external/javacard/external.exp rename to Applet/AndroidSEProvider/api_export_files_3.0.5/javacardx/external/javacard/external.exp index cd85799e0e854dbdb1d3f7f99d920173d6799dd6..4af91e53addd3e0a22b689258f9ddfbd0055a81b 100644 GIT binary patch delta 57 zcmbQoev^%Z;n%5qj7$vL8#y|d8Q2&ZSQ!`@*cpI;iGhU?NHH=3DJBNy$)A|) JCL1#6001|+2@3!K delta 128 zcmcb~HjkZy;n%5q%uEdW8#y|dk{B5{vl7b^^>Y&Q(s>yev>6!L7cej|Brz~DG6;cW zk`s$k^wWwGb5qOni?V@AblIRvfGV_@7<3r)m>Jj@8CV$@8Q6h38JHMY7=aWcBamWZ TU}l)Sp2?1paq?TH97bjUKc^Rl diff --git a/Applet/api_export_files_3.1.0/javacardx/framework/math/javacard/math.exp b/Applet/AndroidSEProvider/api_export_files_3.0.5/javacardx/framework/math/javacard/math.exp similarity index 63% rename from Applet/api_export_files_3.1.0/javacardx/framework/math/javacard/math.exp rename to Applet/AndroidSEProvider/api_export_files_3.0.5/javacardx/framework/math/javacard/math.exp index af2f608c931da886a746ffe29acf78ff7bc25e44..89a1ac6c55c95a8554309066ac86f73d930477be 100644 GIT binary patch delta 32 ocmX@ZwuX&^;n%5qj7$vL8#%0*m>9GsCox$~p3BrVS%X;_0Ht9GO#lD@ delta 65 zcmZ3(c7~0E;n%5q%uEcr8#%0*Y&Q(s>yev>6!L7cej|Brz~DXfZPA VOm=0mnq0@!&B#5OlUbRO5dau%4i5kT diff --git a/Applet/api_export_files_3.0.5/javacardx/framework/string/javacard/string.exp b/Applet/AndroidSEProvider/api_export_files_3.0.5/javacardx/framework/string/javacard/string.exp similarity index 67% rename from Applet/api_export_files_3.0.5/javacardx/framework/string/javacard/string.exp rename to Applet/AndroidSEProvider/api_export_files_3.0.5/javacardx/framework/string/javacard/string.exp index ef6c5cb778fcd3a50544855adee50933e1eec24f..7a3b73c3781afdb18424e6ca199806ef0e3bff87 100644 GIT binary patch delta 29 lcmbQmbB&vW;n%5qj7$uH8#y#sm>2>km$2k+e#BzV2mp^22?hWF delta 99 zcmcb{J&T8f;n%5q%uEcS8#y#sTo@TRvl7b^^>Y&Q(s>ye0vQQEfO36 delta 128 zcmX>s-Xp=m@axn)W+sN>jU3O}T^JcSvl7b^^>Y&Q(s>ye@);P}7cej|Brz~DG6;cW zk`s$k^wWwGb5qOni?V@A3fZ7afGYBs7z!AQCVym)VPu=^%khMfW3nM<10&DmjhtbO WoRitPiWs>jS8{>a=efQxG6MjxDItRZ diff --git a/Applet/AndroidSEProvider/api_export_files_3.0.5/javacardx/framework/util/intx/javacard/intx.exp b/Applet/AndroidSEProvider/api_export_files_3.0.5/javacardx/framework/util/intx/javacard/intx.exp new file mode 100644 index 0000000000000000000000000000000000000000..881a9612d59a35ba904ff74d3d0e24d68bf58c35 GIT binary patch literal 309 zcmaKkJ5mBc5QhI=V26hf2nY;}NM@rsfRSsomQ@Bz1W|({wXh83?4WoX&*LFHh><;N zL_jBB*Z;!z=NBay5!9A9ws1i{oy%nfp`*((GF{p5Yo&Ug|0&JCqM}k{C1D%~rk-6> zSr_BC-t)VZb(v@LxME-STsM-`4{Ls9Q?px{$Hm$%!%a3LOrpAE|8y|Vp11aG=Qm~_ zs@ha89L)WlKw&@_9@iDl3D+m<61W8QJ^(C|F3AW1BbgOcprSmc{s53CKFJNF`NMc}QWDo+$ rBqtW7=%*DW=BAeC7i9yLXtF_-09B|lF=#MoP2R-hIQbJ(G$S(ruNN03 diff --git a/Applet/api_export_files_3.1.0/javacardx/security/javacard/security.exp b/Applet/AndroidSEProvider/api_export_files_3.0.5/javacardx/security/javacard/security.exp similarity index 59% rename from Applet/api_export_files_3.1.0/javacardx/security/javacard/security.exp rename to Applet/AndroidSEProvider/api_export_files_3.0.5/javacardx/security/javacard/security.exp index 30b3ed6eae5e8f897e6f7d6e10db414970c2e70c..5153a68de41361ac16c3e58ba895715a58a0dd5c 100644 GIT binary patch delta 24 ecmdnUJeiq;;n%5qj7$t78##1=lY&Q(s>yeL>L&^7cej|Brz~D2s1K> LPBv$ZVPpgVc$o_k diff --git a/Applet/AndroidSEProvider/api_export_files_3.0.5/org/globalplatform/upgrade/javacard/upgrade.exp b/Applet/AndroidSEProvider/api_export_files_3.0.5/org/globalplatform/upgrade/javacard/upgrade.exp new file mode 100644 index 0000000000000000000000000000000000000000..110117b209c2942b965fba795e5525112ff65f6f GIT binary patch literal 1705 zcmc&!+g8&+6y4KXD7^)wB8WFcNEEGiQM^&;TC!G4YlFDJ2i6dV5(r66Qe6Ix-{VL4 zA-?FDv{k5D>yxVwJF|Oc&pG>?8GQZxg+=g^A+^3)D{ULAm0G#Pz={l+W!Lco?gSg$ zZiy%W)(xvH)oP^`Nktga#_CpSyI8H3OG|6C)nG`rsm*ng8VcZb_en+JQYcT{LK8y?>kg_13fgcB^v$l}0}#(J;neNiqcfEii+g-O$V;Hg=E2s;;8wzZY zu^uf>if&O*$c2J*3biCDiH_v3{O-z)Y5K1vwU4cz)J;(yArXqoq~)rkD3g}UuITjN z8>HY0gW7ARf~yR&^2&vYnRK$&i6UD>bz->Z`tw#;RsJbff{T1ZQ61g z3=`x^%@fC#+wyDNJmd|rAw1u5X_CgxePJH<{JXTe!k}pHibheVk;s^yphP+)GU!^- z7QAxy35Me|D%IS!q zULtvdh+_mXdeo3&A*3TAWTGKtV+1*05wZ+5o(U$5>%DoGE_#DX_V=VED$6}^nXZWgpR$2sZoMiWFwT+ZJ88h zMAj0i()V + } + + .interface public abstract Element 0 { + + .fields { + public static final byte TYPE_SIMPLE = 1; // B + public static final byte TYPE_MAPPED = 2; // B + public static final short SIZE_BOOLEAN = 1; // S + public static final short SIZE_BYTE = 1; // S + public static final short SIZE_SHORT = 2; // S + } + + .method public abstract write(Z)Lorg/globalplatform/upgrade/Element; 0 { + } + + .method public abstract write(B)Lorg/globalplatform/upgrade/Element; 1 { + } + + .method public abstract write(S)Lorg/globalplatform/upgrade/Element; 2 { + } + + .method public abstract write(Ljava/lang/Object;)Lorg/globalplatform/upgrade/Element; 3 { + .descriptor Ljava/lang/Object; 0.0; + + } + + .method public abstract canWriteBoolean()S 4 { + } + + .method public abstract canWriteByte()S 5 { + } + + .method public abstract canWriteShort()S 6 { + } + + .method public abstract canWriteObject()S 7 { + } + + .method public abstract initRead()V 8 { + } + + .method public abstract readBoolean()Z 9 { + } + + .method public abstract readByte()B 10 { + } + + .method public abstract readShort()S 11 { + } + + .method public abstract readObject()Ljava/lang/Object; 12 { + .descriptor Ljava/lang/Object; 0.0; + + } + + .method public abstract canReadBoolean()S 13 { + } + + .method public abstract canReadByte()S 14 { + } + + .method public abstract canReadShort()S 15 { + } + + .method public abstract canReadObject()S 16 { + } + + } + + .interface public abstract MappedElement 1 { + + .superInterfaces { + Element; + } + + .method public abstract write(Z)Lorg/globalplatform/upgrade/Element; 0 { + } + + .method public abstract write(B)Lorg/globalplatform/upgrade/Element; 1 { + } + + .method public abstract write(S)Lorg/globalplatform/upgrade/Element; 2 { + } + + .method public abstract write(Ljava/lang/Object;)Lorg/globalplatform/upgrade/Element; 3 { + .descriptor Ljava/lang/Object; 0.0; + + } + + .method public abstract canWriteBoolean()S 4 { + } + + .method public abstract canWriteByte()S 5 { + } + + .method public abstract canWriteShort()S 6 { + } + + .method public abstract canWriteObject()S 7 { + } + + .method public abstract initRead()V 8 { + } + + .method public abstract readBoolean()Z 9 { + } + + .method public abstract readByte()B 10 { + } + + .method public abstract readShort()S 11 { + } + + .method public abstract readObject()Ljava/lang/Object; 12 { + .descriptor Ljava/lang/Object; 0.0; + + } + + .method public abstract canReadBoolean()S 13 { + } + + .method public abstract canReadByte()S 14 { + } + + .method public abstract canReadShort()S 15 { + } + + .method public abstract canReadObject()S 16 { + } + + .method public abstract getMappedObject()Ljava/lang/Object; 17 { + .descriptor Ljava/lang/Object; 0.0; + + } + + .method public abstract setMappedObject(Ljava/lang/Object;)Lorg/globalplatform/upgrade/Element; 18 { + .descriptor Ljava/lang/Object; 0.0; + + } + + } + + .interface public abstract OnUpgradeListener 2 { + + .method public abstract onSave()Lorg/globalplatform/upgrade/Element; 0 { + } + + .method public abstract onCleanup()V 1 { + } + + .method public abstract onRestore(Lorg/globalplatform/upgrade/Element;)V 2 { + } + + .method public abstract onConsolidate()V 3 { + } + + } + + .class public final UpgradeManager 3 extends 0.0 { // extends java/lang/Object + + .publicMethodTable 1 { + equals(Ljava/lang/Object;)Z; + } + + .packageMethodTable 0 { + } + + .method private ()V { + .stack 1; + .locals 0; + + L0: aload_0; + invokespecial 0; // java/lang/Object.()V + return; + } + + .method public static isUpgrading()Z 0 { + .stack 1; + .locals 0; + + L0: sconst_0; + sreturn; + } + + .method public static getPreviousPackageVersion()S 1 { + .stack 1; + .locals 0; + + L0: sconst_0; + sreturn; + } + + .method public static checkPreviousPackageAID([BSB)Z 2 { + .stack 1; + .locals 0; + + L0: sconst_0; + sreturn; + } + + .method public static createElement(BSS)Lorg/globalplatform/upgrade/Element; 3 { + .stack 1; + .locals 0; + + L0: aconst_null; + areturn; + } + + .method public static matchMappedElement(Ljava/lang/Object;)Lorg/globalplatform/upgrade/MappedElement; 4 { + .stack 1; + .locals 0; + + .descriptor Ljava/lang/Object; 0.0; + + L0: aconst_null; + areturn; + } + + .method public static nonNullReference()Ljava/lang/Object; 5 { + .stack 1; + .locals 0; + + .descriptor Ljava/lang/Object; 0.0; + + L0: aconst_null; + areturn; + } + + } + +} diff --git a/Applet/api_export_files_3.0.5/java/io/javacard/io.exp b/Applet/AndroidSEProvider/api_export_files_3.1.0/java/io/javacard/io.exp similarity index 100% rename from Applet/api_export_files_3.0.5/java/io/javacard/io.exp rename to Applet/AndroidSEProvider/api_export_files_3.1.0/java/io/javacard/io.exp diff --git a/Applet/api_export_files_3.0.5/java/lang/javacard/lang.exp b/Applet/AndroidSEProvider/api_export_files_3.1.0/java/lang/javacard/lang.exp similarity index 100% rename from Applet/api_export_files_3.0.5/java/lang/javacard/lang.exp rename to Applet/AndroidSEProvider/api_export_files_3.1.0/java/lang/javacard/lang.exp diff --git a/Applet/api_export_files_3.0.5/java/rmi/javacard/rmi.exp b/Applet/AndroidSEProvider/api_export_files_3.1.0/java/rmi/javacard/rmi.exp similarity index 100% rename from Applet/api_export_files_3.0.5/java/rmi/javacard/rmi.exp rename to Applet/AndroidSEProvider/api_export_files_3.1.0/java/rmi/javacard/rmi.exp diff --git a/Applet/api_export_files_3.1.0/javacard/framework/javacard/framework.exp b/Applet/AndroidSEProvider/api_export_files_3.1.0/javacard/framework/javacard/framework.exp similarity index 100% rename from Applet/api_export_files_3.1.0/javacard/framework/javacard/framework.exp rename to Applet/AndroidSEProvider/api_export_files_3.1.0/javacard/framework/javacard/framework.exp diff --git a/Applet/api_export_files_3.1.0/javacard/framework/service/javacard/service.exp b/Applet/AndroidSEProvider/api_export_files_3.1.0/javacard/framework/service/javacard/service.exp similarity index 100% rename from Applet/api_export_files_3.1.0/javacard/framework/service/javacard/service.exp rename to Applet/AndroidSEProvider/api_export_files_3.1.0/javacard/framework/service/javacard/service.exp diff --git a/Applet/api_export_files_3.1.0/javacard/security/javacard/security.exp b/Applet/AndroidSEProvider/api_export_files_3.1.0/javacard/security/javacard/security.exp similarity index 100% rename from Applet/api_export_files_3.1.0/javacard/security/javacard/security.exp rename to Applet/AndroidSEProvider/api_export_files_3.1.0/javacard/security/javacard/security.exp diff --git a/Applet/api_export_files_3.0.5/javacardx/apdu/javacard/apdu.exp b/Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/apdu/javacard/apdu.exp similarity index 100% rename from Applet/api_export_files_3.0.5/javacardx/apdu/javacard/apdu.exp rename to Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/apdu/javacard/apdu.exp diff --git a/Applet/api_export_files_3.0.5/javacardx/apdu/util/javacard/util.exp b/Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/apdu/util/javacard/util.exp similarity index 100% rename from Applet/api_export_files_3.0.5/javacardx/apdu/util/javacard/util.exp rename to Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/apdu/util/javacard/util.exp diff --git a/Applet/api_export_files_3.1.0/javacardx/biometry/javacard/biometry.exp b/Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/biometry/javacard/biometry.exp similarity index 100% rename from Applet/api_export_files_3.1.0/javacardx/biometry/javacard/biometry.exp rename to Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/biometry/javacard/biometry.exp diff --git a/Applet/api_export_files_3.1.0/javacardx/biometry1toN/javacard/biometry1toN.exp b/Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/biometry1toN/javacard/biometry1toN.exp similarity index 100% rename from Applet/api_export_files_3.1.0/javacardx/biometry1toN/javacard/biometry1toN.exp rename to Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/biometry1toN/javacard/biometry1toN.exp diff --git a/Applet/api_export_files_3.1.0/javacardx/crypto/javacard/crypto.exp b/Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/crypto/javacard/crypto.exp similarity index 100% rename from Applet/api_export_files_3.1.0/javacardx/crypto/javacard/crypto.exp rename to Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/crypto/javacard/crypto.exp diff --git a/Applet/api_export_files_3.1.0/javacardx/external/javacard/external.exp b/Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/external/javacard/external.exp similarity index 100% rename from Applet/api_export_files_3.1.0/javacardx/external/javacard/external.exp rename to Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/external/javacard/external.exp diff --git a/Applet/api_export_files_3.1.0/javacardx/framework/event/javacard/event.exp b/Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/framework/event/javacard/event.exp similarity index 100% rename from Applet/api_export_files_3.1.0/javacardx/framework/event/javacard/event.exp rename to Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/framework/event/javacard/event.exp diff --git a/Applet/api_export_files_3.0.5/javacardx/framework/math/javacard/math.exp b/Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/framework/math/javacard/math.exp similarity index 100% rename from Applet/api_export_files_3.0.5/javacardx/framework/math/javacard/math.exp rename to Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/framework/math/javacard/math.exp diff --git a/Applet/api_export_files_3.1.0/javacardx/framework/nio/javacard/nio.exp b/Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/framework/nio/javacard/nio.exp similarity index 100% rename from Applet/api_export_files_3.1.0/javacardx/framework/nio/javacard/nio.exp rename to Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/framework/nio/javacard/nio.exp diff --git a/Applet/api_export_files_3.1.0/javacardx/framework/string/javacard/string.exp b/Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/framework/string/javacard/string.exp similarity index 100% rename from Applet/api_export_files_3.1.0/javacardx/framework/string/javacard/string.exp rename to Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/framework/string/javacard/string.exp diff --git a/Applet/api_export_files_3.1.0/javacardx/framework/time/javacard/time.exp b/Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/framework/time/javacard/time.exp similarity index 100% rename from Applet/api_export_files_3.1.0/javacardx/framework/time/javacard/time.exp rename to Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/framework/time/javacard/time.exp diff --git a/Applet/api_export_files_3.1.0/javacardx/framework/tlv/javacard/tlv.exp b/Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/framework/tlv/javacard/tlv.exp similarity index 100% rename from Applet/api_export_files_3.1.0/javacardx/framework/tlv/javacard/tlv.exp rename to Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/framework/tlv/javacard/tlv.exp diff --git a/Applet/api_export_files_3.1.0/javacardx/framework/util/intx/javacard/intx.exp b/Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/framework/util/intx/javacard/intx.exp similarity index 100% rename from Applet/api_export_files_3.1.0/javacardx/framework/util/intx/javacard/intx.exp rename to Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/framework/util/intx/javacard/intx.exp diff --git a/Applet/api_export_files_3.1.0/javacardx/framework/util/javacard/util.exp b/Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/framework/util/javacard/util.exp similarity index 100% rename from Applet/api_export_files_3.1.0/javacardx/framework/util/javacard/util.exp rename to Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/framework/util/javacard/util.exp diff --git a/Applet/api_export_files_3.1.0/javacardx/security/cert/javacard/cert.exp b/Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/security/cert/javacard/cert.exp similarity index 100% rename from Applet/api_export_files_3.1.0/javacardx/security/cert/javacard/cert.exp rename to Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/security/cert/javacard/cert.exp diff --git a/Applet/api_export_files_3.1.0/javacardx/security/derivation/javacard/derivation.exp b/Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/security/derivation/javacard/derivation.exp similarity index 100% rename from Applet/api_export_files_3.1.0/javacardx/security/derivation/javacard/derivation.exp rename to Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/security/derivation/javacard/derivation.exp diff --git a/Applet/api_export_files_3.0.5/javacardx/security/javacard/security.exp b/Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/security/javacard/security.exp similarity index 100% rename from Applet/api_export_files_3.0.5/javacardx/security/javacard/security.exp rename to Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/security/javacard/security.exp diff --git a/Applet/api_export_files_3.1.0/javacardx/security/util/javacard/util.exp b/Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/security/util/javacard/util.exp similarity index 100% rename from Applet/api_export_files_3.1.0/javacardx/security/util/javacard/util.exp rename to Applet/AndroidSEProvider/api_export_files_3.1.0/javacardx/security/util/javacard/util.exp diff --git a/Applet/AndroidSEProvider/build.xml b/Applet/AndroidSEProvider/build.xml new file mode 100644 index 00000000..04b1dee6 --- /dev/null +++ b/Applet/AndroidSEProvider/build.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Applet/lib/gpapi-upgrade.jar b/Applet/AndroidSEProvider/lib/gpapi-upgrade.jar similarity index 100% rename from Applet/lib/gpapi-upgrade.jar rename to Applet/AndroidSEProvider/lib/gpapi-upgrade.jar diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java new file mode 100644 index 00000000..1d24f580 --- /dev/null +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java @@ -0,0 +1,71 @@ +package com.android.javacard.keymaster; + +import org.globalplatform.upgrade.Element; +import org.globalplatform.upgrade.OnUpgradeListener; +import org.globalplatform.upgrade.UpgradeManager; + +public class KMAndroidSEApplet extends KMKeymasterApplet implements OnUpgradeListener { + + KMAndroidSEApplet(){ + super(new KMAndroidSEProvider(true)); + } + /** + * Installs this applet. + * + * @param bArray the array containing installation parameters + * @param bOffset the starting offset in bArray + * @param bLength the length in bytes of the parameter data in bArray + */ + public static void install(byte[] bArray, short bOffset, byte bLength) { + new KMAndroidSEApplet().register(bArray, (short) (bOffset + 1), bArray[bOffset]); + } + + @Override + public void onCleanup() { + } + + @Override + public void onConsolidate() { + } + + @Override + public void onRestore(Element element) { + element.initRead(); + provisionStatus = element.readByte(); + keymasterState = element.readByte(); + repository.onRestore(element); + seProvider.onRestore(element); + } + + @Override + public Element onSave() { + // SEProvider count + short primitiveCount = seProvider.getBackupPrimitiveByteCount(); + short objectCount = seProvider.getBackupObjectCount(); + //Repository count + primitiveCount += repository.getBackupPrimitiveByteCount(); + objectCount += repository.getBackupObjectCount(); + //KMKeymasterApplet count + primitiveCount += computePrimitveDataSize(); + objectCount += computeObjectCount(); + + // Create element. + Element element = UpgradeManager.createElement(Element.TYPE_SIMPLE, + primitiveCount, objectCount); + element.write(provisionStatus); + element.write(keymasterState); + repository.onSave(element); + seProvider.onSave(element); + return element; + } + + private short computePrimitveDataSize() { + // provisionStatus + keymasterState + return (short) 2; + } + + private short computeObjectCount() { + return (short) 0; + } +} + diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java similarity index 99% rename from Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java rename to Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java index d85dd781..db1cd7f5 100644 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/AndroidSEProvider.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java @@ -35,7 +35,7 @@ import javacardx.crypto.AEADCipher; import javacardx.crypto.Cipher; -public class AndroidSEProvider implements KMSEProvider { +public class KMAndroidSEProvider implements KMSEProvider { // static final variables // -------------------------------------------------------------- // P-256 Curve Parameters @@ -157,13 +157,13 @@ public class AndroidSEProvider implements KMSEProvider { //For storing root certificate and intermediate certificates. private byte[] certificateChain; - private static AndroidSEProvider androidSEProvider = null; + private static KMAndroidSEProvider androidSEProvider = null; - public static AndroidSEProvider getInstance() { + public static KMAndroidSEProvider getInstance() { return androidSEProvider; } - public AndroidSEProvider(boolean isUpgrading) { + public KMAndroidSEProvider(boolean isUpgrading) { // Re-usable AES,DES and HMAC keys in persisted memory. aesKeys = new AESKey[2]; aesKeys[KEYSIZE_128_OFFSET] = (AESKey) KeyBuilder.buildKey( diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java similarity index 99% rename from Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java rename to Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java index 77a97b1e..1e50f620 100644 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -889,7 +889,7 @@ public void build() { tbsLength = (short) (tbsLength - tbsOffset); pushSequenceHeader((short) (last - stackPtr)); certStart = stackPtr; - short sigLen = AndroidSEProvider.getInstance() + short sigLen = KMAndroidSEProvider.getInstance() .ecSign256( KMByteBlob.cast(signPriv).getBuffer(), KMByteBlob.cast(signPriv).getStartOff(), @@ -933,7 +933,7 @@ public KMAttestationCert makeUniqueId(byte[] scratchPad, short scratchPadOff, scratchPadOff++; timeOffset = KMByteBlob.instance((short) 32); - appIdOff = AndroidSEProvider.getInstance().hmacSign(key, keyOff, keyLen, + appIdOff = KMAndroidSEProvider.getInstance().hmacSign(key, keyOff, keyLen, scratchPad, /* data */ temp, /* data start */ scratchPadOff, /* data length */ diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java similarity index 86% rename from Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java rename to Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java index 31abede5..727641c0 100644 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java @@ -75,16 +75,16 @@ public short sign(byte[] bytes, short i, short i1, byte[] bytes1, short i2) CryptoException.throwIt(CryptoException.ILLEGAL_USE); // add zeros to the left if (i1 < MAX_NO_DIGEST_MSG_LEN) { - Util.arrayFillNonAtomic(AndroidSEProvider.getInstance().tmpArray, + Util.arrayFillNonAtomic(KMAndroidSEProvider.getInstance().tmpArray, (short) 0, (short) MAX_NO_DIGEST_MSG_LEN, (byte) 0); } Util.arrayCopyNonAtomic(bytes, i, - AndroidSEProvider.getInstance().tmpArray, + KMAndroidSEProvider.getInstance().tmpArray, (short) (MAX_NO_DIGEST_MSG_LEN - i1), i1); - return inst.signPreComputedHash(AndroidSEProvider.getInstance().tmpArray, + return inst.signPreComputedHash(KMAndroidSEProvider.getInstance().tmpArray, (short) 0, (short) MAX_NO_DIGEST_MSG_LEN, bytes1, i2); } finally { - AndroidSEProvider.getInstance().clean(); + KMAndroidSEProvider.getInstance().clean(); } } @@ -102,17 +102,17 @@ public boolean verify(byte[] bytes, short i, short i1, byte[] bytes1, CryptoException.throwIt(CryptoException.ILLEGAL_USE); // add zeros to the left if (i1 < MAX_NO_DIGEST_MSG_LEN) { - Util.arrayFillNonAtomic(AndroidSEProvider.getInstance().tmpArray, + Util.arrayFillNonAtomic(KMAndroidSEProvider.getInstance().tmpArray, (short) 0, (short) MAX_NO_DIGEST_MSG_LEN, (byte) 0); } Util.arrayCopyNonAtomic(bytes, i, - AndroidSEProvider.getInstance().tmpArray, + KMAndroidSEProvider.getInstance().tmpArray, (short) (MAX_NO_DIGEST_MSG_LEN - i1), i1); return inst.verifyPreComputedHash( - AndroidSEProvider.getInstance().tmpArray, (short) 0, + KMAndroidSEProvider.getInstance().tmpArray, (short) 0, (short) MAX_NO_DIGEST_MSG_LEN, bytes1, i2, i3); } finally { - AndroidSEProvider.getInstance().clean(); + KMAndroidSEProvider.getInstance().clean(); } } diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMInstance.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMInstance.java similarity index 100% rename from Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMInstance.java rename to Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMInstance.java diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMOperationImpl.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMOperationImpl.java similarity index 92% rename from Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMOperationImpl.java rename to Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMOperationImpl.java index 2469dd0c..b1f48827 100644 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMOperationImpl.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMOperationImpl.java @@ -103,7 +103,7 @@ public short update(byte[] inputDataBuf, short inputDataStart, @Override public short finish(byte[] inputDataBuf, short inputDataStart, short inputDataLen, byte[] outputDataBuf, short outputDataStart) { - byte[] tmpArray = AndroidSEProvider.getInstance().tmpArray; + byte[] tmpArray = KMAndroidSEProvider.getInstance().tmpArray; short len = 0; try { if (cipherAlg == KMType.AES && blockMode == KMType.GCM) { @@ -175,8 +175,8 @@ public short finish(byte[] inputDataBuf, short inputDataStart, } } } finally { - AndroidSEProvider.getInstance().clean(); - AndroidSEProvider.getInstance().releaseCipherInstance(cipher); + KMAndroidSEProvider.getInstance().clean(); + KMAndroidSEProvider.getInstance().releaseCipherInstance(cipher); resetCipher(); } return len; @@ -190,7 +190,7 @@ public short sign(byte[] inputDataBuf, short inputDataStart, len = signature.sign(inputDataBuf, inputDataStart, inputDataLength, signBuf, signStart); } finally { - AndroidSEProvider.getInstance().releaseSignatureInstance(signature); + KMAndroidSEProvider.getInstance().releaseSignatureInstance(signature); signature = null; } return len; @@ -204,7 +204,7 @@ public boolean verify(byte[] inputDataBuf, short inputDataStart, ret = signature.verify(inputDataBuf, inputDataStart, inputDataLength, signBuf, signStart, signLength); } finally { - AndroidSEProvider.getInstance().releaseSignatureInstance(signature); + KMAndroidSEProvider.getInstance().releaseSignatureInstance(signature); signature = null; } return ret; @@ -214,14 +214,14 @@ public boolean verify(byte[] inputDataBuf, short inputDataStart, public void abort() { // do nothing if (cipher != null) { - AndroidSEProvider.getInstance().releaseCipherInstance(cipher); + KMAndroidSEProvider.getInstance().releaseCipherInstance(cipher); resetCipher(); } if (signature != null) { - AndroidSEProvider.getInstance().releaseSignatureInstance(signature); + KMAndroidSEProvider.getInstance().releaseSignatureInstance(signature); signature = null; } - AndroidSEProvider.getInstance().releaseOperationInstance(this); + KMAndroidSEProvider.getInstance().releaseOperationInstance(this); } @Override diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java similarity index 95% rename from Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java rename to Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java index eb799dfe..71c36a3d 100644 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java @@ -68,8 +68,8 @@ public void update(byte[] bytes, short i, short i1) throws CryptoException { @Override public short sign(byte[] bytes, short i, short i1, byte[] bytes1, short i2) throws CryptoException { - padData(bytes, i, i1, AndroidSEProvider.getInstance().tmpArray, (short) 0); - return inst.doFinal(AndroidSEProvider.getInstance().tmpArray, (short) 0, + padData(bytes, i, i1, KMAndroidSEProvider.getInstance().tmpArray, (short) 0); + return inst.doFinal(KMAndroidSEProvider.getInstance().tmpArray, (short) 0, (short) 256, bytes1, i2); } diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMRsaOAEPEncoding.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsaOAEPEncoding.java similarity index 98% rename from Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMRsaOAEPEncoding.java rename to Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsaOAEPEncoding.java index aa35793f..d4f4cb83 100644 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMRsaOAEPEncoding.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsaOAEPEncoding.java @@ -5,7 +5,6 @@ import javacard.security.CryptoException; import javacard.security.Key; import javacard.security.MessageDigest; -import javacard.security.RSAPrivateKey; import javacardx.crypto.Cipher; public class KMRsaOAEPEncoding extends Cipher { @@ -165,7 +164,7 @@ private void I2OS(short i, byte[] out, short offset) { private short rsaOAEPDecode(byte[] encodedMsg, short encodedMsgOff, short encodedMsgLen, byte[] msg, short offset) { MessageDigest.OneShot md = null; - byte[] tmpArray = AndroidSEProvider.getInstance().tmpArray; + byte[] tmpArray = KMAndroidSEProvider.getInstance().tmpArray; try { short hLen = getDigestLength(); @@ -238,7 +237,7 @@ private short rsaOAEPDecode(byte[] encodedMsg, short encodedMsgOff, if (md != null) md.close(); Util.arrayFillNonAtomic(tmpArray, (short) 0, - AndroidSEProvider.TMP_ARRAY_SIZE, (byte) 0); + KMAndroidSEProvider.TMP_ARRAY_SIZE, (byte) 0); } } } \ No newline at end of file diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMUtils.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java similarity index 100% rename from Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMUtils.java rename to Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java diff --git a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMSEProviderImpl.java b/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMSEProviderImpl.java deleted file mode 100644 index 11778a7d..00000000 --- a/Applet/Applet/AndroidSEProvider/com/android/javacard/keymaster/KMSEProviderImpl.java +++ /dev/null @@ -1,8 +0,0 @@ - -package com.android.javacard.keymaster; - -public class KMSEProviderImpl { - public static KMSEProvider instance(boolean isUpgrading){ - return new AndroidSEProvider(isUpgrading); - } -} diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMSEProviderImpl.java b/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMSEProviderImpl.java deleted file mode 100644 index 43eb2f94..00000000 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMSEProviderImpl.java +++ /dev/null @@ -1,9 +0,0 @@ - -package com.android.javacard.keymaster; - -public class KMSEProviderImpl { - public static KMSEProvider instance(boolean isUpgrading) { - //Ignore isUpgrading flag as JCardSimulator does not support upgrade. - return new KMJcardSimulator(); - } -} diff --git a/Applet/JCardSimProvider/build.xml b/Applet/JCardSimProvider/build.xml new file mode 100644 index 00000000..58343402 --- /dev/null +++ b/Applet/JCardSimProvider/build.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Applet/JCardSimProvider/lib/gpapi-upgrade.jar b/Applet/JCardSimProvider/lib/gpapi-upgrade.jar new file mode 100644 index 0000000000000000000000000000000000000000..e4814bde4b6b21982103c55f9b1a3a4a58f0b807 GIT binary patch literal 12638 zcmbul1yEi~w=IghySuwPgy8P(?(XjHF2UV`gkZtl-Q6KTa3|P<{mahIIXCxKy-7hW zinRvon>~B>izz?0X><$9HtpU3AhEfMm-{hYJV5zg}VnH-}a5?OzDJ zeZRj16ac{6i+L*l^Aljd{nggNl-|_J)Ys zA%jv|s@$PcJ>vU-=zypxIr)I79gt(CMRqYETXUFxgZHlPZdORPeTeAd3ak!pNs7$ zDsU3PfnzxpG(K@0n3_<~R*^JWQ&-Asd;ug~h*%8s?6!<ulJT_AFDwM;coA!sJVdE!jlhf z3Vp9$(%m-{W3W{3Oq>@qRU+0OlYx|sXGdt$V#n|)eGaB7O@?@rhz24mLrnK8rjJ<7 zby1W0Xz|GyaU-XEKg_cXO5ej}###IG&!R*>rDqbNdC}zDx>##9AcZAuOrh318><7Z zQouxNYyD^!JZe^Whz>BcyK9C^{HPABl-^`2iQ)pH1|i*bE%1<4L)R-vXQ4U~;#YoL z=_Lv(6@Z9RvC^ zgUUJs5>8=Lv`?0$!%I3|1BSdF%9~xHtX^Uf8mG9MZs@Ll zG7eI#xJy%$AS5E^$M)MVPcT#5@*ClHDS$ zv_TZ015iVNiIWnw^b|@h;l7P&BJd1M9r6OF>nFFkQ?iQnwM_$677`gRiUq7%l8c}y z21=PfqV*aPOLs{?6#45Z9IV|n=~Q}!6Z(!nLH-XeKhTP`3HR~a(IEo11Z=lD>gmAh zK(SCAdK;gN_D6lTmMoohe4ker&ae|*I-gH%>Ud81{czplOzZBi;d}_krq#L{y350v zPo-aoN?NbHv7416#xs-;g@-@6v>6(Qo3H+Kx0DL@UC(URq&AO9<&n>LmWa_=X^jFN520gYRTy@W(MBwmQbqNs3AY-Mb1Y~%D7Q5LC4 z+wQRaMU-jz;42>qvNYq-s2XY(U)y`&%}JLvz$*b) zkVxCv@oi1i7+;3jAQY?f=ZU zS<`5{Q&$9%s%xn1LW>@t@>xpfqljzr<2>bUI>i{8DhdrGP@)AD28)IjgGC^{3S9jc zmIrYMk9Bv!(&iJOO&CJk7&P^aNBBXOYZ44=Kiklx^gN=V)w4?;wBthM%?Am&nB9i- zN+{JW5`7$pDc}z6-K(NH=Wn@J!Kf`NUeNClUXEK(Cge~TzO6RzLZ;e;rHANfY%*Mz zRZ$+C?VO$SR|m5+tF%79()dOp&ycf}(dMk2uKZ3LYPEZKyc>3uWJbLc^01A;k_iLcI2qM z@~ramR`TfxBrKk74}O=5L+@4-6>!FRNHk-S=Ql*DKt*q??<8_{W{PM~EqvmXgo{Lu zl=fv5C+Iz|Sg^qA_0ai|BZ!)f{Ky;Rk>#2YaUF9u>p6JHe>STofbp~ZZfTg%u)$W0 zo`bHeD5*c#CL}P8lR7~ z7x-cy?Gdq}x^2okGmZL(O{RYI+RR2viTI&CObn#XfxCS#pIj{7@w~` z3^5^cAZ4fNdEWVj>6YaB@WFm=t!W3!z2b1Ww(EFd!}rnHWNDNEu&A!o_A+^~-vED6 z;SqgzFA`3s-Y+jZd*bl0W9XoYqIn0C^RqabNi2r3NQ=@yoKqZ9T^lk|g?Z@7rIU)4 zRZfY>WOv_pLU1>n+}Fw*;ut^ta~^0fp0=%NI1^oLZDl7@Rc@_wg1Wo~;AIBXg7~u; z*wvE@;rc~xM&^~($TQ(P!RZDJksnnC5mWn3t%;>{-pT5_ACqsAS8z3n55a^b>Gds! zH~#AA^0%*IP~PY!73NpEDg2FY$p1_?zY@)fhV@%VhV+6*@Txxrgg%6@OU57B($9Fr z0e6&N7R}LDbXTMnPaTe)Fmg&)SsMKMI5tA}jf7O#-a%TsmmeWRYkYK^`D*kyE?H`Q zFc@i>rZ`e-!boRtdaRzZ*twp8Njdgxqs8~^d~@@K*PcK|=%kj%(K0?+CjFaKQfZ|` z@Ju(R`tmm>1EalqB%3k`{Uqn*Qbw9anUor?WEm)4a&vK5SLi&`SLN`pM3vGibU`S| z?8BM_pKIA>_O460`oFi5W|at=1k-4;dcZk6MUbS<%LuV4E4GIDhNllZf8%$SN#tQ@ zoXVK(FP+}AR11-8#XVGNRjT<23Pp3;Wa>*aqQLDI0+Nrc5N`r@>QBIFzzF22m9K|x^5S`IEQlt^ztG8aybO0wW#v=EmVhZ>4X>5oE+(zs%1$D{b z5CltgkbRv;IY33d3c3^g35^A|E^5#=9hqADd)X##gak0jS1r&x_gqa~3{u=qcs-m0JeVYrBtdl=raw>35au(@L>8K?JTxQYRqL^vexsTs zv@R8h>%LxNVON+czj8dx$*{#H~frD8+}T(F-$ ztSA}#6V=OjH2*|lpOcHm2=cTLlH=75=QE8F)wpDyemG!b21FOO#d zmg$(qcVLHUEcwB517-qMjXSr{1TnW_VmL`IZg_O90k zVCzh&Us74=Wc2k)HQmGZ*f%w)Mz0O3W7ECVpf_gGyAL~=IJ10>WaykHhQTn9xL{MGC(YGN(H&L?P%c-n1&L(1O4DVwhWIIrap-ktK zt|(dXZ0jslRtjYMNM`b#N`0sy+UzbieXY67@*W=W{s)t}; zth!;HTdL8z*(-`iockO;k^p5uK{Y{amO7e~Wl4$9W)2iwz}hB3hImVYf-jugv{i@T z74?H)LxRO8z~g&9|GX&`)pjX4$ii5jjG8u7PcMfeN?NXk99tgv08 zGizp;-2|sd_La{z3?IRd!FR2$UGFm1puw}&S<{Mf>b3EqfrEDk*YRjQfFj-bWP*s@ z5SuIN3E|Nj!*QL>fgnBqk&;PiUotll>l3yRh^AAHZkk=$C)1)cb3ssZ33O)jKzuZ5 zNmRIPkeaN?cxoa256P4@-|TO-S@@-q$_5Ds;$sPABc;>vNMZAJ`8gJwHv`w{p!>w6 z(G}@61vKQ>OLq%Q0gS&#P7U@94$_)(UTGj}R)9rm zP!MMe<;w(sN*`p!i^*uFV0b9a%Zt7)gYke%qWvbtnv%cpptZitL;*#JnNi4&shE-2gyDNj%yjl}DXnc^bY?9hexKG#Dv*W#G95|aXZ)8Geq$NRd#I53i zJS;cQI>p|w9+$C+mdlNT6Q|Q{jwwlt(@KDXU|KAX0)e>EQQt*_Z!_(&LUfs7If^xV zW?m!f=bw=_l#=d7ls4CYFc>;80N-)J(ogNMrg;%tz0Mbk-$B8!$@D{ekX1X3a^Mxy zHGQHXsmi8uczCo8WFQtRbA^wLy7~rtFA_A`L?VwQXyyDVe9I#F>SG0EubomLiLich zu9Vf|y7p-4Mli%&ai_}*4w8UAF%SM}5pN6-qy9w>F(?2z&^*{vWDl_!-%nAE&u)$^ zrBxKr>;wm@%_JT-ZSZl+Og zG)`VnHV%XazuX6& zK}X%kqsV4M@OVe}CG@FX)oh4OSKq=*jf18 zjO;B{tA3}a^X19lH`?m3*VS}1vnnxcuks?diGhKbda`iY9h zyJ+AEbQ*PXz%Qn_Sc1*Uo0Sl{=foSsA`k&_){`N9(GI-{hkU|+&l05;NFRLU|M?c= zL5W0;kwHl|BlE+ZZAf znt5LH%1t_f-KH~}<6_PgErf0T!9#R@&sqpEvkPMvA*LoQvh~A>YcbL158;J<1>1Ho zHX%vr5usSPcn@$lt)9yRJ$yD8=ihoB@5(*E#?)qKSc{^Fj?XvwTQwYk%kN{XVli5gd1>9))a`RL{Ttp* zsA{{)UE_!O62mUH6E}SemRO`ma0vo9saAVl%_{`RWI_*tMBp*h{|@eGKlf?a_T9x1!}q$!4%u2CDNH>sVTv zCp4oLUt3$xSu=-;@7)i2nln4eee&4HTM0No7k3vide%rkVuY!7UD>4|dFU@4)7Fa^ z`VcZt!luHC&Q#(QzTD#!`9@Og5!9_h*uu?jX{N1&{E&<3JGanv7pDK_@T5_A=-JkE z&pOb~$O>bk&6c;!J}CNi2JUBpHhsM35%8vOd?(!5)^jQmg}o)uovV3E-s+OvfOQU0 zoT0JmOPf)})WlCPz)*cMyX(pe+T8oC>pje%Pl3AT_aU~Bg`2Tk_q-R}Ga=-90`P~= zPGt$~*E)%O`-gX9PxWJ-4Eo4av@*EiDp60=SM~S9zC1g+V>d}|?${k-osGbRez*Ir zlONen!RFN6B4cvSybX#CZGdBu6M2oRqi_8`pWuCf(ur=G&^v)fYqG*G+{QaHD&Gtg$7@th4gLS(@?6txj ztvM8@d=bj*f+M>03Y~Gv&M#D@4BCvir~*9o>kc>)pwA% z1aZ9oHISF7)^PgdS?ws=TOmtfV%+veW0bBFUH z#Cb^g5UrjM2L7I=c%$$Gk&U_y_<3iFP{@$zJ(3gma8Jw$J@mCOL;Y3Ri1qkGi}$wh z3HB?#AsGU8-OcXh5TIG}Tq?KZ9v=AJ2Y5ekxChs%$HougujcI=XR|)wS@_clAEwKm;PR&)jxS!?G9K?3xRkl0ld;Xeh4DGnlb97YgePCW4SoBLQ@D^T0NMx?bLcvX$$WD>zha7T zjtC|3VLtM~7T1(QJ{oRUb3~M}oSr2zQ&&?{(;}Tg(J2at_9fQ-liR=@l4Skps)Wa(Fa>e_+{O9nXqBBn~WN|FSdoUoS zVPrq?fw-DsNNYh9m2&v+ni6>Zm%d zuLN%j9Zr>h5dJhTj9?-Y#0>Ks$pPUJXyss_vq)eh&`E0TBozT60jDGXol4s>od~3P zhSkZtnS2UDCfmbRiEj%7y*tJyBuFVa15bvqoNk8rc3iYwqDu9a=3sIsR@MHz3?x(B ztqiMI^^5c7Nj^smsF!>|Wz%3XHFn7K#A1Y)M6NdG1(YTd^2jol69n_yi* z3~i~D-jR4Y3;NwC3V%IUsn*v{tFjUu@zY{eeFpo~PxVH?4J4d8c!Q2w5UTq;;pe0FyGor=ae*u(PT)okp~HS8L60WT&Sdp#W%Bv#*A@az-6Hi0lq_ueujpu3u8-Uno%BI zY5JJ8Z#A8cA~@4OduD|a#lDCIC^+J+jxpj!KG!h6AF~dJL1aQ0MGl=AG~-VjOMU)| zCGD5!cIHI@+#wE4-{?EGyfV6cM(fDk2n96zQly`G= z+#)MWt*d81j~mj329&tj1IO#xOpgr&U>td_bt&dZObwdr9?UpOE{au**_INYhxR2Q zSPf(ALF7`d^wyk6l(OW>vDd*?S#0`4c4U4^Afivp>_#gy^lBvX&-x*5GvF`hBIcig z9UWgJrAg`SZ>3MqQ)gz6(=4^^H`cB>+-(AouRz_`NmX&~KGmJ$N9lT>dZ^KW1!Nd#mhFw|2uak=0$*s7coymJ^H&~t~gzqP`AlvLj4B@UC9-F>BV88R@MP!D3*PA%i z`wuM~@VDbenm_ZSoxY*v+j$|axs8eKUs5=0ETc^i1B|dMa67OmJRFm$c}adosE%I> zMMfA6RN?mZee$f)(-S^?Y^pgHc$%I(=Tah|fE>>Or3X0VCef#Q$IH&LI4~zxDq))4 zJcy*M&3JZU**Ikj%d7)RyYfT=D3@F`yV7+%;R;ppb5!HLCMCHn9KCcLa2GYTgt4p( z`vi^X^RHk1(eF4YlG{tY9EUBFAGF&2iRzDZor-W}(JF_eaM8C#oB5cNpM&-_zyTAip~ImJD&gUzd~LPiN`> zoUY#vSq-i99UY?;ByDH-5wh!NLU<%r>f|(Z_D%r011#l0%|8k_;CIIXqlQK^+c!A7 zRE}{WJ(0oL32b-5Z;BH3!wZW?K=F+pk9%#fb2Go(JPybLxIw{}>-DTLty1@RgGEjR zqnL#HpRjPlNVJrP!ldvLUJziq$an0lg%QEZg7O^M(N23J(xm%iFuLth;x_9SHuFRf z+x(P(Un7BIJ?c~7N@Ur3miCxFc#ncMQ-RI47>#7Bo_~olsRZZ zj~GMGjw{st!6f$M5~t1MiBjKw{y-;}jiP4x27aD?XIKkH9?X~@U6MK!i$h>F5l%h{ z|BU&g&s8fNlo|EOouZU=b-xBoFrwk=PRQdnbDu@IXMq2bvN+W;h66IptvimPt%CW$ zh0J|g3u0=XXIhu$ceLy+Mfc)q-pnbz8lq$#vHSztTloT*1KuApSGI%Y)kwITmhn}# z)-LR_3SPJpHT;SXXVD5b4_w!Y>esPFy6G|`5OpBU-*zz{f(Gh1Zzj?OiZS*RW+m1_t72wvVXkTad*laU?@z_w$~ zm}a|STk!7BJZ%@fb?I-u`m1wMV^uMPd$S|Jyv@$P&+~sTHHtr%+J9u@f7MvRhzt-T zMzHM1Q}heE^}dxF`|a^w)B_A@IS4_98b(m67);Yq4l^%SbUr_LV=Ku40y?9co6Hy9 zla1S}AJ4#@h;o|dZbK1z}2~Y+4k^mvu(k(_^>qF z;n*hXeLj0<7JC>nhL^sR6E=L=o4g;CJfN}X-!8XSETdcPf~U6dA>HoKDV2*oKeYD8 zaugSce&ryy%7^jSE}J9_t?k-^x1U^302r3`B+qSj?M&t4GFZHD}AYIZ##*P+mG{16J?j z^PfBkdOM^++=CeVl!d&AgucZ@A8;%{lK765^gDS74KOnIVe_NKWvYx)j*E>O$T;ZO zf3%mkha5?8|14HzAnl+%W~-;@AbDur7qA^e@L{HkXJ(!KomBW|9vze32*nuqPb2+* zac=zcJo2yc4vyo6>gGoX-snBBP(rx?Q4!xUAXl?Q{c;YHVWbU{fp4(AMZ@D4ip1XA z51|1AY|F=ocjdNz3ZR0)%mE`9f~cQw^bOseu0RlBq=sZvdm^?^*^XABFT=^OQxaRN zWh3*uY4Em$ssH3Rv^`2{B%Qr-g!o-eTIBS3rtfLW!W6Eiw2)s#9^2_G$-ADn9yTFo zT%fzReIxPw_0kX1a@5$mM9>*pz)g?@I>s5@0N-=rPk^H$Srei(pt!bK-%|_R(PFuiut#l0T>F-Qi=X?_l(cW$1T=|I2FjUxa^~kLZlu?D~`}6=(QS zcvn;@tj+kT0`67BP%CZaz2py~M(gU>!hn7BQfiX;7iU@eE;jBxpAcUVIu6$Aj3tym z=VW?uw2-?_tb3lGZa*&A(gZBPl+{OD*pFyXs!9rjspw6n@+`qL!OVYKL6QgfjIE;c zStW8LB7&i?GI?xUB~O786WJ$V^R@G0>OBtUj#5@Q8qIJZWS9fV0-KBq@JORB(1wzVFcR0} zCRbP9OjU7uqR}8wI$Pbx=2|(!zX4ANSvR;mN4iR@KI*KG7uw<=R<=b@rLibd> zBkxFd%&U)o{j9B}ZZbIv4_c8M6J(>f0z4%iPiTtv`D5(!A|d>78*)2S>(fGuodItd z)^uV8?LuX^_7=2xqB!Kmm%cSJ!CTjDCE-()=a^7qx-yU2bIzXGoF3z7kRtjd5dC^)Af|dSh*88DBpi|9`T>qeBL<-jc)E8mx{yZ)AhQiLSkE!he1P6biK9VmVdQNoE(80Op#T5Q z6AMHA6IE^76*d%a6~8BNJ}&wcBXVghTj1^a9-zf~{cn_?ctPr%PHOVRqYKwygkK-& zgok7@;T5$fPYB@(?*+fF_wp%|y+3@Ms^$Dd6 zhZo1m!fTL?g&S&F530+*H}bXhtxli04jK0sV}<{&B||yE$;w=Yw#Ae~{R!})p#z=maSnCI*~oSP_pz7EbM;GJAerW_0;VO%JxL(a)P}GpISXNw!+4s- z9~JacBzPRHC^V^yv#O*E{7H#pcf}}2mm|V{!Gl!)Ln&d0EG1L*x|F^Rl=bkY?W={hWgGaZ zQfRJrZ`;Y;2E4r31)#lQnmTkpGr`0scVCjVDI@jC((!2j9)`!_=O+vOkB%U@sR z-46V#{q4P}{5u}sF8=`Z+rIUE;r|u;-9Y!N*X7+n_ji!Kapxbf|JlC&4*hPH`Blk% zH_QATNpDH|1N49PK)-{&i@?9iAMYaY-+_qnN6`P-V*U>QuA%%Y7rbjIe+MJ(AL0Lp zqVj8^-}ivO?hfA@w7)|S?~lm84dP#o@$cZjZb;rYn19Cz!5_i@lj{E!_1D(^pLJJH z^heZx*2e#e{cA7$zB%|ix`_XX{XfU?zxe-|e7~>r?;Z8uas2k{AByk2D*oMH|IH=u zh`;s}{~SO%(*HNaU;6D|2k;&IR}%XtxXRmj{=dBLf56|G6gf%Ix48=d0RQ#{1_}Tm I@K+`Of52({3;+NC literal 0 HcmV?d00001 diff --git a/Applet/lib/hamcrest-core-1.3.jar b/Applet/JCardSimProvider/lib/hamcrest-core-1.3.jar similarity index 100% rename from Applet/lib/hamcrest-core-1.3.jar rename to Applet/JCardSimProvider/lib/hamcrest-core-1.3.jar diff --git a/Applet/lib/jcardsim-3.0.5-SNAPSHOT.jar b/Applet/JCardSimProvider/lib/jcardsim-3.0.5-SNAPSHOT.jar similarity index 100% rename from Applet/lib/jcardsim-3.0.5-SNAPSHOT.jar rename to Applet/JCardSimProvider/lib/jcardsim-3.0.5-SNAPSHOT.jar diff --git a/Applet/lib/junit-4.13.jar b/Applet/JCardSimProvider/lib/junit-4.13.jar similarity index 100% rename from Applet/lib/junit-4.13.jar rename to Applet/JCardSimProvider/lib/junit-4.13.jar diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java similarity index 99% rename from Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java rename to Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java index 9e046264..136ec4ba 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -889,7 +889,7 @@ public void build() { tbsLength = (short) (tbsLength - tbsOffset); pushSequenceHeader((short) (last - stackPtr)); certStart = stackPtr; - short sigLen = KMJcardSimulator.getInstance() + short sigLen = KMJCardSimulator.getInstance() .ecSign256( KMByteBlob.cast(signPriv).getBuffer(), KMByteBlob.cast(signPriv).getStartOff(), @@ -933,7 +933,7 @@ public KMAttestationCert makeUniqueId(byte[] scratchPad, short scratchPadOff, scratchPadOff++; timeOffset = KMByteBlob.instance((short) 32); - appIdOff = KMJcardSimulator.getInstance().hmacSign(key, keyOff, keyLen, + appIdOff = KMJCardSimulator.getInstance().hmacSign(key, keyOff, keyLen, scratchPad, /* data */ temp, /* data start */ scratchPadOff, /* data length */ diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMCipher.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipher.java similarity index 97% rename from Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMCipher.java rename to Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipher.java index b599c003..145fea9d 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMCipher.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipher.java @@ -1,51 +1,51 @@ -package com.android.javacard.keymaster; - -public abstract class KMCipher { - /* - public static final byte CIPHER_RSA = 7; - public static final short PAD_PKCS1_OAEP = 9; - public static final short PAD_PKCS1_OAEP_SHA224 = 13; - public static final byte PAD_PKCS1_OAEP_SHA256 = 14; - public static final short PAD_PKCS1_OAEP_SHA384 = 15; - public static final short PAD_PKCS1_OAEP_SHA512 = 16; - public static final short PAD_NOPAD = 1; - public static final short PAD_PKCS1_PSS = 8; - public static final short PAD_NULL = 0; - public static final short PAD_PKCS7 = 31; // Not supported in javacard - public static final short ALG_DES_CBC_NOPAD = 1; - public static final short ALG_DES_ECB_NOPAD = 5; - public static final short ALG_AES_BLOCK_128_CBC_NOPAD= 13; - public static final short ALG_AES_BLOCK_128_ECB_NOPAD = 14; - public static final short ALG_AES_GCM = -13; - public static final short MODE_ENCRYPT = 2; - public static final short MODE_DECRYPT = 1; - public static final short PAD_PKCS1 = 7; - public static final short AES_BLOCK_SIZE = 16; - public static final short DES_BLOCK_SIZE = 8; - public static final short ALG_AES_CTR = -16; - - */ - public static final short SUN_JCE = 0xE9; - - public abstract short doFinal(byte[] buffer, short startOff, short length, byte[] scratchPad, short i); - - public abstract short update(byte[] buffer, short startOff, short length, byte[] scratchPad, short i); - - public abstract void updateAAD(byte[] buffer, short startOff, short length); - - public abstract short getBlockMode(); - - public abstract void setBlockMode(short mode); - - public abstract short getPaddingAlgorithm(); - - public abstract short getCipherAlgorithm(); - - public abstract void setPaddingAlgorithm(short alg); - - public abstract void setCipherAlgorithm(short alg); - - public abstract short getCipherProvider(); - - public abstract short getAesGcmOutputSize(short len, short macLength); -} +package com.android.javacard.keymaster; + +public abstract class KMCipher { + /* + public static final byte CIPHER_RSA = 7; + public static final short PAD_PKCS1_OAEP = 9; + public static final short PAD_PKCS1_OAEP_SHA224 = 13; + public static final byte PAD_PKCS1_OAEP_SHA256 = 14; + public static final short PAD_PKCS1_OAEP_SHA384 = 15; + public static final short PAD_PKCS1_OAEP_SHA512 = 16; + public static final short PAD_NOPAD = 1; + public static final short PAD_PKCS1_PSS = 8; + public static final short PAD_NULL = 0; + public static final short PAD_PKCS7 = 31; // Not supported in javacard + public static final short ALG_DES_CBC_NOPAD = 1; + public static final short ALG_DES_ECB_NOPAD = 5; + public static final short ALG_AES_BLOCK_128_CBC_NOPAD= 13; + public static final short ALG_AES_BLOCK_128_ECB_NOPAD = 14; + public static final short ALG_AES_GCM = -13; + public static final short MODE_ENCRYPT = 2; + public static final short MODE_DECRYPT = 1; + public static final short PAD_PKCS1 = 7; + public static final short AES_BLOCK_SIZE = 16; + public static final short DES_BLOCK_SIZE = 8; + public static final short ALG_AES_CTR = -16; + + */ + public static final short SUN_JCE = 0xE9; + + public abstract short doFinal(byte[] buffer, short startOff, short length, byte[] scratchPad, short i); + + public abstract short update(byte[] buffer, short startOff, short length, byte[] scratchPad, short i); + + public abstract void updateAAD(byte[] buffer, short startOff, short length); + + public abstract short getBlockMode(); + + public abstract void setBlockMode(short mode); + + public abstract short getPaddingAlgorithm(); + + public abstract short getCipherAlgorithm(); + + public abstract void setPaddingAlgorithm(short alg); + + public abstract void setCipherAlgorithm(short alg); + + public abstract short getCipherProvider(); + + public abstract short getAesGcmOutputSize(short len, short macLength); +} diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMCipherImpl.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipherImpl.java similarity index 97% rename from Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMCipherImpl.java rename to Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipherImpl.java index 65ebfad0..ea65a94c 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMCipherImpl.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipherImpl.java @@ -1,220 +1,220 @@ -package com.android.javacard.keymaster; - -import javacard.framework.Util; -import javacard.security.CryptoException; -import javacardx.crypto.Cipher; -import javax.crypto.AEADBadTagException; -import javax.crypto.BadPaddingException; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.ShortBufferException; - - -public class KMCipherImpl extends KMCipher{ - private Cipher cipher; - private javax.crypto.Cipher sunCipher; - private short cipherAlg; - private short padding; - private short mode; - private boolean verificationFlag; - private short blockMode; - KMCipherImpl(Cipher c){ - cipher = c; - } - KMCipherImpl(javax.crypto.Cipher c){ - sunCipher = c; - } - - @Override - public short doFinal(byte[] buffer, short startOff, short length, byte[] scratchPad, short i){ - if(cipherAlg == KMType.RSA && padding == KMType.RSA_OAEP){ - try { - return (short)sunCipher.doFinal(buffer,startOff,length,scratchPad,i); - } catch (ShortBufferException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } catch (IllegalBlockSizeException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } catch (BadPaddingException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - }else if(cipherAlg == KMType.AES && blockMode == KMType.GCM){ - try { - return (short)sunCipher.doFinal(buffer,startOff,length,scratchPad,i); - } catch (AEADBadTagException e) { - e.printStackTrace(); - verificationFlag = false; - KMException.throwIt(KMError.VERIFICATION_FAILED); - } catch (ShortBufferException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } catch (IllegalBlockSizeException e) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } catch (BadPaddingException e) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - } else if(cipherAlg == KMType.AES && blockMode == KMType.CTR){ - try { - return (short)sunCipher.doFinal(buffer,startOff,length,scratchPad,i); - } catch (ShortBufferException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } catch (IllegalBlockSizeException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } catch (BadPaddingException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - } else{ - if(cipherAlg == KMType.RSA && padding == KMType.PADDING_NONE && mode == KMType.ENCRYPT ){ - // Length cannot be greater then key size according to JcardSim - if(length >= 256) KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - // make input equal to 255 bytes - byte[] tmp = new byte[255]; - Util.arrayFillNonAtomic(tmp,(short)0,(short)255, (byte)0); - Util.arrayCopyNonAtomic( - buffer, - startOff, - tmp, (short)(255 - length),length); - startOff = 0; - length = 255; - buffer = tmp; - - }else if((cipherAlg == KMType.DES || cipherAlg == KMType.AES) && padding ==KMType.PKCS7 && mode == KMType.ENCRYPT){ - byte blkSize = 16; - byte paddingBytes; - short len = length; - if (cipherAlg == KMType.DES) blkSize = 8; - // padding bytes - if (len % blkSize == 0) paddingBytes = blkSize; - else paddingBytes = (byte) (blkSize - (len % blkSize)); - // final len with padding - len = (short) (len + paddingBytes); - // intermediate buffer to copy input data+padding - byte[] tmp = new byte[len]; - // fill in the padding - Util.arrayFillNonAtomic(tmp, (short) 0, len, paddingBytes); - // copy the input data - Util.arrayCopyNonAtomic(buffer,startOff,tmp,(short)0,length); - buffer = tmp; - length = len; - startOff = 0; - } - short len = cipher.doFinal(buffer, startOff, length, scratchPad, i); - // JCard Sim removes leading zeros during decryption in case of no padding - so add that back. - if (cipherAlg == KMType.RSA && padding == KMType.PADDING_NONE && mode == KMType.DECRYPT && len < 256) { - byte[] tempBuf = new byte[256]; - Util.arrayFillNonAtomic(tempBuf, (short) 0, (short) 256, (byte) 0); - Util.arrayCopyNonAtomic(scratchPad, (short) 0, tempBuf, (short) (i + 256 - len), len); - Util.arrayCopyNonAtomic(tempBuf, (short) 0, scratchPad, i, (short) 256); - len = 256; - }else if((cipherAlg == KMType.AES || cipherAlg == KMType.DES) // PKCS7 - && padding == KMType.PKCS7 - && mode == KMType.DECRYPT){ - byte blkSize = 16; - if (cipherAlg == KMType.DES) blkSize = 8; - if(len >0) { - //verify if padding is corrupted. - byte paddingByte = scratchPad[i+len -1]; - //padding byte always should be <= block size - if((short)paddingByte > blkSize || - (short)paddingByte <= 0) KMException.throwIt(KMError.INVALID_ARGUMENT); - len = (short)(len - (short)paddingByte);// remove the padding bytes - } - } - return len; - } - return KMType.INVALID_VALUE; - } - - @Override - public short getCipherAlgorithm() { - return cipherAlg; - } - - @Override - public void setCipherAlgorithm(short alg) { - cipherAlg = alg; - } - - @Override - public short update(byte[] buffer, short startOff, short length, byte[] scratchPad, short i) { - if(cipherAlg == KMType.AES && (blockMode == KMType.GCM || blockMode == KMType.CTR)){ - try { - return (short)sunCipher.update(buffer,startOff,length,scratchPad,i); - } catch (ShortBufferException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } catch (IllegalStateException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - } else{ - return cipher.update(buffer, startOff, length, scratchPad, i); - } - return KMType.INVALID_VALUE; - } - - @Override - public void updateAAD(byte[] buffer, short startOff, short length) { - try { - sunCipher.updateAAD(buffer,startOff,length); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } catch (IllegalStateException e) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } catch (UnsupportedOperationException e) { - CryptoException.throwIt(CryptoException.ILLEGAL_USE); - } - } - - @Override - public short getPaddingAlgorithm() { - return padding; - } - - @Override - public void setPaddingAlgorithm(short alg) { - padding = alg; - } - - @Override - public void setBlockMode(short mode){ - blockMode = mode; - } - - @Override - public short getBlockMode(){ - return blockMode; - } - - public short getMode() { - return mode; - } - - public void setMode(short mode) { - this.mode = mode; - } - - @Override - public short getCipherProvider() { - return KMCipher.SUN_JCE; - } - - @Override - public short getAesGcmOutputSize(short len, short macLength) { - if (sunCipher != null) { - return (short) sunCipher.getOutputSize(len); - } else { - if (mode == KMType.ENCRYPT) { - return (short) (len + macLength); - } else { - return (short) (len - macLength); - } - } - } - -} +package com.android.javacard.keymaster; + +import javacard.framework.Util; +import javacard.security.CryptoException; +import javacardx.crypto.Cipher; +import javax.crypto.AEADBadTagException; +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.ShortBufferException; + + +public class KMCipherImpl extends KMCipher{ + private Cipher cipher; + private javax.crypto.Cipher sunCipher; + private short cipherAlg; + private short padding; + private short mode; + private boolean verificationFlag; + private short blockMode; + KMCipherImpl(Cipher c){ + cipher = c; + } + KMCipherImpl(javax.crypto.Cipher c){ + sunCipher = c; + } + + @Override + public short doFinal(byte[] buffer, short startOff, short length, byte[] scratchPad, short i){ + if(cipherAlg == KMType.RSA && padding == KMType.RSA_OAEP){ + try { + return (short)sunCipher.doFinal(buffer,startOff,length,scratchPad,i); + } catch (ShortBufferException e) { + e.printStackTrace(); + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } catch (IllegalBlockSizeException e) { + e.printStackTrace(); + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } catch (BadPaddingException e) { + e.printStackTrace(); + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } + }else if(cipherAlg == KMType.AES && blockMode == KMType.GCM){ + try { + return (short)sunCipher.doFinal(buffer,startOff,length,scratchPad,i); + } catch (AEADBadTagException e) { + e.printStackTrace(); + verificationFlag = false; + KMException.throwIt(KMError.VERIFICATION_FAILED); + } catch (ShortBufferException e) { + e.printStackTrace(); + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } catch (IllegalBlockSizeException e) { + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } catch (BadPaddingException e) { + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } + } else if(cipherAlg == KMType.AES && blockMode == KMType.CTR){ + try { + return (short)sunCipher.doFinal(buffer,startOff,length,scratchPad,i); + } catch (ShortBufferException e) { + e.printStackTrace(); + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } catch (IllegalBlockSizeException e) { + e.printStackTrace(); + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } catch (BadPaddingException e) { + e.printStackTrace(); + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } + } else{ + if(cipherAlg == KMType.RSA && padding == KMType.PADDING_NONE && mode == KMType.ENCRYPT ){ + // Length cannot be greater then key size according to JcardSim + if(length >= 256) KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + // make input equal to 255 bytes + byte[] tmp = new byte[255]; + Util.arrayFillNonAtomic(tmp,(short)0,(short)255, (byte)0); + Util.arrayCopyNonAtomic( + buffer, + startOff, + tmp, (short)(255 - length),length); + startOff = 0; + length = 255; + buffer = tmp; + + }else if((cipherAlg == KMType.DES || cipherAlg == KMType.AES) && padding ==KMType.PKCS7 && mode == KMType.ENCRYPT){ + byte blkSize = 16; + byte paddingBytes; + short len = length; + if (cipherAlg == KMType.DES) blkSize = 8; + // padding bytes + if (len % blkSize == 0) paddingBytes = blkSize; + else paddingBytes = (byte) (blkSize - (len % blkSize)); + // final len with padding + len = (short) (len + paddingBytes); + // intermediate buffer to copy input data+padding + byte[] tmp = new byte[len]; + // fill in the padding + Util.arrayFillNonAtomic(tmp, (short) 0, len, paddingBytes); + // copy the input data + Util.arrayCopyNonAtomic(buffer,startOff,tmp,(short)0,length); + buffer = tmp; + length = len; + startOff = 0; + } + short len = cipher.doFinal(buffer, startOff, length, scratchPad, i); + // JCard Sim removes leading zeros during decryption in case of no padding - so add that back. + if (cipherAlg == KMType.RSA && padding == KMType.PADDING_NONE && mode == KMType.DECRYPT && len < 256) { + byte[] tempBuf = new byte[256]; + Util.arrayFillNonAtomic(tempBuf, (short) 0, (short) 256, (byte) 0); + Util.arrayCopyNonAtomic(scratchPad, (short) 0, tempBuf, (short) (i + 256 - len), len); + Util.arrayCopyNonAtomic(tempBuf, (short) 0, scratchPad, i, (short) 256); + len = 256; + }else if((cipherAlg == KMType.AES || cipherAlg == KMType.DES) // PKCS7 + && padding == KMType.PKCS7 + && mode == KMType.DECRYPT){ + byte blkSize = 16; + if (cipherAlg == KMType.DES) blkSize = 8; + if(len >0) { + //verify if padding is corrupted. + byte paddingByte = scratchPad[i+len -1]; + //padding byte always should be <= block size + if((short)paddingByte > blkSize || + (short)paddingByte <= 0) KMException.throwIt(KMError.INVALID_ARGUMENT); + len = (short)(len - (short)paddingByte);// remove the padding bytes + } + } + return len; + } + return KMType.INVALID_VALUE; + } + + @Override + public short getCipherAlgorithm() { + return cipherAlg; + } + + @Override + public void setCipherAlgorithm(short alg) { + cipherAlg = alg; + } + + @Override + public short update(byte[] buffer, short startOff, short length, byte[] scratchPad, short i) { + if(cipherAlg == KMType.AES && (blockMode == KMType.GCM || blockMode == KMType.CTR)){ + try { + return (short)sunCipher.update(buffer,startOff,length,scratchPad,i); + } catch (ShortBufferException e) { + e.printStackTrace(); + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } catch (IllegalStateException e) { + e.printStackTrace(); + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } + } else{ + return cipher.update(buffer, startOff, length, scratchPad, i); + } + return KMType.INVALID_VALUE; + } + + @Override + public void updateAAD(byte[] buffer, short startOff, short length) { + try { + sunCipher.updateAAD(buffer,startOff,length); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } catch (IllegalStateException e) { + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } catch (UnsupportedOperationException e) { + CryptoException.throwIt(CryptoException.ILLEGAL_USE); + } + } + + @Override + public short getPaddingAlgorithm() { + return padding; + } + + @Override + public void setPaddingAlgorithm(short alg) { + padding = alg; + } + + @Override + public void setBlockMode(short mode){ + blockMode = mode; + } + + @Override + public short getBlockMode(){ + return blockMode; + } + + public short getMode() { + return mode; + } + + public void setMode(short mode) { + this.mode = mode; + } + + @Override + public short getCipherProvider() { + return KMCipher.SUN_JCE; + } + + @Override + public short getAesGcmOutputSize(short len, short macLength) { + if (sunCipher != null) { + return (short) sunCipher.getOutputSize(len); + } else { + if (mode == KMType.ENCRYPT) { + return (short) (len + macLength); + } else { + return (short) (len - macLength); + } + } + } + +} diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java similarity index 100% rename from Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java rename to Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java new file mode 100644 index 00000000..e1ec74f8 --- /dev/null +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java @@ -0,0 +1,19 @@ +package com.android.javacard.keymaster; + +public class KMJCardSimApplet extends KMKeymasterApplet { + + KMJCardSimApplet(){ + super(new KMJCardSimulator()); + } + /** + * Installs this applet. + * + * @param bArray the array containing installation parameters + * @param bOffset the starting offset in bArray + * @param bLength the length in bytes of the parameter data in bArray + */ + public static void install(byte[] bArray, short bOffset, byte bLength) { + new KMJCardSimApplet().register(); + } + +} diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java similarity index 99% rename from Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java rename to Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java index 76ebb3e9..446f8bd2 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMJcardSimulator.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java @@ -65,7 +65,7 @@ * Key, and upto 512 bit HMAC key. Also simulator does not support TRNG, so this implementation just * creates its own RNG using PRNG. */ -public class KMJcardSimulator implements KMSEProvider { +public class KMJCardSimulator implements KMSEProvider { public static final short AES_GCM_TAG_LENGTH = 12; public static final short AES_GCM_NONCE_LENGTH = 12; public static final short MAX_RND_NUM_SIZE = 64; @@ -85,14 +85,14 @@ public class KMJcardSimulator implements KMSEProvider { private static byte[] rndNum; private byte[] certificateChain; - private static KMJcardSimulator jCardSimulator = null; + private static KMJCardSimulator jCardSimulator = null; - public static KMJcardSimulator getInstance() { + public static KMJCardSimulator getInstance() { return jCardSimulator; } // Implements Oracle Simulator based restricted crypto provider - public KMJcardSimulator() { + public KMJCardSimulator() { // Various Keys kdf = Signature.getInstance(Signature.ALG_AES_CMAC_128, false); hmacSignature = Signature.getInstance(Signature.ALG_HMAC_SHA_256, false); diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMOperationImpl.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMOperationImpl.java similarity index 100% rename from Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMOperationImpl.java rename to Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMOperationImpl.java diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java similarity index 96% rename from Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java rename to Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java index 82793bfb..38e9a3bc 100644 --- a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java @@ -1,120 +1,120 @@ -package com.android.javacard.keymaster; - -import javacard.framework.Util; -import javacard.security.CryptoException; -import javacard.security.Key; -import javacard.security.Signature; -import javacardx.crypto.Cipher; - -public class KMRsa2048NoDigestSignature extends Signature { - private Cipher inst; // ALG_RSA_NOPAD. - private byte padding; - private byte[] rsaModulus; // to compare with the data value - - public KMRsa2048NoDigestSignature(Cipher ciph, byte padding, byte[]mod, short start, short len){ - inst = ciph; - this.padding = padding; - if(len != 256) CryptoException.throwIt(CryptoException.INVALID_INIT); - rsaModulus = new byte[256]; - Util.arrayCopyNonAtomic(mod,start,rsaModulus,(short)0,len); - } - - @Override - public void init(Key key, byte b) throws CryptoException { - - } - - @Override - public void init(Key key, byte b, byte[] bytes, short i, short i1) throws CryptoException { - } - - @Override - public void setInitialDigest(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) throws CryptoException { - } - - @Override - public byte getAlgorithm() { - return 0; - } - - @Override - public byte getMessageDigestAlgorithm() { - return 0; - } - - @Override - public byte getCipherAlgorithm() { - return 0; - } - - @Override - public byte getPaddingAlgorithm() { - return 0; - } - - @Override - public short getLength() throws CryptoException { - return 0; - } - - @Override - public void update(byte[] bytes, short i, short i1) throws CryptoException { - } - - @Override - public short sign(byte[] bytes, short i, short i1, byte[] bytes1, short i2) throws CryptoException { - byte[] inputData = padData(bytes,i,i1); - return inst.doFinal(inputData,(short)0,(short)256,bytes1,i2); - } - - @Override - public short signPreComputedHash(byte[] bytes, short i, short i1, byte[] bytes1, short i2) throws CryptoException { - return 0; - } - - @Override - public boolean verify(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) throws CryptoException { - // Cannot support this method as javacard cipher api does not allow 256 byte for public key - // encryption without padding. It only allows 255 bytes data. - return false; - } - - @Override - public boolean verifyPreComputedHash(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) throws CryptoException { - return false; - } - - private byte[] padData(byte[] buf, short start, short len){ - byte[] inputData = new byte[256]; - if(!isValidData(buf, start,len)){ - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - Util.arrayFillNonAtomic(inputData, (short) 0, (short) 256, (byte) 0x00); - if (padding == KMType.PADDING_NONE) { // add zero to right - } else if (padding == KMType.RSA_PKCS1_1_5_SIGN) {// 0x00||0x01||PS||0x00 - inputData[0] = 0x00; - inputData[1] = 0x01; - Util.arrayFillNonAtomic(inputData,(short)2,(short)(256-len-3),(byte)0xFF); - inputData[(short)(256-len-1)] = 0x00; - }else{ - CryptoException.throwIt(CryptoException.ILLEGAL_USE); - } - Util.arrayCopyNonAtomic(buf,start,inputData,(short)(256 -len),len); - return inputData; - } - - private boolean isValidData(byte[] buf, short start, short len) { - if (padding == KMType.PADDING_NONE) { - if (len > 256) return false; - else if (len == 256) { - short v = Util.arrayCompare(buf, start, rsaModulus, (short) 0, len); - if (v > 0) return false; - } - } else {//pkcs1 no digest - if(len > 245){ - return false; - } - } - return true; - } -} +package com.android.javacard.keymaster; + +import javacard.framework.Util; +import javacard.security.CryptoException; +import javacard.security.Key; +import javacard.security.Signature; +import javacardx.crypto.Cipher; + +public class KMRsa2048NoDigestSignature extends Signature { + private Cipher inst; // ALG_RSA_NOPAD. + private byte padding; + private byte[] rsaModulus; // to compare with the data value + + public KMRsa2048NoDigestSignature(Cipher ciph, byte padding, byte[]mod, short start, short len){ + inst = ciph; + this.padding = padding; + if(len != 256) CryptoException.throwIt(CryptoException.INVALID_INIT); + rsaModulus = new byte[256]; + Util.arrayCopyNonAtomic(mod,start,rsaModulus,(short)0,len); + } + + @Override + public void init(Key key, byte b) throws CryptoException { + + } + + @Override + public void init(Key key, byte b, byte[] bytes, short i, short i1) throws CryptoException { + } + + @Override + public void setInitialDigest(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) throws CryptoException { + } + + @Override + public byte getAlgorithm() { + return 0; + } + + @Override + public byte getMessageDigestAlgorithm() { + return 0; + } + + @Override + public byte getCipherAlgorithm() { + return 0; + } + + @Override + public byte getPaddingAlgorithm() { + return 0; + } + + @Override + public short getLength() throws CryptoException { + return 0; + } + + @Override + public void update(byte[] bytes, short i, short i1) throws CryptoException { + } + + @Override + public short sign(byte[] bytes, short i, short i1, byte[] bytes1, short i2) throws CryptoException { + byte[] inputData = padData(bytes,i,i1); + return inst.doFinal(inputData,(short)0,(short)256,bytes1,i2); + } + + @Override + public short signPreComputedHash(byte[] bytes, short i, short i1, byte[] bytes1, short i2) throws CryptoException { + return 0; + } + + @Override + public boolean verify(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) throws CryptoException { + // Cannot support this method as javacard cipher api does not allow 256 byte for public key + // encryption without padding. It only allows 255 bytes data. + return false; + } + + @Override + public boolean verifyPreComputedHash(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) throws CryptoException { + return false; + } + + private byte[] padData(byte[] buf, short start, short len){ + byte[] inputData = new byte[256]; + if(!isValidData(buf, start,len)){ + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } + Util.arrayFillNonAtomic(inputData, (short) 0, (short) 256, (byte) 0x00); + if (padding == KMType.PADDING_NONE) { // add zero to right + } else if (padding == KMType.RSA_PKCS1_1_5_SIGN) {// 0x00||0x01||PS||0x00 + inputData[0] = 0x00; + inputData[1] = 0x01; + Util.arrayFillNonAtomic(inputData,(short)2,(short)(256-len-3),(byte)0xFF); + inputData[(short)(256-len-1)] = 0x00; + }else{ + CryptoException.throwIt(CryptoException.ILLEGAL_USE); + } + Util.arrayCopyNonAtomic(buf,start,inputData,(short)(256 -len),len); + return inputData; + } + + private boolean isValidData(byte[] buf, short start, short len) { + if (padding == KMType.PADDING_NONE) { + if (len > 256) return false; + else if (len == 256) { + short v = Util.arrayCompare(buf, start, rsaModulus, (short) 0, len); + if (v > 0) return false; + } + } else {//pkcs1 no digest + if(len > 245){ + return false; + } + } + return true; + } +} diff --git a/Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMUtils.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java similarity index 100% rename from Applet/Applet/JCardSimProvider/com/android/javacard/keymaster/KMUtils.java rename to Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java diff --git a/Applet/Applet/test/com/android/javacard/test/KMFunctionalTest.java b/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java similarity index 97% rename from Applet/Applet/test/com/android/javacard/test/KMFunctionalTest.java rename to Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java index 450e7a60..fb248f2d 100644 --- a/Applet/Applet/test/com/android/javacard/test/KMFunctionalTest.java +++ b/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java @@ -1,2740 +1,2735 @@ -/* - * Copyright(C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.javacard.test; - -import com.android.javacard.keymaster.KMArray; -import com.android.javacard.keymaster.KMAttestationCert; -import com.android.javacard.keymaster.KMAttestationCertImpl; -import com.android.javacard.keymaster.KMBoolTag; -import com.android.javacard.keymaster.KMByteBlob; -import com.android.javacard.keymaster.KMByteTag; -import com.android.javacard.keymaster.KMSEProvider; -import com.android.javacard.keymaster.KMSEProviderImpl; -import com.android.javacard.keymaster.KMDecoder; -import com.android.javacard.keymaster.KMEncoder; -import com.android.javacard.keymaster.KMEnum; -import com.android.javacard.keymaster.KMEnumArrayTag; -import com.android.javacard.keymaster.KMEnumTag; -import com.android.javacard.keymaster.KMError; -import com.android.javacard.keymaster.KMHardwareAuthToken; -import com.android.javacard.keymaster.KMHmacSharingParameters; -import com.android.javacard.keymaster.KMInteger; -import com.android.javacard.keymaster.KMIntegerTag; -import com.android.javacard.keymaster.KMKeyCharacteristics; -import com.android.javacard.keymaster.KMKeyParameters; -import com.android.javacard.keymaster.KMKeymasterApplet; -import com.android.javacard.keymaster.KMRepository; -import com.android.javacard.keymaster.KMType; -import com.android.javacard.keymaster.KMVerificationToken; -import com.licel.jcardsim.smartcardio.CardSimulator; -import com.licel.jcardsim.utils.AIDUtil; -import javacard.framework.AID; -import javacard.framework.Util; - -import java.security.spec.PKCS8EncodedKeySpec; - -import javax.smartcardio.CommandAPDU; -import javax.smartcardio.ResponseAPDU; -import org.junit.Assert; -import org.junit.Test; - -public class KMFunctionalTest { - private static final byte INS_BEGIN_KM_CMD = 0x00; - private static final byte INS_PROVISION_ATTESTATION_KEY_CMD = INS_BEGIN_KM_CMD + 1; //0x01 - private static final byte INS_PROVISION_ATTESTATION_CERT_CHAIN_CMD = INS_BEGIN_KM_CMD + 2; //0x02 - private static final byte INS_PROVISION_ATTESTATION_CERT_PARAMS_CMD = INS_BEGIN_KM_CMD + 3; //0x03 - private static final byte INS_PROVISION_ATTEST_IDS_CMD = INS_BEGIN_KM_CMD + 4; //0x04 - private static final byte INS_PROVISION_SHARED_SECRET_CMD = INS_BEGIN_KM_CMD + 5; //0x05 - private static final byte INS_SET_BOOT_PARAMS_CMD = INS_BEGIN_KM_CMD + 6; //0x06 - private static final byte INS_LOCK_PROVISIONING_CMD = INS_BEGIN_KM_CMD + 7; //0x07 - private static final byte INS_GET_PROVISION_STATUS_CMD = INS_BEGIN_KM_CMD + 8; //0x08 - // Top 32 commands are reserved for provisioning. - private static final byte INS_END_KM_PROVISION_CMD = 0x20; - - private static final byte INS_GENERATE_KEY_CMD = INS_END_KM_PROVISION_CMD + 1; //0x21 - private static final byte INS_IMPORT_KEY_CMD = INS_END_KM_PROVISION_CMD + 2; //0x22 - private static final byte INS_IMPORT_WRAPPED_KEY_CMD = INS_END_KM_PROVISION_CMD + 3; //0x23 - private static final byte INS_EXPORT_KEY_CMD = INS_END_KM_PROVISION_CMD + 4; //0x24 - private static final byte INS_ATTEST_KEY_CMD = INS_END_KM_PROVISION_CMD + 5; //0x25 - private static final byte INS_UPGRADE_KEY_CMD = INS_END_KM_PROVISION_CMD + 6; //0x26 - private static final byte INS_DELETE_KEY_CMD = INS_END_KM_PROVISION_CMD + 7; //0x27 - private static final byte INS_DELETE_ALL_KEYS_CMD = INS_END_KM_PROVISION_CMD + 8; //0x28 - private static final byte INS_ADD_RNG_ENTROPY_CMD = INS_END_KM_PROVISION_CMD + 9; //0x29 - private static final byte INS_COMPUTE_SHARED_HMAC_CMD = INS_END_KM_PROVISION_CMD + 10; //0x2A - private static final byte INS_DESTROY_ATT_IDS_CMD = INS_END_KM_PROVISION_CMD + 11; //0x2B - private static final byte INS_VERIFY_AUTHORIZATION_CMD = INS_END_KM_PROVISION_CMD + 12; //0x2C - private static final byte INS_GET_HMAC_SHARING_PARAM_CMD = INS_END_KM_PROVISION_CMD + 13; //0x2D - private static final byte INS_GET_KEY_CHARACTERISTICS_CMD = INS_END_KM_PROVISION_CMD + 14; //0x2E - private static final byte INS_GET_HW_INFO_CMD = INS_END_KM_PROVISION_CMD + 15; //0x2F - private static final byte INS_BEGIN_OPERATION_CMD = INS_END_KM_PROVISION_CMD + 16; //0x30 - private static final byte INS_UPDATE_OPERATION_CMD = INS_END_KM_PROVISION_CMD + 17; //0x31 - private static final byte INS_FINISH_OPERATION_CMD = INS_END_KM_PROVISION_CMD + 18; //0x32 - private static final byte INS_ABORT_OPERATION_CMD = INS_END_KM_PROVISION_CMD + 19; //0x33 - private static final byte INS_DEVICE_LOCKED_CMD = INS_END_KM_PROVISION_CMD + 20;//0x34 - private static final byte INS_EARLY_BOOT_ENDED_CMD = INS_END_KM_PROVISION_CMD + 21; //0x35 - private static final byte INS_GET_CERT_CHAIN_CMD = INS_END_KM_PROVISION_CMD + 22; //0x36 - - private static final byte[] kEcPrivKey = { - (byte) 0x21, (byte) 0xe0, (byte) 0x86, (byte) 0x43, (byte) 0x2a, - (byte) 0x15, (byte) 0x19, (byte) 0x84, (byte) 0x59, (byte) 0xcf, - (byte) 0x36, (byte) 0x3a, (byte) 0x50, (byte) 0xfc, (byte) 0x14, - (byte) 0xc9, (byte) 0xda, (byte) 0xad, (byte) 0xf9, (byte) 0x35, - (byte) 0xf5, (byte) 0x27, (byte) 0xc2, (byte) 0xdf, (byte) 0xd7, - (byte) 0x1e, (byte) 0x4d, (byte) 0x6d, (byte) 0xbc, (byte) 0x42, - (byte) 0xe5, (byte) 0x44 }; - private static final byte[] kEcPubKey = { - (byte) 0x04, (byte) 0xeb, (byte) 0x9e, (byte) 0x79, (byte) 0xf8, - (byte) 0x42, (byte) 0x63, (byte) 0x59, (byte) 0xac, (byte) 0xcb, - (byte) 0x2a, (byte) 0x91, (byte) 0x4c, (byte) 0x89, (byte) 0x86, - (byte) 0xcc, (byte) 0x70, (byte) 0xad, (byte) 0x90, (byte) 0x66, - (byte) 0x93, (byte) 0x82, (byte) 0xa9, (byte) 0x73, (byte) 0x26, - (byte) 0x13, (byte) 0xfe, (byte) 0xac, (byte) 0xcb, (byte) 0xf8, - (byte) 0x21, (byte) 0x27, (byte) 0x4c, (byte) 0x21, (byte) 0x74, - (byte) 0x97, (byte) 0x4a, (byte) 0x2a, (byte) 0xfe, (byte) 0xa5, - (byte) 0xb9, (byte) 0x4d, (byte) 0x7f, (byte) 0x66, (byte) 0xd4, - (byte) 0xe0, (byte) 0x65, (byte) 0x10, (byte) 0x66, (byte) 0x35, - (byte) 0xbc, (byte) 0x53, (byte) 0xb7, (byte) 0xa0, (byte) 0xa3, - (byte) 0xa6, (byte) 0x71, (byte) 0x58, (byte) 0x3e, (byte) 0xdb, - (byte) 0x3e, (byte) 0x11, (byte) 0xae, (byte) 0x10, (byte) 0x14 }; - - private static final byte[] kEcAttestCert = { - 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x78, (byte) 0x30, (byte) 0x82, - (byte) 0x02, (byte) 0x1e, (byte) 0xa0, (byte) 0x03, (byte) 0x02, - (byte) 0x01, (byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x10, 0x01, - (byte) 0x30, (byte) 0x0a, (byte) 0x06, (byte) 0x08, (byte) 0x2a, - (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x04, - (byte) 0x03, (byte) 0x02, (byte) 0x30, (byte) 0x81, (byte) 0x98, 0x31, - (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, - (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, - (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x13, (byte) 0x30, 0x11, - (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08, - (byte) 0x0c, (byte) 0x0a, (byte) 0x43, (byte) 0x61, (byte) 0x6c, - (byte) 0x69, (byte) 0x66, (byte) 0x6f, (byte) 0x72, (byte) 0x6e, 0x69, - (byte) 0x61, (byte) 0x31, (byte) 0x16, (byte) 0x30, (byte) 0x14, - (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x07, - (byte) 0x0c, (byte) 0x0d, (byte) 0x4d, (byte) 0x6f, (byte) 0x75, 0x6e, - (byte) 0x74, (byte) 0x61, (byte) 0x69, (byte) 0x6e, (byte) 0x20, - (byte) 0x56, (byte) 0x69, (byte) 0x65, (byte) 0x77, (byte) 0x31, - (byte) 0x15, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x03, 0x55, - (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x0c, (byte) 0x47, - (byte) 0x6f, (byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65, - (byte) 0x2c, (byte) 0x20, (byte) 0x49, (byte) 0x6e, (byte) 0x63, 0x2e, - (byte) 0x31, (byte) 0x10, (byte) 0x30, (byte) 0x0e, (byte) 0x06, - (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0b, (byte) 0x0c, - (byte) 0x07, (byte) 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, 0x6f, - (byte) 0x69, (byte) 0x64, (byte) 0x31, (byte) 0x33, (byte) 0x30, - (byte) 0x31, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, - (byte) 0x03, (byte) 0x0c, (byte) 0x2a, (byte) 0x41, (byte) 0x6e, 0x64, - (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x20, - (byte) 0x4b, (byte) 0x65, (byte) 0x79, (byte) 0x73, (byte) 0x74, - (byte) 0x6f, (byte) 0x72, (byte) 0x65, (byte) 0x20, (byte) 0x53, 0x6f, - (byte) 0x66, (byte) 0x74, (byte) 0x77, (byte) 0x61, (byte) 0x72, - (byte) 0x65, (byte) 0x20, (byte) 0x41, (byte) 0x74, (byte) 0x74, - (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x61, (byte) 0x74, 0x69, - (byte) 0x6f, (byte) 0x6e, (byte) 0x20, (byte) 0x52, (byte) 0x6f, - (byte) 0x6f, (byte) 0x74, (byte) 0x30, (byte) 0x1e, (byte) 0x17, - (byte) 0x0d, (byte) 0x31, (byte) 0x36, (byte) 0x30, (byte) 0x31, 0x31, - (byte) 0x31, (byte) 0x30, (byte) 0x30, (byte) 0x34, (byte) 0x36, - (byte) 0x30, (byte) 0x39, (byte) 0x5a, (byte) 0x17, (byte) 0x0d, - (byte) 0x32, (byte) 0x36, (byte) 0x30, (byte) 0x31, (byte) 0x30, 0x38, - (byte) 0x30, (byte) 0x30, (byte) 0x34, (byte) 0x36, (byte) 0x30, - (byte) 0x39, (byte) 0x5a, (byte) 0x30, (byte) 0x81, (byte) 0x88, - (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, 0x03, - (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, - (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x13, (byte) 0x30, - (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, 0x08, - (byte) 0x0c, (byte) 0x0a, (byte) 0x43, (byte) 0x61, (byte) 0x6c, - (byte) 0x69, (byte) 0x66, (byte) 0x6f, (byte) 0x72, (byte) 0x6e, - (byte) 0x69, (byte) 0x61, (byte) 0x31, (byte) 0x15, (byte) 0x30, 0x13, - (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, - (byte) 0x0c, (byte) 0x0c, (byte) 0x47, (byte) 0x6f, (byte) 0x6f, - (byte) 0x67, (byte) 0x6c, (byte) 0x65, (byte) 0x2c, (byte) 0x20, 0x49, - (byte) 0x6e, (byte) 0x63, (byte) 0x2e, (byte) 0x31, (byte) 0x10, - (byte) 0x30, (byte) 0x0e, (byte) 0x06, (byte) 0x03, (byte) 0x55, - (byte) 0x04, (byte) 0x0b, (byte) 0x0c, (byte) 0x07, (byte) 0x41, 0x6e, - (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, - (byte) 0x31, (byte) 0x3b, (byte) 0x30, (byte) 0x39, (byte) 0x06, - (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x0c, 0x32, - (byte) 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, - (byte) 0x69, (byte) 0x64, (byte) 0x20, (byte) 0x4b, (byte) 0x65, - (byte) 0x79, (byte) 0x73, (byte) 0x74, (byte) 0x6f, (byte) 0x72, 0x65, - (byte) 0x20, (byte) 0x53, (byte) 0x6f, (byte) 0x66, (byte) 0x74, - (byte) 0x77, (byte) 0x61, (byte) 0x72, (byte) 0x65, (byte) 0x20, - (byte) 0x41, (byte) 0x74, (byte) 0x74, (byte) 0x65, (byte) 0x73, 0x74, - (byte) 0x61, (byte) 0x74, (byte) 0x69, (byte) 0x6f, (byte) 0x6e, - (byte) 0x20, (byte) 0x49, (byte) 0x6e, (byte) 0x74, (byte) 0x65, - (byte) 0x72, (byte) 0x6d, (byte) 0x65, (byte) 0x64, (byte) 0x69, 0x61, - (byte) 0x74, (byte) 0x65, (byte) 0x30, (byte) 0x59, (byte) 0x30, - (byte) 0x13, (byte) 0x06, (byte) 0x07, (byte) 0x2a, (byte) 0x86, - (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x02, (byte) 0x01, 0x06, - (byte) 0x08, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0xce, - (byte) 0x3d, (byte) 0x03, (byte) 0x01, (byte) 0x07, (byte) 0x03, - (byte) 0x42, (byte) 0x00, (byte) 0x04, (byte) 0xeb, (byte) 0x9e, 0x79, - (byte) 0xf8, (byte) 0x42, (byte) 0x63, (byte) 0x59, (byte) 0xac, - (byte) 0xcb, (byte) 0x2a, (byte) 0x91, (byte) 0x4c, (byte) 0x89, - (byte) 0x86, (byte) 0xcc, (byte) 0x70, (byte) 0xad, (byte) 0x90, 0x66, - (byte) 0x93, (byte) 0x82, (byte) 0xa9, (byte) 0x73, (byte) 0x26, - (byte) 0x13, (byte) 0xfe, (byte) 0xac, (byte) 0xcb, (byte) 0xf8, - (byte) 0x21, (byte) 0x27, (byte) 0x4c, (byte) 0x21, (byte) 0x74, - (byte) 0x97, (byte) 0x4a, (byte) 0x2a, (byte) 0xfe, (byte) 0xa5, - (byte) 0xb9, (byte) 0x4d, (byte) 0x7f, (byte) 0x66, (byte) 0xd4, - (byte) 0xe0, (byte) 0x65, (byte) 0x10, (byte) 0x66, (byte) 0x35, - (byte) 0xbc, 0x53, (byte) 0xb7, (byte) 0xa0, (byte) 0xa3, (byte) 0xa6, - (byte) 0x71, (byte) 0x58, (byte) 0x3e, (byte) 0xdb, (byte) 0x3e, - (byte) 0x11, (byte) 0xae, (byte) 0x10, (byte) 0x14, (byte) 0xa3, - (byte) 0x66, 0x30, (byte) 0x64, (byte) 0x30, (byte) 0x1d, (byte) 0x06, - (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e, (byte) 0x04, - (byte) 0x16, (byte) 0x04, (byte) 0x14, (byte) 0x3f, (byte) 0xfc, - (byte) 0xac, (byte) 0xd6, (byte) 0x1a, (byte) 0xb1, (byte) 0x3a, - (byte) 0x9e, (byte) 0x81, (byte) 0x20, (byte) 0xb8, (byte) 0xd5, - (byte) 0x25, (byte) 0x1c, (byte) 0xc5, (byte) 0x65, (byte) 0xbb, - (byte) 0x1e, (byte) 0x91, (byte) 0xa9, (byte) 0x30, (byte) 0x1f, - (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x23, - (byte) 0x04, (byte) 0x18, (byte) 0x30, (byte) 0x16, (byte) 0x80, - (byte) 0x14, (byte) 0xc8, (byte) 0xad, (byte) 0xe9, (byte) 0x77, - (byte) 0x4c, (byte) 0x45, (byte) 0xc3, (byte) 0xa3, (byte) 0xcf, - (byte) 0x0d, (byte) 0x16, (byte) 0x10, (byte) 0xe4, (byte) 0x79, - (byte) 0x43, (byte) 0x3a, (byte) 0x21, (byte) 0x5a, 0x30, (byte) 0xcf, - (byte) 0x30, (byte) 0x12, (byte) 0x06, (byte) 0x03, (byte) 0x55, - (byte) 0x1d, (byte) 0x13, (byte) 0x01, (byte) 0x01, (byte) 0xff, - (byte) 0x04, (byte) 0x08, (byte) 0x30, (byte) 0x06, 0x01, (byte) 0x01, - (byte) 0xff, (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x30, - (byte) 0x0e, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, - (byte) 0x0f, (byte) 0x01, (byte) 0x01, (byte) 0xff, 0x04, (byte) 0x04, - (byte) 0x03, (byte) 0x02, (byte) 0x02, (byte) 0x84, (byte) 0x30, - (byte) 0x0a, (byte) 0x06, (byte) 0x08, (byte) 0x2a, (byte) 0x86, - (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x04, 0x03, (byte) 0x02, - (byte) 0x03, (byte) 0x48, (byte) 0x00, (byte) 0x30, (byte) 0x45, - (byte) 0x02, (byte) 0x20, (byte) 0x4b, (byte) 0x8a, (byte) 0x9b, - (byte) 0x7b, (byte) 0xee, (byte) 0x82, (byte) 0xbc, (byte) 0xc0, - (byte) 0x33, (byte) 0x87, (byte) 0xae, (byte) 0x2f, (byte) 0xc0, - (byte) 0x89, (byte) 0x98, (byte) 0xb4, (byte) 0xdd, (byte) 0xc3, - (byte) 0x8d, (byte) 0xab, (byte) 0x27, (byte) 0x2a, (byte) 0x45, - (byte) 0x9f, (byte) 0x69, (byte) 0x0c, (byte) 0xc7, (byte) 0xc3, - (byte) 0x92, (byte) 0xd4, (byte) 0x0f, (byte) 0x8e, (byte) 0x02, - (byte) 0x21, (byte) 0x00, (byte) 0xee, (byte) 0xda, (byte) 0x01, - (byte) 0x5d, (byte) 0xb6, (byte) 0xf4, (byte) 0x32, (byte) 0xe9, - (byte) 0xd4, (byte) 0x84, (byte) 0x3b, (byte) 0x62, (byte) 0x4c, - (byte) 0x94, (byte) 0x04, (byte) 0xef, (byte) 0x3a, (byte) 0x7c, - (byte) 0xcc, (byte) 0xbd, 0x5e, (byte) 0xfb, (byte) 0x22, (byte) 0xbb, - (byte) 0xe7, (byte) 0xfe, (byte) 0xb9, (byte) 0x77, (byte) 0x3f, - (byte) 0x59, (byte) 0x3f, (byte) 0xfb, }; - - private static final byte[] kEcAttestRootCert = { - 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x8b, (byte) 0x30, - (byte) 0x82, (byte) 0x02, (byte) 0x32, (byte) 0xa0, (byte) 0x03, - (byte) 0x02, (byte) 0x01, (byte) 0x02, (byte) 0x02, (byte) 0x09, - (byte) 0x00, (byte) 0xa2, (byte) 0x05, (byte) 0x9e, (byte) 0xd1, - (byte) 0x0e, (byte) 0x43, (byte) 0x5b, (byte) 0x57, (byte) 0x30, - (byte) 0x0a, (byte) 0x06, (byte) 0x08, (byte) 0x2a, (byte) 0x86, - (byte) 0x48, (byte) 0xce, 0x3d, (byte) 0x04, (byte) 0x03, - (byte) 0x02, (byte) 0x30, (byte) 0x81, (byte) 0x98, (byte) 0x31, - (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, - (byte) 0x55, (byte) 0x04, (byte) 0x06, 0x13, (byte) 0x02, - (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x13, (byte) 0x30, - (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, - (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x43, 0x61, - (byte) 0x6c, (byte) 0x69, (byte) 0x66, (byte) 0x6f, (byte) 0x72, - (byte) 0x6e, (byte) 0x69, (byte) 0x61, (byte) 0x31, (byte) 0x16, - (byte) 0x30, (byte) 0x14, (byte) 0x06, (byte) 0x03, (byte) 0x55, - 0x04, (byte) 0x07, (byte) 0x0c, (byte) 0x0d, (byte) 0x4d, - (byte) 0x6f, (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61, - (byte) 0x69, (byte) 0x6e, (byte) 0x20, (byte) 0x56, (byte) 0x69, - (byte) 0x65, 0x77, (byte) 0x31, (byte) 0x15, (byte) 0x30, - (byte) 0x13, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, - (byte) 0x0a, (byte) 0x0c, (byte) 0x0c, (byte) 0x47, (byte) 0x6f, - (byte) 0x6f, (byte) 0x67, 0x6c, (byte) 0x65, (byte) 0x2c, - (byte) 0x20, (byte) 0x49, (byte) 0x6e, (byte) 0x63, (byte) 0x2e, - (byte) 0x31, (byte) 0x10, (byte) 0x30, (byte) 0x0e, (byte) 0x06, - (byte) 0x03, (byte) 0x55, (byte) 0x04, 0x0b, (byte) 0x0c, - (byte) 0x07, (byte) 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, - (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x31, (byte) 0x33, - (byte) 0x30, (byte) 0x31, (byte) 0x06, (byte) 0x03, 0x55, - (byte) 0x04, (byte) 0x03, (byte) 0x0c, (byte) 0x2a, (byte) 0x41, - (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, - (byte) 0x64, (byte) 0x20, (byte) 0x4b, (byte) 0x65, (byte) 0x79, - 0x73, (byte) 0x74, (byte) 0x6f, (byte) 0x72, (byte) 0x65, - (byte) 0x20, (byte) 0x53, (byte) 0x6f, (byte) 0x66, (byte) 0x74, - (byte) 0x77, (byte) 0x61, (byte) 0x72, (byte) 0x65, (byte) 0x20, - (byte) 0x41, 0x74, (byte) 0x74, (byte) 0x65, (byte) 0x73, - (byte) 0x74, (byte) 0x61, (byte) 0x74, (byte) 0x69, (byte) 0x6f, - (byte) 0x6e, (byte) 0x20, (byte) 0x52, (byte) 0x6f, (byte) 0x6f, - (byte) 0x74, (byte) 0x30, 0x1e, (byte) 0x17, (byte) 0x0d, - (byte) 0x31, (byte) 0x36, (byte) 0x30, (byte) 0x31, (byte) 0x31, - (byte) 0x31, (byte) 0x30, (byte) 0x30, (byte) 0x34, (byte) 0x33, - (byte) 0x35, (byte) 0x30, (byte) 0x5a, 0x17, (byte) 0x0d, - (byte) 0x33, (byte) 0x36, (byte) 0x30, (byte) 0x31, (byte) 0x30, - (byte) 0x36, (byte) 0x30, (byte) 0x30, (byte) 0x34, (byte) 0x33, - (byte) 0x35, (byte) 0x30, (byte) 0x5a, (byte) 0x30, (byte) 0x81, - (byte) 0x98, (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, - (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, - (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31, - 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, - (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x0a, - (byte) 0x43, (byte) 0x61, (byte) 0x6c, (byte) 0x69, (byte) 0x66, - (byte) 0x6f, 0x72, (byte) 0x6e, (byte) 0x69, (byte) 0x61, - (byte) 0x31, (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06, - (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x07, (byte) 0x0c, - (byte) 0x0d, (byte) 0x4d, 0x6f, (byte) 0x75, (byte) 0x6e, - (byte) 0x74, (byte) 0x61, (byte) 0x69, (byte) 0x6e, (byte) 0x20, - (byte) 0x56, (byte) 0x69, (byte) 0x65, (byte) 0x77, (byte) 0x31, - (byte) 0x15, (byte) 0x30, (byte) 0x13, 0x06, (byte) 0x03, - (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x0c, - (byte) 0x47, (byte) 0x6f, (byte) 0x6f, (byte) 0x67, (byte) 0x6c, - (byte) 0x65, (byte) 0x2c, (byte) 0x20, (byte) 0x49, 0x6e, - (byte) 0x63, (byte) 0x2e, (byte) 0x31, (byte) 0x10, (byte) 0x30, - (byte) 0x0e, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, - (byte) 0x0b, (byte) 0x0c, (byte) 0x07, (byte) 0x41, (byte) 0x6e, - 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, - (byte) 0x31, (byte) 0x33, (byte) 0x30, (byte) 0x31, (byte) 0x06, - (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x0c, - (byte) 0x2a, 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, - (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x20, (byte) 0x4b, - (byte) 0x65, (byte) 0x79, (byte) 0x73, (byte) 0x74, (byte) 0x6f, - (byte) 0x72, (byte) 0x65, 0x20, (byte) 0x53, (byte) 0x6f, - (byte) 0x66, (byte) 0x74, (byte) 0x77, (byte) 0x61, (byte) 0x72, - (byte) 0x65, (byte) 0x20, (byte) 0x41, (byte) 0x74, (byte) 0x74, - (byte) 0x65, (byte) 0x73, (byte) 0x74, 0x61, (byte) 0x74, - (byte) 0x69, (byte) 0x6f, (byte) 0x6e, 0x77, (byte) 0x1f, - (byte) 0x44, (byte) 0x22, (byte) 0x6d, (byte) 0xbd, (byte) 0xb1, - (byte) 0xaf, (byte) 0xfa, (byte) 0x16, (byte) 0xcb, (byte) 0xc7, - (byte) 0xad, (byte) 0xc5, (byte) 0x77, (byte) 0xd2, (byte) 0x20, - (byte) 0x52, (byte) 0x6f, (byte) 0x6f, (byte) 0x74, (byte) 0x30, - (byte) 0x59, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x07, - 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x3d, - (byte) 0x02, (byte) 0x01, (byte) 0x06, (byte) 0x08, (byte) 0x2a, - (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x03, - (byte) 0x01, 0x07, (byte) 0x03, (byte) 0x42, (byte) 0x00, - (byte) 0x04, (byte) 0xee, (byte) 0x5d, (byte) 0x5e, (byte) 0xc7, - (byte) 0xe1, (byte) 0xc0, (byte) 0xdb, (byte) 0x6d, (byte) 0x03, - (byte) 0xa6, (byte) 0x7e, (byte) 0xe6, (byte) 0xb6, (byte) 0x1b, - (byte) 0xec, (byte) 0x4d, (byte) 0x6a, (byte) 0x5d, (byte) 0x6a, - (byte) 0x68, (byte) 0x2e, (byte) 0x0f, (byte) 0xff, (byte) 0x7f, - (byte) 0x49, (byte) 0x0e, (byte) 0x7d, 0x56, (byte) 0x9c, - (byte) 0xaa, (byte) 0xb7, (byte) 0xb0, (byte) 0x2d, (byte) 0x54, - (byte) 0x01, (byte) 0x5d, (byte) 0x3e, (byte) 0x43, (byte) 0x2b, - (byte) 0x2a, (byte) 0x8e, (byte) 0xd7, (byte) 0x4e, (byte) 0xec, - (byte) 0x48, (byte) 0x75, (byte) 0x41, (byte) 0xa4, (byte) 0xa3, - (byte) 0x63, (byte) 0x30, (byte) 0x61, (byte) 0x30, (byte) 0x1d, - (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e, - 0x04, (byte) 0x16, (byte) 0x04, (byte) 0x14, (byte) 0xc8, - (byte) 0xad, (byte) 0xe9, (byte) 0x77, (byte) 0x4c, (byte) 0x45, - (byte) 0xc3, (byte) 0xa3, (byte) 0xcf, (byte) 0x0d, (byte) 0x16, - (byte) 0x10, (byte) 0xe4, (byte) 0x79, (byte) 0x43, (byte) 0x3a, - (byte) 0x21, (byte) 0x5a, (byte) 0x30, (byte) 0xcf, (byte) 0x30, - (byte) 0x1f, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, - (byte) 0x23, (byte) 0x04, 0x18, (byte) 0x30, (byte) 0x16, - (byte) 0x80, (byte) 0x14, (byte) 0xc8, (byte) 0xad, (byte) 0xe9, - (byte) 0x77, (byte) 0x4c, (byte) 0x45, (byte) 0xc3, (byte) 0xa3, - (byte) 0xcf, (byte) 0x0d, (byte) 0x16, 0x10, (byte) 0xe4, - (byte) 0x79, (byte) 0x43, (byte) 0x3a, (byte) 0x21, (byte) 0x5a, - (byte) 0x30, (byte) 0xcf, (byte) 0x30, (byte) 0x0f, (byte) 0x06, - (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x13, 0x01, - (byte) 0x01, (byte) 0xff, (byte) 0x04, (byte) 0x05, (byte) 0x30, - (byte) 0x03, (byte) 0x01, (byte) 0x01, (byte) 0xff, (byte) 0x30, - (byte) 0x0e, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, - 0x0f, (byte) 0x01, (byte) 0x01, (byte) 0xff, (byte) 0x04, - (byte) 0x04, (byte) 0x03, (byte) 0x02, (byte) 0x02, (byte) 0x84, - (byte) 0x30, (byte) 0x0a, (byte) 0x06, (byte) 0x08, (byte) 0x2a, - (byte) 0x86, 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x04, - (byte) 0x03, (byte) 0x02, (byte) 0x03, (byte) 0x47, (byte) 0x00, - (byte) 0x30, (byte) 0x44, (byte) 0x02, (byte) 0x20, (byte) 0x35, - (byte) 0x21, (byte) 0xa3, (byte) 0xef, (byte) 0x8b, (byte) 0x34, - (byte) 0x46, (byte) 0x1e, (byte) 0x9c, (byte) 0xd5, (byte) 0x60, - (byte) 0xf3, (byte) 0x1d, (byte) 0x58, (byte) 0x89, (byte) 0x20, - (byte) 0x6a, (byte) 0xdc, (byte) 0xa3, 0x65, (byte) 0x41, - (byte) 0xf6, (byte) 0x0d, (byte) 0x9e, (byte) 0xce, (byte) 0x8a, - (byte) 0x19, (byte) 0x8c, (byte) 0x66, (byte) 0x48, (byte) 0x60, - (byte) 0x7b, (byte) 0x02, (byte) 0x20, (byte) 0x4d, 0x0b, - (byte) 0xf3, (byte) 0x51, (byte) 0xd9, (byte) 0x30, (byte) 0x7c, - (byte) 0x7d, (byte) 0x5b, (byte) 0xda, (byte) 0x35, (byte) 0x34, - (byte) 0x1d, (byte) 0xa8, (byte) 0x47, (byte) 0x1b, (byte) 0x63, - (byte) 0xa5, (byte) 0x85, (byte) 0x65, (byte) 0x3c, (byte) 0xad, - (byte) 0x4f, (byte) 0x24, (byte) 0xa7, (byte) 0xe7, (byte) 0x4d, - (byte) 0xaf, (byte) 0x41, (byte) 0x7d, (byte) 0xf1, - (byte) 0xbf, }; - - private static final byte[] X509Issuer = { - (byte) 0x30, (byte) 0x81, (byte) 0x88, (byte) 0x31, (byte) 0x0b, - (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, - (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x55, - (byte) 0x53, (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11, - (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08, - (byte) 0x0c, (byte) 0x0a, (byte) 0x43, (byte) 0x61, (byte) 0x6c, - (byte) 0x69, (byte) 0x66, (byte) 0x6f, (byte) 0x72, (byte) 0x6e, - (byte) 0x69, (byte) 0x61, (byte) 0x31, (byte) 0x15, (byte) 0x30, - (byte) 0x13, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, - (byte) 0x0a, (byte) 0x0c, (byte) 0x0c, (byte) 0x47, (byte) 0x6f, - (byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65, (byte) 0x2c, - (byte) 0x20, (byte) 0x49, (byte) 0x6e, (byte) 0x63, (byte) 0x2e, - (byte) 0x31, (byte) 0x10, (byte) 0x30, (byte) 0x0e, (byte) 0x06, - (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0b, (byte) 0x0c, - (byte) 0x07, (byte) 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, - (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x31, (byte) 0x3b, - (byte) 0x30, (byte) 0x39, (byte) 0x06, (byte) 0x03, (byte) 0x55, - (byte) 0x04, (byte) 0x03, (byte) 0x0c, (byte) 0x32, (byte) 0x41, - (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, - (byte) 0x64, (byte) 0x20, (byte) 0x4b, (byte) 0x65, (byte) 0x79, - (byte) 0x73, (byte) 0x74, (byte) 0x6f, (byte) 0x72, (byte) 0x65, - (byte) 0x20, (byte) 0x53, (byte) 0x6f, (byte) 0x66, (byte) 0x74, - (byte) 0x77, (byte) 0x61, (byte) 0x72, (byte) 0x65, (byte) 0x20, - (byte) 0x41, (byte) 0x74, (byte) 0x74, (byte) 0x65, (byte) 0x73, - (byte) 0x74, (byte) 0x61, (byte) 0x74, (byte) 0x69, (byte) 0x6f, - (byte) 0x6e, (byte) 0x20, (byte) 0x49, (byte) 0x6e, (byte) 0x74, - (byte) 0x65, (byte) 0x72, (byte) 0x6d, (byte) 0x65, (byte) 0x64, - (byte) 0x69, (byte) 0x61, (byte) 0x74, (byte) 0x65 }; - // AttestationApplicationId ::= SEQUENCE { - // * packageInfoRecords SET OF PackageInfoRecord, - // * signatureDigests SET OF OCTET_STRING, - // * } - // * - // * PackageInfoRecord ::= SEQUENCE { - // * packageName OCTET_STRING, - // * version INTEGER, - // * } - private static final byte[] attAppId = {0x30, 0x10, 0x31, 0x0B, 0x30, 0x04, 0x05, 'A', 'B', 'C', - 'D', 'E', 0x02, 0x01, 0x01, 0x31, 0x02, 0x04, 0x00}; - private static final byte[] attChallenge = {'c','h','a','l','l','e','n','g','e'}; - private static final byte[] expiryTime = {(byte)0x32, (byte)0x36, (byte)0x30, (byte)0x31, (byte)0x30, (byte)0x38, (byte)0x30, (byte)0x30, (byte)0x34, (byte)0x36, (byte)0x30, (byte)0x39, (byte)0x5a}; - private static final byte[] authKeyId = { (byte)0x80, (byte)0x14, (byte)0xc8, (byte)0xad, (byte)0xe9, (byte)0x77, (byte)0x4c, (byte)0x45, (byte)0xc3, (byte)0xa3, (byte)0xcf, (byte)0x0d, (byte)0x16, (byte)0x10, (byte)0xe4, (byte)0x79, (byte)0x43, (byte)0x3a, (byte)0x21, (byte)0x5a, (byte)0x30, (byte)0xcf}; - - private KMSEProvider sim; - private CardSimulator simulator; - private KMEncoder encoder; - private KMDecoder decoder; - private KMSEProvider cryptoProvider; - - public KMFunctionalTest(){ - cryptoProvider = KMSEProviderImpl.instance(false); - sim = KMSEProviderImpl.instance(false); - simulator = new CardSimulator(); - encoder = new KMEncoder(); - decoder = new KMDecoder(); - } - - private void init(){ - // Create simulator - AID appletAID = AIDUtil.create("A000000062"); - simulator.installApplet(appletAID, KMKeymasterApplet.class); - // Select applet - simulator.selectApplet(appletAID); - // provision attest key - provisionCmd(simulator); - } - - private void setBootParams(CardSimulator simulator, short osVersion, - short osPatchLevel, short vendorPatchLevel, short bootPatchLevel) { - // Argument 1 OS Version - short versionPtr = KMInteger.uint_16(osVersion); - // short versionTagPtr = KMIntegerTag.instance(KMType.UINT_TAG, - // KMType.OS_VERSION,versionPatchPtr); - // Argument 2 OS Patch level - short patchPtr = KMInteger.uint_16(osPatchLevel); - short vendorpatchPtr = KMInteger.uint_16((short) vendorPatchLevel); - short bootpatchPtr = KMInteger.uint_16((short) bootPatchLevel); - // Argument 3 Verified Boot Key - byte[] bootKeyHash = "00011122233344455566677788899900".getBytes(); - short bootKeyPtr = KMByteBlob.instance(bootKeyHash, (short) 0, - (short) bootKeyHash.length); - // Argument 4 Verified Boot Hash - short bootHashPtr = KMByteBlob.instance(bootKeyHash, (short) 0, - (short) bootKeyHash.length); - // Argument 5 Verified Boot State - short bootStatePtr = KMEnum.instance(KMType.VERIFIED_BOOT_STATE, - KMType.VERIFIED_BOOT); - // Argument 6 Device Locked - short deviceLockedPtr = KMEnum.instance(KMType.DEVICE_LOCKED, - KMType.DEVICE_LOCKED_FALSE); - // Arguments - short arrPtr = KMArray.instance((short) 8); - KMArray vals = KMArray.cast(arrPtr); - vals.add((short) 0, versionPtr); - vals.add((short) 1, patchPtr); - vals.add((short) 2, vendorpatchPtr); - vals.add((short) 3, bootpatchPtr); - vals.add((short) 4, bootKeyPtr); - vals.add((short) 5, bootHashPtr); - vals.add((short) 6, bootStatePtr); - vals.add((short) 7, deviceLockedPtr); - CommandAPDU apdu = encodeApdu((byte) INS_SET_BOOT_PARAMS_CMD, arrPtr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - Assert.assertEquals(0x9000, response.getSW()); - - } - - private void provisionSigningCertificate(CardSimulator simulator) { - short byteBlobPtr = KMByteBlob.instance( - (short) (kEcAttestCert.length + kEcAttestRootCert.length)); - Util.arrayCopyNonAtomic(kEcAttestCert, (short) 0, - KMByteBlob.cast(byteBlobPtr).getBuffer(), - KMByteBlob.cast(byteBlobPtr).getStartOff(), - (short) kEcAttestCert.length); - Util.arrayCopyNonAtomic(kEcAttestRootCert, (short) 0, - KMByteBlob.cast(byteBlobPtr).getBuffer(), - (short) (KMByteBlob.cast(byteBlobPtr).getStartOff() - + kEcAttestCert.length), - (short) kEcAttestRootCert.length); - CommandAPDU apdu = encodeApdu( - (byte) INS_PROVISION_ATTESTATION_CERT_CHAIN_CMD, byteBlobPtr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - Assert.assertEquals(0x9000, response.getSW()); - } - - private void provisionSigningKey(CardSimulator simulator) { - // KeyParameters. - short arrPtr = KMArray.instance((short) 4); - short ecCurve = KMEnumTag.instance(KMType.ECCURVE, KMType.P_256); - short byteBlob = KMByteBlob.instance((short) 1); - KMByteBlob.cast(byteBlob).add((short) 0, KMType.SHA2_256); - short digest = KMEnumArrayTag.instance(KMType.DIGEST, byteBlob); - short byteBlob2 = KMByteBlob.instance((short) 1); - KMByteBlob.cast(byteBlob2).add((short) 0, KMType.ATTEST_KEY); - short purpose = KMEnumArrayTag.instance(KMType.PURPOSE, byteBlob2); - KMArray.cast(arrPtr).add((short) 0, ecCurve); - KMArray.cast(arrPtr).add((short) 1, digest); - KMArray.cast(arrPtr).add((short) 2, - KMEnumTag.instance(KMType.ALGORITHM, KMType.EC)); - KMArray.cast(arrPtr).add((short) 3, purpose); - short keyParams = KMKeyParameters.instance(arrPtr); - // Note: VTS uses PKCS8 KeyFormat RAW - short keyFormatPtr = KMEnum.instance(KMType.KEY_FORMAT, KMType.RAW); - - // Key - short signKeyPtr = KMArray.instance((short) 2); - KMArray.cast(signKeyPtr).add((short) 0, KMByteBlob.instance(kEcPrivKey, - (short) 0, (short) kEcPrivKey.length)); - KMArray.cast(signKeyPtr).add((short) 1, KMByteBlob.instance(kEcPubKey, - (short) 0, (short) kEcPubKey.length)); - byte[] keyBuf = new byte[120]; - short len = encoder.encode(signKeyPtr, keyBuf, (short) 0); - short signKeyBstr = KMByteBlob.instance(keyBuf, (short) 0, len); - - short finalArrayPtr = KMArray.instance((short) 3); - KMArray.cast(finalArrayPtr).add((short) 0, keyParams); - KMArray.cast(finalArrayPtr).add((short) 1, keyFormatPtr); - KMArray.cast(finalArrayPtr).add((short) 2, signKeyBstr); - - CommandAPDU apdu = encodeApdu((byte) INS_PROVISION_ATTESTATION_KEY_CMD, - finalArrayPtr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - Assert.assertEquals(0x9000, response.getSW()); - } - - private void provisionCertificateParams(CardSimulator simulator) { - - short arrPtr = KMArray.instance((short) 3); - short byteBlob1 = KMByteBlob.instance(X509Issuer, (short) 0, - (short) X509Issuer.length); - KMArray.cast(arrPtr).add((short) 0, byteBlob1); - short byteBlob2 = KMByteBlob.instance(expiryTime, (short) 0, - (short) expiryTime.length); - KMArray.cast(arrPtr).add((short) 1, byteBlob2); - short byteBlob3 = KMByteBlob.instance(authKeyId, (short) 0, - (short) authKeyId.length); - KMArray.cast(arrPtr).add((short) 2, byteBlob3); - - CommandAPDU apdu = encodeApdu( - (byte) INS_PROVISION_ATTESTATION_CERT_PARAMS_CMD, arrPtr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - Assert.assertEquals(0x9000, response.getSW()); - } - - private void provisionSharedSecret(CardSimulator simulator) { - byte[] sharedKeySecret = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - short arrPtr = KMArray.instance((short) 1); - short byteBlob = KMByteBlob.instance(sharedKeySecret, (short) 0, - (short) sharedKeySecret.length); - KMArray.cast(arrPtr).add((short) 0, byteBlob); - - CommandAPDU apdu = encodeApdu((byte) INS_PROVISION_SHARED_SECRET_CMD, - arrPtr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - Assert.assertEquals(0x9000, response.getSW()); - } - - private void provisionAttestIds(CardSimulator simulator) { - short arrPtr = KMArray.instance((short) 8); - - byte[] buf = "Attestation Id".getBytes(); - - KMArray.cast(arrPtr).add((short) 0, - KMByteTag.instance(KMType.ATTESTATION_ID_BRAND, - KMByteBlob.instance(buf, (short) 0, (short) buf.length))); - KMArray.cast(arrPtr).add((short) 1, - KMByteTag.instance(KMType.ATTESTATION_ID_PRODUCT, - KMByteBlob.instance(buf, (short) 0, (short) buf.length))); - KMArray.cast(arrPtr).add((short) 2, - KMByteTag.instance(KMType.ATTESTATION_ID_DEVICE, - KMByteBlob.instance(buf, (short) 0, (short) buf.length))); - KMArray.cast(arrPtr).add((short) 3, - KMByteTag.instance(KMType.ATTESTATION_ID_MODEL, - KMByteBlob.instance(buf, (short) 0, (short) buf.length))); - KMArray.cast(arrPtr).add((short) 4, - KMByteTag.instance(KMType.ATTESTATION_ID_IMEI, - KMByteBlob.instance(buf, (short) 0, (short) buf.length))); - KMArray.cast(arrPtr).add((short) 5, - KMByteTag.instance(KMType.ATTESTATION_ID_MEID, - KMByteBlob.instance(buf, (short) 0, (short) buf.length))); - KMArray.cast(arrPtr).add((short) 6, - KMByteTag.instance(KMType.ATTESTATION_ID_MANUFACTURER, - KMByteBlob.instance(buf, (short) 0, (short) buf.length))); - KMArray.cast(arrPtr).add((short) 7, - KMByteTag.instance(KMType.ATTESTATION_ID_SERIAL, - KMByteBlob.instance(buf, (short) 0, (short) buf.length))); - short keyParams = KMKeyParameters.instance(arrPtr); - short outerArrPtr = KMArray.instance((short) 1); - KMArray.cast(outerArrPtr).add((short) 0, keyParams); - CommandAPDU apdu = encodeApdu((byte) INS_PROVISION_ATTEST_IDS_CMD, - outerArrPtr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - Assert.assertEquals(0x9000, response.getSW()); - } - - private void provisionLocked(CardSimulator simulator) { - CommandAPDU commandAPDU = new CommandAPDU(0x80, INS_LOCK_PROVISIONING_CMD, - 0x40, 0x00); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(commandAPDU); - Assert.assertEquals(0x9000, response.getSW()); - } - - private void provisionCmd(CardSimulator simulator) { - provisionSigningKey(simulator); - provisionSigningCertificate(simulator); - provisionCertificateParams(simulator); - provisionSharedSecret(simulator); - provisionAttestIds(simulator); - // set bootup parameters - setBootParams(simulator,(short)1,(short)1, (short)0, (short)0); - provisionLocked(simulator); - } - - private void cleanUp(){ - AID appletAID = AIDUtil.create("A000000062"); - // Delete i.e. uninstall applet - simulator.deleteApplet(appletAID); - } - - private void cleanUpBkUpStore(){ - AID appletAID = AIDUtil.create("A000000063"); - // Delete i.e. uninstall applet - simulator.deleteApplet(appletAID); - } - private CommandAPDU encodeApdu(byte ins, short cmd){ - byte[] buf = new byte[2500]; - buf[0] = (byte)0x80; - buf[1] = ins; - buf[2] = (byte)0x40; - buf[3] = (byte)0x00; - buf[4] = 0; - short len = encoder.encode(cmd, buf, (short) 7); - Util.setShort(buf, (short)5, len); - byte[] apdu = new byte[7+len]; - Util.arrayCopyNonAtomic(buf,(short)0,apdu,(short)0,(short)(7+len)); - //CommandAPDU commandAPDU = new CommandAPDU(0x80, 0x10, 0x40, 0x00, buf, 0, actualLen); - return new CommandAPDU(apdu); - } - - @Test - public void testAesImportKeySuccess() { - init(); - byte[] aesKeySecret = new byte[] {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - short arrPtr = KMArray.instance((short)5); - short boolTag = KMBoolTag.instance(KMType.NO_AUTH_REQUIRED); - short keySize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, KMInteger.uint_16((short)128)); - short byteBlob = KMByteBlob.instance((short)1); - KMByteBlob.cast(byteBlob).add((short)0, KMType.ECB); - short blockMode = KMEnumArrayTag.instance(KMType.BLOCK_MODE, byteBlob); - byteBlob = KMByteBlob.instance((short)1); - KMByteBlob.cast(byteBlob).add((short)0, KMType.PKCS7); - short paddingMode = KMEnumArrayTag.instance(KMType.PADDING, byteBlob); - KMArray.cast(arrPtr).add((short)0, boolTag); - KMArray.cast(arrPtr).add((short)1, keySize); - KMArray.cast(arrPtr).add((short)2, blockMode); - KMArray.cast(arrPtr).add((short)3, paddingMode); - KMArray.cast(arrPtr).add((short)4, KMEnumTag.instance(KMType.ALGORITHM, KMType.AES)); - short keyParams = KMKeyParameters.instance(arrPtr); - short keyFormatPtr = KMEnum.instance(KMType.KEY_FORMAT, KMType.RAW); - short keyBlob = KMArray.instance((short)1); - KMArray.cast(keyBlob).add((short)0, KMByteBlob.instance(aesKeySecret,(short)0,(short)16)); - byte[] blob = new byte[256]; - short len = encoder.encode(keyBlob,blob,(short)0); - keyBlob = KMByteBlob.instance(blob, (short)0, len); - arrPtr = KMArray.instance((short)3); - KMArray arg = KMArray.cast(arrPtr); - arg.add((short) 0, keyParams); - arg.add((short)1, keyFormatPtr); - arg.add((short)2, keyBlob); - CommandAPDU apdu = encodeApdu((byte)INS_IMPORT_KEY_CMD, arrPtr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - short ret = KMArray.instance((short) 3); - KMArray.cast(ret).add((short) 0, KMInteger.exp()); - KMArray.cast(ret).add((short)1, KMByteBlob.exp()); - short inst = KMKeyCharacteristics.exp(); - KMArray.cast(ret).add((short) 2, inst); - byte[] respBuf = response.getBytes(); - len = (short) respBuf.length; - ret = decoder.decode(ret, respBuf, (short) 0, len); - short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - short keyBlobLength = KMByteBlob.cast(KMArray.cast(ret).get((short)1)).length(); - short keyCharacteristics = KMArray.cast(ret).get((short)2); - short hwParams = KMKeyCharacteristics.cast(keyCharacteristics).getHardwareEnforced(); - short swParams = KMKeyCharacteristics.cast(keyCharacteristics).getSoftwareEnforced(); - Assert.assertEquals(0x9000, response.getSW()); - Assert.assertEquals(error, KMError.OK); - short tag = KMKeyParameters.findTag(KMType.BOOL_TAG, KMType.NO_AUTH_REQUIRED, hwParams); - Assert.assertEquals(KMBoolTag.cast(tag).getVal(),0x01); - tag = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.KEYSIZE, hwParams); - Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getShort(), 128); - tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PADDING, hwParams); - Assert.assertTrue(KMEnumArrayTag.cast(tag).contains(KMType.PKCS7)); - tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.BLOCK_MODE, hwParams); - Assert.assertTrue(KMEnumArrayTag.cast(tag).contains(KMType.ECB)); - tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, hwParams); - Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.AES); - tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ORIGIN, hwParams); - Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.IMPORTED); - cleanUp(); - } - - @Test - public void testHmacImportKeySuccess() { - init(); - byte[] hmacKeySecret = new byte[] {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - short arrPtr = KMArray.instance((short)5); - short boolTag = KMBoolTag.instance(KMType.NO_AUTH_REQUIRED); - short keySize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, KMInteger.uint_16((short)128)); - short byteBlob = KMByteBlob.instance((short)1); - KMByteBlob.cast(byteBlob).add((short)0, KMType.SHA2_256); - short digest = KMEnumArrayTag.instance(KMType.DIGEST, byteBlob); - short minMacLength = KMIntegerTag.instance(KMType.UINT_TAG,KMType.MIN_MAC_LENGTH, KMInteger.uint_16((short)256)); - KMArray.cast(arrPtr).add((short)0, boolTag); - KMArray.cast(arrPtr).add((short)1, keySize); - KMArray.cast(arrPtr).add((short)2, digest); - KMArray.cast(arrPtr).add((short)3, minMacLength); - KMArray.cast(arrPtr).add((short)4, KMEnumTag.instance(KMType.ALGORITHM, KMType.HMAC)); - short keyParams = KMKeyParameters.instance(arrPtr); - short keyFormatPtr = KMEnum.instance(KMType.KEY_FORMAT, KMType.RAW); - short keyBlob = KMArray.instance((short)1); - KMArray.cast(keyBlob).add((short)0, KMByteBlob.instance(hmacKeySecret,(short)0,(short)16)); - byte[] blob = new byte[256]; - short len = encoder.encode(keyBlob,blob,(short)0); - keyBlob = KMByteBlob.instance(blob, (short)0, len); - arrPtr = KMArray.instance((short)3); - KMArray arg = KMArray.cast(arrPtr); - arg.add((short) 0, keyParams); - arg.add((short)1, keyFormatPtr); - arg.add((short)2, keyBlob); - CommandAPDU apdu = encodeApdu((byte)INS_IMPORT_KEY_CMD, arrPtr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - short ret = KMArray.instance((short) 3); - KMArray.cast(ret).add((short) 0, KMInteger.exp()); - KMArray.cast(ret).add((short)1, KMByteBlob.exp()); - short inst = KMKeyCharacteristics.exp(); - KMArray.cast(ret).add((short) 2, inst); - byte[] respBuf = response.getBytes(); - len = (short) respBuf.length; - ret = decoder.decode(ret, respBuf, (short) 0, len); - short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - short keyBlobLength = KMByteBlob.cast(KMArray.cast(ret).get((short)1)).length(); - short keyCharacteristics = KMArray.cast(ret).get((short)2); - short hwParams = KMKeyCharacteristics.cast(keyCharacteristics).getHardwareEnforced(); - short swParams = KMKeyCharacteristics.cast(keyCharacteristics).getSoftwareEnforced(); - Assert.assertEquals(0x9000, response.getSW()); - Assert.assertEquals(error, KMError.OK); - short tag = KMKeyParameters.findTag(KMType.BOOL_TAG, KMType.NO_AUTH_REQUIRED, hwParams); - Assert.assertEquals(KMBoolTag.cast(tag).getVal(),0x01); - tag = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.KEYSIZE, hwParams); - Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getShort(), 128); - tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.DIGEST, hwParams); - Assert.assertTrue(KMEnumArrayTag.cast(tag).contains(KMType.SHA2_256)); - tag = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, hwParams); - Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getShort(), 256); - tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, hwParams); - Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.HMAC); - tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ORIGIN, hwParams); - Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.IMPORTED); - cleanUp(); - } - - @Test - public void testRsaImportKeySuccess() { - init(); - /* - KeyPair rsaKeyPair = cryptoProvider.createRsaKeyPair(); - byte[] pub = new byte[4]; - short len = ((RSAPublicKey)rsaKeyPair.getPublic()).getExponent(pub,(short)1); - byte[] priv = new byte[256]; - byte[] mod = new byte[256]; - len = ((RSAPrivateKey)rsaKeyPair.getPrivate()).getModulus(mod,(short)0); - len = ((RSAPrivateKey)rsaKeyPair.getPrivate()).getExponent(priv,(short)0); - */ - - byte[] pub = new byte[]{0x00,0x01,0x00,0x01}; - byte[] mod = new byte[256]; - byte[] priv = new byte[256]; - short[] lengths = new short[2]; - cryptoProvider.createAsymmetricKey(KMType.RSA,priv,(short)0,(short)256,mod,(short)0, (short)256,lengths); - short arrPtr = KMArray.instance((short)6); - short boolTag = KMBoolTag.instance(KMType.NO_AUTH_REQUIRED); - short keySize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, KMInteger.uint_16((short)2048)); - short byteBlob = KMByteBlob.instance((short)1); - KMByteBlob.cast(byteBlob).add((short)0, KMType.SHA2_256); - short digest = KMEnumArrayTag.instance(KMType.DIGEST, byteBlob); - short rsaPubExpTag = KMIntegerTag.instance(KMType.ULONG_TAG,KMType.RSA_PUBLIC_EXPONENT, - KMInteger.uint_32(pub, (short)0)); - byteBlob = KMByteBlob.instance((short)1); - KMByteBlob.cast(byteBlob).add((short)0, KMType.RSA_PSS); - short padding = KMEnumArrayTag.instance(KMType.PADDING, byteBlob); - KMArray.cast(arrPtr).add((short)0, boolTag); - KMArray.cast(arrPtr).add((short)1, keySize); - KMArray.cast(arrPtr).add((short)2, digest); - KMArray.cast(arrPtr).add((short)3, rsaPubExpTag); - KMArray.cast(arrPtr).add((short)4, KMEnumTag.instance(KMType.ALGORITHM, KMType.RSA)); - KMArray.cast(arrPtr).add((short)5, padding); - short keyParams = KMKeyParameters.instance(arrPtr); - short keyFormatPtr = KMEnum.instance(KMType.KEY_FORMAT, KMType.RAW);// Note: VTS uses PKCS8 - short keyBlob = KMArray.instance((short)2); - KMArray.cast(keyBlob).add((short)0, KMByteBlob.instance(priv,(short)0,(short)256)); - KMArray.cast(keyBlob).add((short)1, KMByteBlob.instance(mod,(short)0,(short)256)); - byte[] blob = new byte[620]; - short len = encoder.encode(keyBlob,blob,(short)0); - keyBlob = KMByteBlob.instance(blob, (short)0, len); - arrPtr = KMArray.instance((short)3); - KMArray arg = KMArray.cast(arrPtr); - arg.add((short) 0, keyParams); - arg.add((short)1, keyFormatPtr); - arg.add((short)2, keyBlob); - CommandAPDU apdu = encodeApdu((byte)INS_IMPORT_KEY_CMD, arrPtr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - short ret = KMArray.instance((short) 3); - KMArray.cast(ret).add((short) 0, KMInteger.exp()); - KMArray.cast(ret).add((short)1, KMByteBlob.exp()); - short inst = KMKeyCharacteristics.exp(); - KMArray.cast(ret).add((short) 2, inst); - byte[] respBuf = response.getBytes(); - len = (short) respBuf.length; - ret = decoder.decode(ret, respBuf, (short) 0, len); - short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - short keyBlobLength = KMByteBlob.cast(KMArray.cast(ret).get((short)1)).length(); - short keyCharacteristics = KMArray.cast(ret).get((short)2); - short hwParams = KMKeyCharacteristics.cast(keyCharacteristics).getHardwareEnforced(); - short swParams = KMKeyCharacteristics.cast(keyCharacteristics).getSoftwareEnforced(); - Assert.assertEquals(0x9000, response.getSW()); - Assert.assertEquals(error, KMError.OK); - short tag = KMKeyParameters.findTag(KMType.BOOL_TAG, KMType.NO_AUTH_REQUIRED, hwParams); - Assert.assertEquals(KMBoolTag.cast(tag).getVal(),0x01); - tag = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.KEYSIZE, hwParams); - Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getShort(), 2048); - tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.DIGEST, hwParams); - Assert.assertTrue(KMEnumArrayTag.cast(tag).contains(KMType.SHA2_256)); - tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PADDING, hwParams); - Assert.assertTrue(KMEnumArrayTag.cast(tag).contains(KMType.RSA_PSS)); - tag = KMKeyParameters.findTag(KMType.ULONG_TAG, KMType.RSA_PUBLIC_EXPONENT, hwParams); - Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getSignificantShort(), 0x01); - Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getShort(), 0x01); - tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, hwParams); - Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.RSA); - tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ORIGIN, hwParams); - Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.IMPORTED); - cleanUp(); - } - - @Test - public void testDeviceLocked(){ - init(); - byte[] hmacKey = new byte[32]; - cryptoProvider.newRandomNumber(hmacKey,(short)0,(short)32); - KMRepository.instance().initComputedHmac(hmacKey,(short)0,(short)32); - // generate aes key with unlocked_device_required - short aesKey = generateAesDesKey(KMType.AES,(short)128,null,null, true); - short keyBlobPtr = KMArray.cast(aesKey).get((short)1); - byte[] keyBlob= new byte[KMByteBlob.cast(keyBlobPtr).length()]; - Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), - KMByteBlob.cast(keyBlobPtr).getStartOff(), - keyBlob,(short)0, (short)keyBlob.length); - // encrypt something - short inParams = getAesDesParams(KMType.AES, KMType.ECB, KMType.PKCS7, null); - byte[] plainData= "Hello World 123!".getBytes(); - short ret = processMessage(plainData, - KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), - KMType.ENCRYPT, - KMKeyParameters.instance(inParams), - (short)0,null,false, false - ); - keyBlobPtr = KMArray.cast(ret).get((short)2); - byte[] cipherData = new byte[KMByteBlob.cast(keyBlobPtr).length()]; - Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), - cipherData,(short)0, (short)cipherData.length); - // create verification token - short verToken = KMVerificationToken.instance(); - KMVerificationToken.cast(verToken).setTimestamp(KMInteger.uint_16((short)1)); - verToken = signVerificationToken(verToken); - // device locked request - deviceLock(verToken); - // decrypt should fail - inParams = getAesDesParams(KMType.AES, KMType.ECB, KMType.PKCS7, null); - short beginResp = begin(KMType.DECRYPT, - KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), KMKeyParameters.instance(inParams), (short)0); - Assert.assertEquals(beginResp,KMError.DEVICE_LOCKED); - short hwToken = KMHardwareAuthToken.instance(); - KMHardwareAuthToken.cast(hwToken).setTimestamp(KMInteger.uint_16((byte)2)); - KMHardwareAuthToken.cast(hwToken).setHwAuthenticatorType(KMEnum.instance(KMType.USER_AUTH_TYPE, (byte)KMType.PASSWORD)); - inParams = getAesDesParams(KMType.AES, KMType.ECB, KMType.PKCS7, null); - hwToken = signHwToken(hwToken); - ret = processMessage(cipherData, - KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), - KMType.DECRYPT, - KMKeyParameters.instance(inParams),hwToken,null,false, false - ); - ret = KMArray.cast(ret).get((short)0); - Assert.assertEquals(KMInteger.cast(ret).getShort(), KMError.OK); - cleanUp(); - } - - private short signHwToken(short hwToken){ - short len = 0; - byte[] scratchPad = new byte[256]; - // add 0 - Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0); - len = 1; - // concatenate challenge - 8 bytes - short ptr = KMHardwareAuthToken.cast(hwToken).getChallenge(); - KMInteger.cast(ptr) - .value(scratchPad, (short) (len + (short) (8 - KMInteger.cast(ptr).length()))); - len += 8; - // concatenate user id - 8 bytes - ptr = KMHardwareAuthToken.cast(hwToken).getUserId(); - KMInteger.cast(ptr) - .value(scratchPad, (short) (len + (short) (8 - KMInteger.cast(ptr).length()))); - len += 8; - // concatenate authenticator id - 8 bytes - ptr = KMHardwareAuthToken.cast(hwToken).getAuthenticatorId(); - KMInteger.cast(ptr) - .value(scratchPad, (short) (len + (short) (8 - KMInteger.cast(ptr).length()))); - len += 8; - // concatenate authenticator type - 4 bytes - ptr = KMHardwareAuthToken.cast(hwToken).getHwAuthenticatorType(); - scratchPad[(short) (len + 3)] = KMEnum.cast(ptr).getVal(); - len += 4; - // concatenate timestamp -8 bytes - ptr = KMHardwareAuthToken.cast(hwToken).getTimestamp(); - KMInteger.cast(ptr) - .value(scratchPad, (short) (len + (short) (8 - KMInteger.cast(ptr).length()))); - len += 8; - // hmac the data -/* HMACKey key = - cryptoProvider.createHMACKey( - KMRepository.instance().getComputedHmacKey(), - (short) 0, - (short) KMRepository.instance().getComputedHmacKey().length); - - */ - byte[] mac = new byte[32]; - /* - len = - cryptoProvider.hmacSign(key, scratchPad, (short) 0, len, - mac, - (short)0); - */ - short key = KMRepository.instance().getComputedHmacKey(); - cryptoProvider.hmacSign( - KMByteBlob.cast(key).getBuffer(), - KMByteBlob.cast(key).getStartOff(), - KMByteBlob.cast(key).length(), - scratchPad, (short) 0, len, - mac, - (short)0); - KMHardwareAuthToken.cast(hwToken).setMac(KMByteBlob.instance(mac,(short)0,(short)mac.length)); - return hwToken; - } - private void deviceLock(short verToken) { - short req = KMArray.instance((short)2); - KMArray.cast(req).add((short)0, KMInteger.uint_8((byte)1)); - KMArray.cast(req).add((short)1, verToken); - CommandAPDU apdu = encodeApdu((byte)INS_DEVICE_LOCKED_CMD,req); - ResponseAPDU response = simulator.transmitCommand(apdu); - short ret = KMArray.instance((short) 1); - KMArray.cast(ret).add((short) 0, KMInteger.exp()); - byte[] respBuf = response.getBytes(); - Assert.assertEquals(respBuf[0],KMError.OK); - } - - private short signVerificationToken(short verToken) { - byte[] scratchPad = new byte[256]; - byte[] authVer = "Auth Verification".getBytes(); - //print(authVer,(short)0,(short)authVer.length); - // concatenation length will be 37 + length of verified parameters list - which is typically empty - Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0); - short params = KMVerificationToken.cast(verToken).getParametersVerified(); - // Add "Auth Verification" - 17 bytes. - Util.arrayCopy(authVer,(short)0, scratchPad, (short)0, (short)authVer.length); - short len = (short)authVer.length; - // concatenate challenge - 8 bytes - short ptr = KMVerificationToken.cast(verToken).getChallenge(); - KMInteger.cast(ptr) - .value(scratchPad, (short) (len + (short) (8 - KMInteger.cast(ptr).length()))); - len += 8; - // concatenate timestamp -8 bytes - ptr = KMVerificationToken.cast(verToken).getTimestamp(); - KMInteger.cast(ptr) - .value(scratchPad, (short) (len + (short) (8 - KMInteger.cast(ptr).length()))); - len += 8; - // concatenate security level - 4 bytes - ptr = KMVerificationToken.cast(verToken).getSecurityLevel(); - scratchPad[(short) (len + 3)] = KMEnum.cast(ptr).getVal(); - len += 4; - // concatenate Parameters verified - blob of encoded data. - ptr = KMVerificationToken.cast(verToken).getParametersVerified(); - if (KMByteBlob.cast(ptr).length() != 0) { - len += KMByteBlob.cast(ptr).getValues(scratchPad, (short) 0); - } - // hmac the data - /* HMACKey key = - cryptoProvider.createHMACKey( - KMRepository.instance().getComputedHmacKey(), - (short) 0, - (short) KMRepository.instance().getComputedHmacKey().length); - - */ - ptr = KMVerificationToken.cast(verToken).getMac(); - byte[] mac = new byte[32]; - /*len = - cryptoProvider.hmacSign(key, scratchPad, (short) 0, len, - mac, - (short)0); - */ - short key = KMRepository.instance().getComputedHmacKey(); - cryptoProvider.hmacSign(KMByteBlob.cast(key).getBuffer(), - KMByteBlob.cast(key).getStartOff(), - KMByteBlob.cast(key).length(), - scratchPad, (short) 0, len, - mac, - (short)0); - KMVerificationToken.cast(verToken).setMac(KMByteBlob.instance(mac,(short)0,(short)mac.length)); - return verToken; - } - - @Test - public void testEcImportKeySuccess() { - init(); - /* - KeyPair ecKeyPair = cryptoProvider.createECKeyPair(); - byte[] pub = new byte[128]; - short len = ((ECPublicKey)ecKeyPair.getPublic()).getW(pub,(short)0); - byte[] priv = new byte[128]; - len = ((ECPrivateKey)ecKeyPair.getPrivate()).getS(priv,(short)0); - */ - byte[] pub = new byte[128]; - byte[] priv = new byte[128]; - short[] lengths = new short[2]; - cryptoProvider.createAsymmetricKey(KMType.EC,priv,(short)0,(short)128,pub,(short)0, (short)128,lengths); - short pubBlob = KMByteBlob.instance(pub,(short)0,lengths[1]); - short privBlob = KMByteBlob.instance(priv,(short)0,lengths[0]); - short arrPtr = KMArray.instance((short)5); - short boolTag = KMBoolTag.instance(KMType.NO_AUTH_REQUIRED); - short keySize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, KMInteger.uint_16((short)256)); - short byteBlob = KMByteBlob.instance((short)1); - KMByteBlob.cast(byteBlob).add((short)0, KMType.SHA2_256); - short digest = KMEnumArrayTag.instance(KMType.DIGEST, byteBlob); - short ecCurve = KMEnumTag.instance(KMType.ECCURVE, KMType.P_256); - KMArray.cast(arrPtr).add((short)0, boolTag); - KMArray.cast(arrPtr).add((short)1, keySize); - KMArray.cast(arrPtr).add((short)2, digest); - KMArray.cast(arrPtr).add((short)3, ecCurve); - KMArray.cast(arrPtr).add((short)4, KMEnumTag.instance(KMType.ALGORITHM, KMType.EC)); - short keyParams = KMKeyParameters.instance(arrPtr); - short keyFormatPtr = KMEnum.instance(KMType.KEY_FORMAT, KMType.RAW);// Note: VTS uses PKCS8 - short keyBlob = KMArray.instance((short)2); - KMArray.cast(keyBlob).add((short)0, privBlob); - KMArray.cast(keyBlob).add((short)1, pubBlob); - byte[] blob = new byte[128]; - short len = encoder.encode(keyBlob,blob,(short)0); - keyBlob = KMByteBlob.instance(blob, (short)0, len); - arrPtr = KMArray.instance((short)3); - KMArray arg = KMArray.cast(arrPtr); - arg.add((short) 0, keyParams); - arg.add((short)1, keyFormatPtr); - arg.add((short)2, keyBlob); - CommandAPDU apdu = encodeApdu((byte)INS_IMPORT_KEY_CMD, arrPtr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - short ret = KMArray.instance((short) 3); - KMArray.cast(ret).add((short) 0, KMInteger.exp()); - KMArray.cast(ret).add((short)1, KMByteBlob.exp()); - short inst = KMKeyCharacteristics.exp(); - KMArray.cast(ret).add((short) 2, inst); - byte[] respBuf = response.getBytes(); - len = (short) respBuf.length; - ret = decoder.decode(ret, respBuf, (short) 0, len); - short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - short keyBlobLength = KMByteBlob.cast(KMArray.cast(ret).get((short)1)).length(); - short blobArr = extractKeyBlobArray(KMArray.cast(ret).get((short)1)); - short keyCharacteristics = KMArray.cast(ret).get((short)2); - short hwParams = KMKeyCharacteristics.cast(keyCharacteristics).getHardwareEnforced(); - short swParams = KMKeyCharacteristics.cast(keyCharacteristics).getSoftwareEnforced(); - Assert.assertEquals(0x9000, response.getSW()); - Assert.assertEquals(error, KMError.OK); - short tag = KMKeyParameters.findTag(KMType.BOOL_TAG, KMType.NO_AUTH_REQUIRED, hwParams); - Assert.assertEquals(KMBoolTag.cast(tag).getVal(),0x01); - tag = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.KEYSIZE, hwParams); - Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getShort(), 256); - tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.DIGEST, hwParams); - Assert.assertTrue(KMEnumArrayTag.cast(tag).contains(KMType.SHA2_256)); - tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ECCURVE, hwParams); - Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.P_256); - tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, hwParams); - Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.EC); - tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ORIGIN, hwParams); - Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.IMPORTED); - cleanUp(); - } - - private short extractKeyBlobArray(short keyBlob) { - short ret = KMArray.instance((short) 5); - KMArray.cast(ret).add(KMKeymasterApplet.KEY_BLOB_SECRET, KMByteBlob.exp()); - KMArray.cast(ret).add(KMKeymasterApplet.KEY_BLOB_AUTH_TAG, KMByteBlob.exp()); - KMArray.cast(ret).add(KMKeymasterApplet.KEY_BLOB_NONCE, KMByteBlob.exp()); - short ptr = KMKeyCharacteristics.exp(); - KMArray.cast(ret).add(KMKeymasterApplet.KEY_BLOB_KEYCHAR, ptr); - KMArray.cast(ret).add(KMKeymasterApplet.KEY_BLOB_PUB_KEY, KMByteBlob.exp()); - ret = - decoder.decodeArray( - ret, - KMByteBlob.cast(keyBlob).getBuffer(), - KMByteBlob.cast(keyBlob).getStartOff(), - KMByteBlob.cast(keyBlob).length()); - short len = KMArray.cast(ret).length(); - ptr = KMArray.cast(ret).get((short)4); -// print(KMByteBlob.cast(ptr).getBuffer(),KMByteBlob.cast(ptr).getStartOff(),KMByteBlob.cast(ptr).length()); - return ret; - } - - @Test - public void testRsaGenerateKeySuccess() { - init(); - short ret = generateRsaKey(null, null); - short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - short keyBlobLength = KMByteBlob.cast(KMArray.cast(ret).get((short)1)).length(); - short keyCharacteristics = KMArray.cast(ret).get((short)2); - short hwParams = KMKeyCharacteristics.cast(keyCharacteristics).getHardwareEnforced(); - short swParams = KMKeyCharacteristics.cast(keyCharacteristics).getSoftwareEnforced(); - Assert.assertEquals(error, KMError.OK); - short tag = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.KEYSIZE, hwParams); - Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getShort(), 2048); - tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.DIGEST, hwParams); - Assert.assertTrue(KMEnumArrayTag.cast(tag).contains(KMType.DIGEST_NONE)); - tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PADDING, hwParams); - Assert.assertTrue(KMEnumArrayTag.cast(tag).contains(KMType.RSA_PKCS1_1_5_ENCRYPT)); - tag = KMKeyParameters.findTag(KMType.ULONG_TAG, KMType.RSA_PUBLIC_EXPONENT, hwParams); - Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getSignificantShort(), 0x01); - Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getShort(), 0x01); - tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, hwParams); - Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.RSA); - tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ORIGIN, hwParams); - Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.GENERATED); - cleanUp(); - } - - private short generateRsaKey(byte[] clientId, byte[] appData){ - byte[] activeAndCreationDateTime = {0,0,0x01,0x73,0x51,0x7C,(byte)0xCC,0x00}; - short tagCount = 11; - if(clientId != null) tagCount++; - if(appData != null) tagCount++; - short arrPtr = KMArray.instance(tagCount); - short keySize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, KMInteger.uint_16((short)2048)); - short byteBlob = KMByteBlob.instance((short)3); - KMByteBlob.cast(byteBlob).add((short)0, KMType.DIGEST_NONE); - KMByteBlob.cast(byteBlob).add((short)1, KMType.SHA2_256); - KMByteBlob.cast(byteBlob).add((short)2, KMType.SHA1); - short digest = KMEnumArrayTag.instance(KMType.DIGEST, byteBlob); - byteBlob = KMByteBlob.instance((short)5); - KMByteBlob.cast(byteBlob).add((short)0, KMType.RSA_PKCS1_1_5_ENCRYPT); - KMByteBlob.cast(byteBlob).add((short)1, KMType.RSA_PKCS1_1_5_SIGN); - KMByteBlob.cast(byteBlob).add((short)2, KMType.RSA_OAEP); - KMByteBlob.cast(byteBlob).add((short)3, KMType.RSA_PSS); - KMByteBlob.cast(byteBlob).add((short)4, KMType.PADDING_NONE); - short padding = KMEnumArrayTag.instance(KMType.PADDING, byteBlob); - byteBlob = KMByteBlob.instance((short)5); - KMByteBlob.cast(byteBlob).add((short)0, KMType.SIGN); - KMByteBlob.cast(byteBlob).add((short)1, KMType.VERIFY); - KMByteBlob.cast(byteBlob).add((short)2, KMType.ENCRYPT); - KMByteBlob.cast(byteBlob).add((short)3, KMType.DECRYPT); - KMByteBlob.cast(byteBlob).add((short)4, KMType.WRAP_KEY); - short purpose = KMEnumArrayTag.instance(KMType.PURPOSE, byteBlob); - byte[] pub = {0,1,0,1}; - short rsaPubExpTag = KMIntegerTag.instance(KMType.ULONG_TAG,KMType.RSA_PUBLIC_EXPONENT, KMInteger.uint_32(pub, (short)0)); - short boolTag = KMBoolTag.instance(KMType.NO_AUTH_REQUIRED); - short tagIndex = 0; - KMArray.cast(arrPtr).add(tagIndex++, purpose); - KMArray.cast(arrPtr).add(tagIndex++, KMBoolTag.instance(KMType.INCLUDE_UNIQUE_ID)); - KMArray.cast(arrPtr).add(tagIndex++, KMBoolTag.instance(KMType.RESET_SINCE_ID_ROTATION)); - KMArray.cast(arrPtr).add(tagIndex++, boolTag); - KMArray.cast(arrPtr).add(tagIndex++, keySize); - KMArray.cast(arrPtr).add(tagIndex++, digest); - KMArray.cast(arrPtr).add(tagIndex++, rsaPubExpTag); - KMArray.cast(arrPtr).add(tagIndex++, KMEnumTag.instance(KMType.ALGORITHM, KMType.RSA)); - KMArray.cast(arrPtr).add(tagIndex++, padding); - short dateTag = KMInteger.uint_64(activeAndCreationDateTime,(short)0); - KMArray.cast(arrPtr).add(tagIndex++, KMIntegerTag.instance(KMType.DATE_TAG,KMType.ACTIVE_DATETIME,dateTag)); - KMArray.cast(arrPtr).add(tagIndex++, KMIntegerTag.instance(KMType.DATE_TAG,KMType.CREATION_DATETIME,dateTag)); - - if(clientId != null)KMArray.cast(arrPtr).add(tagIndex++, - KMByteTag.instance(KMType.APPLICATION_ID, KMByteBlob.instance(clientId,(short)0,(short)clientId.length))); - if(appData != null)KMArray.cast(arrPtr).add(tagIndex++, - KMByteTag.instance(KMType.APPLICATION_DATA, KMByteBlob.instance(appData,(short)0,(short)appData.length))); - short keyParams = KMKeyParameters.instance(arrPtr); - arrPtr = KMArray.instance((short)1); - KMArray arg = KMArray.cast(arrPtr); - arg.add((short) 0, keyParams); - CommandAPDU apdu = encodeApdu((byte)INS_GENERATE_KEY_CMD, arrPtr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - Assert.assertEquals(0x9000, response.getSW()); - short ret = KMArray.instance((short) 3); - KMArray.cast(ret).add((short) 0, KMInteger.exp()); - KMArray.cast(ret).add((short)1, KMByteBlob.exp()); - short inst = KMKeyCharacteristics.exp(); - KMArray.cast(ret).add((short) 2, inst); - byte[] respBuf = response.getBytes(); - short len = (short) respBuf.length; - ret = decoder.decode(ret, respBuf, (short) 0, len); - return ret; - } - - private short generateAttestationKey(){ - // 15th July 2020 00.00.00 - byte[] activeAndCreationDateTime = {0,0,0x01,0x73,0x51,0x7C,(byte)0xCC,0x00}; - short tagCount = 11; - short arrPtr = KMArray.instance(tagCount); - short keySize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, KMInteger.uint_16((short)2048)); - short byteBlob = KMByteBlob.instance((short)3); - KMByteBlob.cast(byteBlob).add((short)0, KMType.DIGEST_NONE); - KMByteBlob.cast(byteBlob).add((short)1, KMType.SHA2_256); - KMByteBlob.cast(byteBlob).add((short)2, KMType.SHA1); - short digest = KMEnumArrayTag.instance(KMType.DIGEST, byteBlob); - byteBlob = KMByteBlob.instance((short)1); - KMByteBlob.cast(byteBlob).add((short)0, KMType.RSA_PKCS1_1_5_SIGN); - short padding = KMEnumArrayTag.instance(KMType.PADDING, byteBlob); - byteBlob = KMByteBlob.instance((short)1); - KMByteBlob.cast(byteBlob).add((short)0, KMType.ATTEST_KEY); - short purpose = KMEnumArrayTag.instance(KMType.PURPOSE, byteBlob); - byte[] pub = {0,1,0,1}; - short rsaPubExpTag = KMIntegerTag.instance(KMType.ULONG_TAG,KMType.RSA_PUBLIC_EXPONENT, KMInteger.uint_32(pub, (short)0)); - short boolTag = KMBoolTag.instance(KMType.NO_AUTH_REQUIRED); - short tagIndex = 0; - KMArray.cast(arrPtr).add(tagIndex++, purpose); - KMArray.cast(arrPtr).add(tagIndex++, boolTag); - KMArray.cast(arrPtr).add(tagIndex++, KMBoolTag.instance(KMType.INCLUDE_UNIQUE_ID)); - KMArray.cast(arrPtr).add(tagIndex++, KMBoolTag.instance(KMType.RESET_SINCE_ID_ROTATION)); - KMArray.cast(arrPtr).add(tagIndex++, boolTag); - KMArray.cast(arrPtr).add(tagIndex++, keySize); - KMArray.cast(arrPtr).add(tagIndex++, digest); - KMArray.cast(arrPtr).add(tagIndex++, rsaPubExpTag); - KMArray.cast(arrPtr).add(tagIndex++, KMEnumTag.instance(KMType.ALGORITHM, KMType.RSA)); - KMArray.cast(arrPtr).add(tagIndex++, padding); - short dateTag = KMInteger.uint_64(activeAndCreationDateTime,(short)0); - KMArray.cast(arrPtr).add(tagIndex++, KMIntegerTag.instance(KMType.ULONG_TAG,KMType.ACTIVE_DATETIME,dateTag)); - KMArray.cast(arrPtr).add(tagIndex++, KMIntegerTag.instance(KMType.ULONG_TAG,KMType.CREATION_DATETIME,dateTag)); - short keyParams = KMKeyParameters.instance(arrPtr); - arrPtr = KMArray.instance((short)1); - KMArray arg = KMArray.cast(arrPtr); - arg.add((short) 0, keyParams); - CommandAPDU apdu = encodeApdu((byte)INS_GENERATE_KEY_CMD, arrPtr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - Assert.assertEquals(0x9000, response.getSW()); - short ret = KMArray.instance((short) 3); - KMArray.cast(ret).add((short) 0, KMInteger.exp()); - KMArray.cast(ret).add((short)1, KMByteBlob.exp()); - short inst = KMKeyCharacteristics.exp(); - KMArray.cast(ret).add((short) 2, inst); - byte[] respBuf = response.getBytes(); - short len = (short) respBuf.length; - ret = decoder.decode(ret, respBuf, (short) 0, len); - return ret; - } - - @Test - public void testEcGenerateKeySuccess() { - init(); - short ret = generateEcKey(null, null); - short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - short keyBlobLength = KMByteBlob.cast(KMArray.cast(ret).get((short)1)).length(); - short keyCharacteristics = KMArray.cast(ret).get((short)2); - short hwParams = KMKeyCharacteristics.cast(keyCharacteristics).getHardwareEnforced(); - short swParams = KMKeyCharacteristics.cast(keyCharacteristics).getSoftwareEnforced(); - Assert.assertEquals(error, KMError.OK); - short tag = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.KEYSIZE, hwParams); - Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getShort(), 256); - tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.DIGEST, hwParams); - Assert.assertTrue(KMEnumArrayTag.cast(tag).contains(KMType.DIGEST_NONE)); - tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, hwParams); - Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.EC); - tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ORIGIN, hwParams); - Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.GENERATED); - cleanUp(); - } - public short generateEcKey(byte[] clientId, byte[] appData) { - byte[] activeAndCreationDateTime = {0,0,0x01,0x73,0x51,0x7C,(byte)0xCC,0x00}; - short tagCount = 6; - if(clientId != null) tagCount++; - if(appData != null) tagCount++; - short arrPtr = KMArray.instance(tagCount); - short keySize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, KMInteger.uint_16((short)256)); - short byteBlob = KMByteBlob.instance((short)2); - KMByteBlob.cast(byteBlob).add((short)0, KMType.DIGEST_NONE); - KMByteBlob.cast(byteBlob).add((short)1, KMType.SHA2_256); - short digest = KMEnumArrayTag.instance(KMType.DIGEST, byteBlob); - byteBlob = KMByteBlob.instance((short)2); - KMByteBlob.cast(byteBlob).add((short)0, KMType.SIGN); - KMByteBlob.cast(byteBlob).add((short)1, KMType.VERIFY); - short purpose = KMEnumArrayTag.instance(KMType.PURPOSE, byteBlob); - short boolTag = KMBoolTag.instance(KMType.NO_AUTH_REQUIRED); - short tagIndex = 0; - KMArray.cast(arrPtr).add(tagIndex++, purpose); - KMArray.cast(arrPtr).add(tagIndex++, boolTag); - KMArray.cast(arrPtr).add(tagIndex++, keySize); - KMArray.cast(arrPtr).add(tagIndex++, digest); - KMArray.cast(arrPtr).add(tagIndex++, KMEnumTag.instance(KMType.ALGORITHM, KMType.EC)); - short dateTag = KMInteger.uint_64(activeAndCreationDateTime,(short)0); - KMArray.cast(arrPtr).add(tagIndex++, KMIntegerTag.instance(KMType.DATE_TAG,KMType.CREATION_DATETIME,dateTag)); - if(clientId != null)KMArray.cast(arrPtr).add(tagIndex++, - KMByteTag.instance(KMType.APPLICATION_ID, KMByteBlob.instance(clientId,(short)0,(short)clientId.length))); - if(appData != null)KMArray.cast(arrPtr).add(tagIndex++, - KMByteTag.instance(KMType.APPLICATION_DATA, KMByteBlob.instance(appData,(short)0,(short)appData.length))); - short keyParams = KMKeyParameters.instance(arrPtr); - arrPtr = KMArray.instance((short)1); - KMArray arg = KMArray.cast(arrPtr); - arg.add((short) 0, keyParams); - CommandAPDU apdu = encodeApdu((byte)INS_GENERATE_KEY_CMD, arrPtr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - Assert.assertEquals(0x9000, response.getSW()); - short ret = KMArray.instance((short) 3); - KMArray.cast(ret).add((short) 0, KMInteger.exp()); - KMArray.cast(ret).add((short)1, KMByteBlob.exp()); - short inst = KMKeyCharacteristics.exp(); - KMArray.cast(ret).add((short) 2, inst); - byte[] respBuf = response.getBytes(); - short len = (short) respBuf.length; - ret = decoder.decode(ret, respBuf, (short) 0, len); - return ret; - } - - @Test - public void testHmacGenerateKeySuccess() { - init(); - short ret = generateHmacKey(null, null); - short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - short keyBlobLength = KMByteBlob.cast(KMArray.cast(ret).get((short)1)).length(); - short keyCharacteristics = KMArray.cast(ret).get((short)2); - short hwParams = KMKeyCharacteristics.cast(keyCharacteristics).getHardwareEnforced(); - short swParams = KMKeyCharacteristics.cast(keyCharacteristics).getSoftwareEnforced(); - Assert.assertEquals(error, KMError.OK); - short tag = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.KEYSIZE, hwParams); - Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getShort(), 128); - tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.DIGEST, hwParams); - Assert.assertTrue(KMEnumArrayTag.cast(tag).contains(KMType.SHA2_256)); - tag = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, hwParams); - Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getShort(), 160); - tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, hwParams); - Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.HMAC); - tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ORIGIN, hwParams); - Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.GENERATED); - cleanUp(); - } - public short generateHmacKey(byte[] clientId, byte[] appData){ - short tagCount = 6; - if(clientId != null) tagCount++; - if(appData != null) tagCount++; - short arrPtr = KMArray.instance(tagCount); - short keySize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, KMInteger.uint_16((short)128)); - short byteBlob = KMByteBlob.instance((short)1); - KMByteBlob.cast(byteBlob).add((short)0, KMType.SHA2_256); - short digest = KMEnumArrayTag.instance(KMType.DIGEST, byteBlob); - byteBlob = KMByteBlob.instance((short)2); - KMByteBlob.cast(byteBlob).add((short)0, KMType.SIGN); - KMByteBlob.cast(byteBlob).add((short)1, KMType.VERIFY); - short purpose = KMEnumArrayTag.instance(KMType.PURPOSE, byteBlob); - short boolTag = KMBoolTag.instance(KMType.NO_AUTH_REQUIRED); - short minMacLen = KMIntegerTag.instance(KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, KMInteger.uint_16((short)/*256*/160)); - short tagIndex = 0; - KMArray.cast(arrPtr).add(tagIndex++, minMacLen); - KMArray.cast(arrPtr).add(tagIndex++, purpose); - KMArray.cast(arrPtr).add(tagIndex++, boolTag); - KMArray.cast(arrPtr).add(tagIndex++, keySize); - KMArray.cast(arrPtr).add(tagIndex++, digest); - KMArray.cast(arrPtr).add(tagIndex++, KMEnumTag.instance(KMType.ALGORITHM, KMType.HMAC)); - if(clientId != null)KMArray.cast(arrPtr).add(tagIndex++, - KMByteTag.instance(KMType.APPLICATION_ID, KMByteBlob.instance(clientId,(short)0,(short)clientId.length))); - if(appData != null)KMArray.cast(arrPtr).add(tagIndex++, - KMByteTag.instance(KMType.APPLICATION_DATA, KMByteBlob.instance(appData,(short)0,(short)appData.length))); - short keyParams = KMKeyParameters.instance(arrPtr); - arrPtr = KMArray.instance((short)1); - KMArray arg = KMArray.cast(arrPtr); - arg.add((short) 0, keyParams); - CommandAPDU apdu = encodeApdu((byte)INS_GENERATE_KEY_CMD, arrPtr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - short ret = KMArray.instance((short) 3); - KMArray.cast(ret).add((short) 0, KMInteger.exp()); - KMArray.cast(ret).add((short)1, KMByteBlob.exp()); - short inst = KMKeyCharacteristics.exp(); - KMArray.cast(ret).add((short) 2, inst); - byte[] respBuf = response.getBytes(); - short len = (short) respBuf.length; - ret = decoder.decode(ret, respBuf, (short) 0, len); - short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - Assert.assertEquals(0x9000, response.getSW()); - Assert.assertEquals(error, KMError.OK); - return ret; - } - public short generateAesDesKey(byte alg, short keysize, byte[] clientId, byte[] appData, boolean unlockReqd) { - short tagCount = 7; - if(clientId != null) tagCount++; - if(appData != null) tagCount++; - if(unlockReqd)tagCount++; - short arrPtr = KMArray.instance(tagCount); - short boolTag = KMBoolTag.instance(KMType.NO_AUTH_REQUIRED); - short keySize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, KMInteger.uint_16(keysize)); - short byteBlob = KMByteBlob.instance((short)3); - KMByteBlob.cast(byteBlob).add((short)0, KMType.ECB); - KMByteBlob.cast(byteBlob).add((short)1, KMType.CBC); - KMByteBlob.cast(byteBlob).add((short)2, KMType.CTR); - short blockModeTag = KMEnumArrayTag.instance(KMType.BLOCK_MODE, byteBlob); - byteBlob = KMByteBlob.instance((short)2); - KMByteBlob.cast(byteBlob).add((short)0, KMType.PKCS7); - KMByteBlob.cast(byteBlob).add((short)1, KMType.PADDING_NONE); - short paddingMode = KMEnumArrayTag.instance(KMType.PADDING, byteBlob); - byteBlob = KMByteBlob.instance((short)2); - KMByteBlob.cast(byteBlob).add((short)0, KMType.ENCRYPT); - KMByteBlob.cast(byteBlob).add((short)1, KMType.DECRYPT); - short purpose = KMEnumArrayTag.instance(KMType.PURPOSE, byteBlob); - short tagIndex = 0; - KMArray.cast(arrPtr).add(tagIndex++, boolTag); - KMArray.cast(arrPtr).add(tagIndex++, keySize); - KMArray.cast(arrPtr).add(tagIndex++, blockModeTag); - KMArray.cast(arrPtr).add(tagIndex++, paddingMode); - KMArray.cast(arrPtr).add(tagIndex++, KMEnumTag.instance(KMType.ALGORITHM, alg)); - KMArray.cast(arrPtr).add(tagIndex++, purpose); - KMArray.cast(arrPtr).add(tagIndex++, KMBoolTag.instance(KMType.CALLER_NONCE)); - if(unlockReqd)KMArray.cast(arrPtr).add(tagIndex++, KMBoolTag.instance(KMType.UNLOCKED_DEVICE_REQUIRED)); - if(clientId != null)KMArray.cast(arrPtr).add(tagIndex++, - KMByteTag.instance(KMType.APPLICATION_ID, KMByteBlob.instance(clientId,(short)0,(short)clientId.length))); - if(appData != null)KMArray.cast(arrPtr).add(tagIndex++, - KMByteTag.instance(KMType.APPLICATION_DATA, KMByteBlob.instance(appData,(short)0,(short)appData.length))); - short keyParams = KMKeyParameters.instance(arrPtr); - arrPtr = KMArray.instance((short)1); - KMArray arg = KMArray.cast(arrPtr); - arg.add((short) 0, keyParams); - CommandAPDU apdu = encodeApdu((byte)INS_GENERATE_KEY_CMD, arrPtr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - short ret = KMArray.instance((short) 3); - KMArray.cast(ret).add((short) 0, KMInteger.exp()); - KMArray.cast(ret).add((short)1, KMByteBlob.exp()); - short inst = KMKeyCharacteristics.exp(); - KMArray.cast(ret).add((short) 2, inst); - byte[] respBuf = response.getBytes(); - short len = (short) respBuf.length; - ret = decoder.decode(ret, respBuf, (short) 0, len); - short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - Assert.assertEquals(0x9000, response.getSW()); - Assert.assertEquals(error, KMError.OK); - return ret; - } - public short generateAesGcmKey(short keysize, byte[] clientId, byte[] appData) { - short tagCount = 8; - if(clientId != null) tagCount++; - if(appData != null) tagCount++; - short arrPtr = KMArray.instance(tagCount); - short boolTag = KMBoolTag.instance(KMType.NO_AUTH_REQUIRED); - short keySize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, KMInteger.uint_16(keysize)); - short macLength = KMIntegerTag.instance(KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, KMInteger.uint_16((short)96)); - short byteBlob = KMByteBlob.instance((short)1); - KMByteBlob.cast(byteBlob).add((short)0, KMType.GCM); - short blockModeTag = KMEnumArrayTag.instance(KMType.BLOCK_MODE, byteBlob); - byteBlob = KMByteBlob.instance((short)1); - KMByteBlob.cast(byteBlob).add((short)0, KMType.PADDING_NONE); - short paddingMode = KMEnumArrayTag.instance(KMType.PADDING, byteBlob); - byteBlob = KMByteBlob.instance((short)2); - KMByteBlob.cast(byteBlob).add((short)0, KMType.ENCRYPT); - KMByteBlob.cast(byteBlob).add((short)1, KMType.DECRYPT); - short purpose = KMEnumArrayTag.instance(KMType.PURPOSE, byteBlob); - short tagIndex = 0; - KMArray.cast(arrPtr).add(tagIndex++, boolTag); - KMArray.cast(arrPtr).add(tagIndex++, macLength); - KMArray.cast(arrPtr).add(tagIndex++, keySize); - KMArray.cast(arrPtr).add(tagIndex++, blockModeTag); - KMArray.cast(arrPtr).add(tagIndex++, paddingMode); - KMArray.cast(arrPtr).add(tagIndex++, KMEnumTag.instance(KMType.ALGORITHM, KMType.AES)); - KMArray.cast(arrPtr).add(tagIndex++, purpose); - KMArray.cast(arrPtr).add(tagIndex++, KMBoolTag.instance(KMType.CALLER_NONCE)); - if(clientId != null)KMArray.cast(arrPtr).add(tagIndex++, - KMByteTag.instance(KMType.APPLICATION_ID, KMByteBlob.instance(clientId,(short)0,(short)clientId.length))); - if(appData != null)KMArray.cast(arrPtr).add(tagIndex++, - KMByteTag.instance(KMType.APPLICATION_DATA, KMByteBlob.instance(appData,(short)0,(short)appData.length))); - short keyParams = KMKeyParameters.instance(arrPtr); - arrPtr = KMArray.instance((short)1); - KMArray arg = KMArray.cast(arrPtr); - arg.add((short) 0, keyParams); - CommandAPDU apdu = encodeApdu((byte)INS_GENERATE_KEY_CMD, arrPtr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - short ret = KMArray.instance((short) 3); - KMArray.cast(ret).add((short) 0, KMInteger.exp()); - KMArray.cast(ret).add((short)1, KMByteBlob.exp()); - short inst = KMKeyCharacteristics.exp(); - KMArray.cast(ret).add((short) 2, inst); - byte[] respBuf = response.getBytes(); - short len = (short) respBuf.length; - ret = decoder.decode(ret, respBuf, (short) 0, len); - short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - Assert.assertEquals(0x9000, response.getSW()); - Assert.assertEquals(error, KMError.OK); - return ret; - } - - @Test - public void testComputeHmacParams(){ - init(); - // Get Hmac parameters - short ret = getHmacSharingParams(); - short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - KMHmacSharingParameters params = KMHmacSharingParameters.cast(KMArray.cast(ret).get((short)1)); - short seed = params.getSeed(); - short nonce = params.getNonce(); - - short params1 = KMHmacSharingParameters.instance(); - KMHmacSharingParameters.cast(params1).setSeed(KMByteBlob.instance((short)0)); - short num = KMByteBlob.instance((short)32); - Util.arrayCopyNonAtomic( - KMByteBlob.cast(nonce).getBuffer(), - KMByteBlob.cast(nonce).getStartOff(), - KMByteBlob.cast(num).getBuffer(), - KMByteBlob.cast(num).getStartOff(), - KMByteBlob.cast(num).length()); - // cryptoProvider.newRandomNumber( -// KMByteBlob.cast(num).getBuffer(), -// KMByteBlob.cast(num).getStartOff(), -// KMByteBlob.cast(num).length()); - KMHmacSharingParameters.cast(params1).setNonce(num); - short params2 = KMHmacSharingParameters.instance(); - KMHmacSharingParameters.cast(params2).setSeed(KMByteBlob.instance((short)0)); - num = KMByteBlob.instance((short)32); - cryptoProvider.newRandomNumber( - KMByteBlob.cast(num).getBuffer(), - KMByteBlob.cast(num).getStartOff(), - KMByteBlob.cast(num).length()); - KMHmacSharingParameters.cast(params2).setNonce(num); - short arr = KMArray.instance((short)2); - KMArray.cast(arr).add((short)0, params1); - KMArray.cast(arr).add((short)1,params2); - short arrPtr = KMArray.instance((short)1); - KMArray.cast(arrPtr).add((short)0,arr); - CommandAPDU apdu = encodeApdu((byte)INS_COMPUTE_SHARED_HMAC_CMD, arrPtr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - Assert.assertEquals(0x9000, response.getSW()); - ret = KMArray.instance((short) 2); - KMArray.cast(ret).add((short) 0, KMInteger.exp()); - KMArray.cast(ret).add((short)1, KMByteBlob.exp()); - byte[] respBuf = response.getBytes(); - short len = (short) respBuf.length; - ret = decoder.decode(ret, respBuf, (short) 0, len); - error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - Assert.assertEquals(0x9000, response.getSW()); - Assert.assertEquals(error, KMError.OK); - - cleanUp(); - } - @Test - public void testGetHmacSharingParams(){ - init(); - CommandAPDU commandAPDU = new CommandAPDU(0x80, INS_GET_HMAC_SHARING_PARAM_CMD, 0x40, 0x00); - //print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(commandAPDU); - KMDecoder dec = new KMDecoder(); - short ret = KMArray.instance((short) 2); - KMArray.cast(ret).add((short) 0, KMInteger.exp()); - short inst = KMHmacSharingParameters.exp(); - KMArray.cast(ret).add((short) 1, inst); - byte[] respBuf = response.getBytes(); - short len = (short) respBuf.length; - ret = decoder.decode(ret, respBuf, (short) 0, len); - short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - KMHmacSharingParameters params = KMHmacSharingParameters.cast(KMArray.cast(ret).get((short)1)); - short seed = params.getSeed(); - short nonce = params.getNonce(); - Assert.assertTrue(KMByteBlob.cast(seed).length() == 0); - Assert.assertTrue(KMByteBlob.cast(nonce).length() == 32); - //print(seed); - //print(nonce); - Assert.assertEquals(error, KMError.OK); - cleanUp(); - } - public short getHmacSharingParams(){ - CommandAPDU commandAPDU = new CommandAPDU(0x80, INS_GET_HMAC_SHARING_PARAM_CMD, 0x40, 0x00); - //print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(commandAPDU); - KMDecoder dec = new KMDecoder(); - short ret = KMArray.instance((short) 2); - KMArray.cast(ret).add((short) 0, KMInteger.exp()); - short inst = KMHmacSharingParameters.exp(); - KMArray.cast(ret).add((short) 1, inst); - byte[] respBuf = response.getBytes(); - short len = (short) respBuf.length; - ret = decoder.decode(ret, respBuf, (short) 0, len); - return ret; - } - - @Test - public void testImportWrappedKey(){ - init(); - byte[] wrappedKey = new byte[16]; - cryptoProvider.newRandomNumber(wrappedKey,(short)0,(short)16); - byte[] encWrappedKey = new byte[16]; - //AESKey transportKey = cryptoProvider.createAESKey((short)256); - byte[] transportKeyMaterial = new byte[32]; - cryptoProvider.newRandomNumber(transportKeyMaterial,(short)0,(short)32); - //transportKey.setKey(transportKeyMaterial,(short)0); - byte[] nonce = new byte[12]; - cryptoProvider.newRandomNumber(nonce,(short)0,(short)12); - byte[] authData = "Auth Data".getBytes(); - byte[] authTag = new byte[12]; - cryptoProvider.aesGCMEncrypt(transportKeyMaterial,(short)0,(short)32,wrappedKey, - (short)0,(short)16,encWrappedKey,(short)0, - nonce,(short)0, (short)12,authData,(short)0,(short)authData.length, - authTag, (short)0, (short)12); - byte[] maskingKey = {1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0}; - byte[] maskedTransportKey = new byte[32]; - for(int i=0; i< maskingKey.length;i++){ - maskedTransportKey[i] = (byte)(transportKeyMaterial[i] ^ maskingKey[i]); - } - short rsaKeyArr = generateRsaKey(null,null); - short keyBlobPtr = KMArray.cast(rsaKeyArr).get((short)1); - byte[] wrappingKeyBlob= new byte[KMByteBlob.cast(keyBlobPtr).length()]; - Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), - KMByteBlob.cast(keyBlobPtr).getStartOff(), - wrappingKeyBlob,(short)0, (short)wrappingKeyBlob.length); - short inParams = getRsaParams(KMType.SHA2_256, KMType.RSA_OAEP); - short ret = processMessage(maskedTransportKey, - KMByteBlob.instance(wrappingKeyBlob,(short)0, (short)wrappingKeyBlob.length), - KMType.ENCRYPT, - KMKeyParameters.instance(inParams), - (short)0,null,false,false - ); - keyBlobPtr = KMArray.cast(ret).get((short)2); - byte[] encTransportKey = new byte[KMByteBlob.cast(keyBlobPtr).length()]; - Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), - encTransportKey,(short)0, (short)encTransportKey.length); - short tagCount = 7; - short arrPtr = KMArray.instance(tagCount); - short boolTag = KMBoolTag.instance(KMType.NO_AUTH_REQUIRED); - short keySize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, KMInteger.uint_16((short)128)); - short byteBlob = KMByteBlob.instance((short)2); - KMByteBlob.cast(byteBlob).add((short)0, KMType.ECB); - KMByteBlob.cast(byteBlob).add((short)1, KMType.CBC); - short blockModeTag = KMEnumArrayTag.instance(KMType.BLOCK_MODE, byteBlob); - byteBlob = KMByteBlob.instance((short)2); - KMByteBlob.cast(byteBlob).add((short)0, KMType.PKCS7); - KMByteBlob.cast(byteBlob).add((short)1, KMType.PADDING_NONE); - short paddingMode = KMEnumArrayTag.instance(KMType.PADDING, byteBlob); - byteBlob = KMByteBlob.instance((short)2); - KMByteBlob.cast(byteBlob).add((short)0, KMType.ENCRYPT); - KMByteBlob.cast(byteBlob).add((short)1, KMType.DECRYPT); - short purpose = KMEnumArrayTag.instance(KMType.PURPOSE, byteBlob); - short tagIndex = 0; - KMArray.cast(arrPtr).add(tagIndex++, boolTag); - KMArray.cast(arrPtr).add(tagIndex++, keySize); - KMArray.cast(arrPtr).add(tagIndex++, blockModeTag); - KMArray.cast(arrPtr).add(tagIndex++, paddingMode); - KMArray.cast(arrPtr).add(tagIndex++, KMEnumTag.instance(KMType.ALGORITHM, KMType.AES)); - KMArray.cast(arrPtr).add(tagIndex++, purpose); - KMArray.cast(arrPtr).add(tagIndex++, KMBoolTag.instance(KMType.CALLER_NONCE)); - short keyParams = KMKeyParameters.instance(arrPtr); - short nullParams = KMArray.instance((short)0); - nullParams = KMKeyParameters.instance(nullParams); - short arr = KMArray.instance((short)12); - KMArray.cast(arr).add((short) 0, keyParams); // Key Params of wrapped key - KMArray.cast(arr).add((short) 1, KMEnum.instance(KMType.KEY_FORMAT,KMType.RAW)); // Key Format - KMArray.cast(arr).add((short) 2, KMByteBlob.instance(encWrappedKey,(short)0,(short)encWrappedKey.length)); // Wrapped Import Key Blob - KMArray.cast(arr).add((short) 3, KMByteBlob.instance(authTag,(short)0,(short)authTag.length)); // Auth Tag - KMArray.cast(arr).add((short) 4, KMByteBlob.instance(nonce,(short)0,(short)nonce.length)); // IV - Nonce - KMArray.cast(arr).add((short) 5, KMByteBlob.instance(encTransportKey,(short)0,(short)encTransportKey.length)); // Encrypted Transport Key - KMArray.cast(arr).add((short) 6, KMByteBlob.instance(wrappingKeyBlob,(short)0, (short)wrappingKeyBlob.length)); // Wrapping Key KeyBlob - KMArray.cast(arr).add((short) 7, KMByteBlob.instance(maskingKey,(short)0,(short)maskingKey.length)); // Masking Key - KMArray.cast(arr).add((short) 8, nullParams); // Un-wrapping Params - KMArray.cast(arr).add((short) 9, KMByteBlob.instance(authData,(short)0,(short)authData.length)); // Wrapped Key ASSOCIATED AUTH DATA - KMArray.cast(arr).add((short) 10, KMInteger.uint_8((byte)0)); // Password Sid - KMArray.cast(arr).add((short) 11, KMInteger.uint_8((byte)0)); // Biometric Sid - CommandAPDU apdu = encodeApdu((byte)INS_IMPORT_WRAPPED_KEY_CMD, arr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - ret = KMArray.instance((short) 3); - KMArray.cast(ret).add((short) 0, KMInteger.exp()); - KMArray.cast(ret).add((short)1, KMByteBlob.exp()); - short inst = KMKeyCharacteristics.exp(); - KMArray.cast(ret).add((short) 2, inst); - byte[] respBuf = response.getBytes(); - short len = (short) respBuf.length; - ret = decoder.decode(ret, respBuf, (short) 0, len); - short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - short keyBlobLength = KMByteBlob.cast(KMArray.cast(ret).get((short)1)).length(); - short keyCharacteristics = KMArray.cast(ret).get((short)2); - short hwParams = KMKeyCharacteristics.cast(keyCharacteristics).getHardwareEnforced(); - short swParams = KMKeyCharacteristics.cast(keyCharacteristics).getSoftwareEnforced(); - Assert.assertEquals(0x9000, response.getSW()); - Assert.assertEquals(error, KMError.OK); - short tag = KMKeyParameters.findTag(KMType.BOOL_TAG, KMType.NO_AUTH_REQUIRED, hwParams); - Assert.assertEquals(KMBoolTag.cast(tag).getVal(),0x01); - tag = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.KEYSIZE, hwParams); - Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getShort(), 128); - tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PADDING, hwParams); - Assert.assertTrue(KMEnumArrayTag.cast(tag).contains(KMType.PKCS7)); - tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.BLOCK_MODE, hwParams); - Assert.assertTrue(KMEnumArrayTag.cast(tag).contains(KMType.ECB)); - tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, hwParams); - Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.AES); - tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ORIGIN, hwParams); - Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.SECURELY_IMPORTED); - cleanUp(); - } - - @Test - public void testGetKeyCharacteristicsWithIdDataSuccess() { - init(); - byte[] clientId = "clientId".getBytes(); - byte[] appData = "appData".getBytes(); - short ret = generateRsaKey(clientId,appData); - short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - Assert.assertEquals(error, KMError.OK); - short keyBlob = KMArray.cast(ret).get((short)1); - - short arrPtr = KMArray.instance((short)3); - KMArray.cast(arrPtr).add((short)0, keyBlob); - KMArray.cast(arrPtr).add((short)1, KMByteBlob.instance(clientId,(short)0, (short)clientId.length)); - KMArray.cast(arrPtr).add((short)2, KMByteBlob.instance(appData,(short)0, (short)appData.length)); - CommandAPDU apdu = encodeApdu((byte)INS_GET_KEY_CHARACTERISTICS_CMD, arrPtr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - ret = KMArray.instance((short) 2); - KMArray.cast(ret).add((short) 0, KMInteger.exp()); - short inst = KMKeyCharacteristics.exp(); - KMArray.cast(ret).add((short) 1, inst); - byte[] respBuf = response.getBytes(); - short len = (short) respBuf.length; - ret = decoder.decode(ret, respBuf, (short) 0, len); - error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - Assert.assertEquals(error, KMError.OK); - cleanUp(); - } - - @Test - public void testGetKeyCharacteristicsSuccess() { - init(); - short ret = generateRsaKey(null, null); - short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - Assert.assertEquals(error, KMError.OK); - short keyBlob = KMArray.cast(ret).get((short)1); - - short arrPtr = KMArray.instance((short)3); - KMArray.cast(arrPtr).add((short)0, keyBlob); - KMArray.cast(arrPtr).add((short)1, KMByteBlob.instance((short)0)); - KMArray.cast(arrPtr).add((short)2, KMByteBlob.instance((short)0)); - CommandAPDU apdu = encodeApdu((byte)INS_GET_KEY_CHARACTERISTICS_CMD, arrPtr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - ret = KMArray.instance((short) 2); - KMArray.cast(ret).add((short) 0, KMInteger.exp()); - short inst = KMKeyCharacteristics.exp(); - KMArray.cast(ret).add((short) 1, inst); - byte[] respBuf = response.getBytes(); - short len = (short) respBuf.length; - ret = decoder.decode(ret, respBuf, (short) 0, len); - error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - Assert.assertEquals(error, KMError.OK); - cleanUp(); - } - - @Test - public void testDeleteKeySuccess() { - init(); - short ret = generateRsaKey(null, null); - short keyBlobPtr = KMArray.cast(ret).get((short)1); - byte[] keyBlob = new byte[KMByteBlob.cast(keyBlobPtr).length()]; - short len = KMByteBlob.cast(keyBlobPtr).getValues(keyBlob, (short)0); - ret = getKeyCharacteristics(keyBlobPtr); - short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - Assert.assertEquals(error, KMError.OK); - ret = deleteKey(KMByteBlob.instance(keyBlob,(short)0,(short)keyBlob.length)); - Assert.assertEquals(ret, KMError.OK); -/* ret = getKeyCharacteristics(KMByteBlob.instance(keyBlob,(short)0,(short)keyBlob.length)); - short err = KMByteBlob.cast(ret).get((short)1); - Assert.assertEquals(KMError.INVALID_KEY_BLOB,err); - - */ - cleanUp(); - } - - @Test - public void testDeleteAllKeySuccess() { - init(); - short ret1 = generateRsaKey(null, null); - short keyBlobPtr = KMArray.cast(ret1).get((short)1); - byte[] keyBlob1 = new byte[KMByteBlob.cast(keyBlobPtr).length()]; - short len = KMByteBlob.cast(keyBlobPtr).getValues(keyBlob1, (short)0); - short ret2 = generateRsaKey(null, null); - keyBlobPtr = KMArray.cast(ret2).get((short)1); - byte[] keyBlob2 = new byte[KMByteBlob.cast(keyBlobPtr).length()]; - len = KMByteBlob.cast(keyBlobPtr).getValues(keyBlob2, (short)0); - CommandAPDU apdu = new CommandAPDU(0x80, INS_DELETE_ALL_KEYS_CMD, 0x40, 0x00); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - byte[] respBuf = response.getBytes(); - Assert.assertEquals(respBuf[0], KMError.OK); -/* short ret = getKeyCharacteristics(KMByteBlob.instance(keyBlob1,(short)0,(short)keyBlob1.length)); - short err = KMByteBlob.cast(ret).get((short)1); - Assert.assertEquals(KMError.INVALID_KEY_BLOB,err); - ret = getKeyCharacteristics(KMByteBlob.instance(keyBlob2,(short)0,(short)keyBlob2.length)); - err = KMByteBlob.cast(ret).get((short)1); - Assert.assertEquals(KMError.INVALID_KEY_BLOB,err); - - */ - cleanUp(); - } - - private short deleteKey(short keyBlob) { - short arrPtr = KMArray.instance((short)1); - KMArray.cast(arrPtr).add((short)0, keyBlob); - CommandAPDU apdu = encodeApdu((byte)INS_DELETE_KEY_CMD, arrPtr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - byte[] respBuf = response.getBytes(); - return respBuf[0]; - } - - private short abort(short opHandle) { - short arrPtr = KMArray.instance((short)1); - KMArray.cast(arrPtr).add((short)0, opHandle); - CommandAPDU apdu = encodeApdu((byte)INS_ABORT_OPERATION_CMD, arrPtr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - byte[] respBuf = response.getBytes(); - return respBuf[0]; - } - - public short getKeyCharacteristics(short keyBlob){ - short arrPtr = KMArray.instance((short)3); - KMArray.cast(arrPtr).add((short)0, keyBlob); - KMArray.cast(arrPtr).add((short)1, KMByteBlob.instance((short)0)); - KMArray.cast(arrPtr).add((short)2, KMByteBlob.instance((short)0)); - CommandAPDU apdu = encodeApdu((byte)INS_GET_KEY_CHARACTERISTICS_CMD, arrPtr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - short ret = KMArray.instance((short) 2); - KMArray.cast(ret).add((short) 0, KMInteger.exp()); - short inst = KMKeyCharacteristics.exp(); - KMArray.cast(ret).add((short) 1, inst); - byte[] respBuf = response.getBytes(); - short len = (short) respBuf.length; - if( len > 5) - ret = decoder.decode(ret, respBuf, (short) 0, len); - else - ret = KMByteBlob.instance(respBuf, (short)0, len); - return ret; - } - - @Test - public void testWithAesGcmWithUpdate(){ - init(); - testEncryptDecryptWithAesDes(KMType.AES, KMType.GCM, KMType.PADDING_NONE,true); - cleanUp(); - } - @Test - public void testWithAesEcbPkcs7WithUpdate(){ - init(); - testEncryptDecryptWithAesDes(KMType.AES, KMType.ECB, KMType.PKCS7,true); - cleanUp(); - } - - @Test - public void testWithAesCtrNoPadWithUpdate(){ - init(); - testEncryptDecryptWithAesDes(KMType.AES, KMType.CTR, KMType.PADDING_NONE,true); - cleanUp(); - } - - @Test - public void testWithAesCtrNoPad(){ - init(); - testEncryptDecryptWithAesDes(KMType.AES, KMType.CTR, KMType.PADDING_NONE,false); - cleanUp(); - } - - @Test - public void testWithAesEcbNoPadWithUpdate(){ - init(); - testEncryptDecryptWithAesDes(KMType.AES, KMType.ECB, KMType.PADDING_NONE,true); - cleanUp(); - } - @Test - public void testWithDesEcbPkcs7WithUpdate(){ - init(); - testEncryptDecryptWithAesDes(KMType.DES, KMType.ECB, KMType.PKCS7,true); - cleanUp(); - } - @Test - public void testWithDesEcbNoPadWithUpdate(){ - init(); - testEncryptDecryptWithAesDes(KMType.DES, KMType.ECB, KMType.PADDING_NONE,true); - cleanUp(); - } - @Test - public void testWithAesCbcPkcs7WithUpdate(){ - init(); - testEncryptDecryptWithAesDes(KMType.AES, KMType.CBC, KMType.PKCS7,true); - cleanUp(); - } - @Test - public void testWithAesCbcNoPadWithUpdate(){ - init(); - testEncryptDecryptWithAesDes(KMType.AES, KMType.CBC, KMType.PADDING_NONE,true); - cleanUp(); - } - @Test - public void testWithDesCbcPkcs7WithUpdate(){ - init(); - testEncryptDecryptWithAesDes(KMType.DES, KMType.CBC, KMType.PKCS7,true); - cleanUp(); - } - @Test - public void testWithDesCbcNoPadWithUpdate(){ - init(); - testEncryptDecryptWithAesDes(KMType.DES, KMType.CBC, KMType.PADDING_NONE,true); - cleanUp(); - } - - @Test - public void testWithAesEcbPkcs7(){ - init(); - testEncryptDecryptWithAesDes(KMType.AES, KMType.ECB, KMType.PKCS7,false); - cleanUp(); - } - @Test - public void testWithAesCbcPkcs7(){ - init(); - testEncryptDecryptWithAesDes(KMType.AES, KMType.CBC, KMType.PKCS7,false); - cleanUp(); - } - @Test - public void testWithAesEcbNoPad(){ - init(); - testEncryptDecryptWithAesDes(KMType.AES, KMType.ECB, KMType.PADDING_NONE,false); - cleanUp(); - } - - @Test - public void testWithAesCbcNoPad(){ - init(); - testEncryptDecryptWithAesDes(KMType.AES, KMType.CBC, KMType.PADDING_NONE,false); - cleanUp(); - } - - @Test - public void testWithDesCbcPkcs7(){ - init(); - testEncryptDecryptWithAesDes(KMType.DES, KMType.CBC, KMType.PKCS7,false); - cleanUp(); - } - - @Test - public void testWithDesCbcNoPad(){ - init(); - testEncryptDecryptWithAesDes(KMType.DES, KMType.CBC, KMType.PADDING_NONE,false); - cleanUp(); - } - @Test - public void testWithDesEcbNoPad(){ - init(); - testEncryptDecryptWithAesDes(KMType.DES, KMType.ECB, KMType.PADDING_NONE,false); - cleanUp(); - } - @Test - public void testWithDesEcbPkcs7(){ - init(); - testEncryptDecryptWithAesDes(KMType.DES, KMType.ECB, KMType.PKCS7,false); - cleanUp(); - } - - @Test - public void testWithRsa256Oaep(){ - init(); - testEncryptDecryptWithRsa(KMType.SHA2_256, KMType.RSA_OAEP); - cleanUp(); - } - @Test - public void testWithRsaSha1Oaep(){ - init(); - testEncryptDecryptWithRsa(KMType.SHA1, KMType.RSA_OAEP); - cleanUp(); - } - - @Test - public void testWithRsaNonePkcs1(){ - init(); - testEncryptDecryptWithRsa(KMType.DIGEST_NONE, KMType.RSA_PKCS1_1_5_ENCRYPT); - cleanUp(); - } - - @Test - public void testWithRsaNoneNoPad(){ - init(); - testEncryptDecryptWithRsa(KMType.DIGEST_NONE, KMType.PADDING_NONE); - cleanUp(); - } - - // TODO Signing with no digest is not supported by crypto provider or javacard - @Test - public void testSignWithRsaNoneNoPad(){ - init(); - testSignVerifyWithRsa(KMType.DIGEST_NONE, KMType.PADDING_NONE,false, false); - cleanUp(); - } - - @Test - public void testSignWithRsaNonePkcs1(){ - init(); - testSignVerifyWithRsa(KMType.DIGEST_NONE, KMType.RSA_PKCS1_1_5_SIGN,false, false); - cleanUp(); - } - - @Test - public void testSignVerifyWithHmacSHA256WithUpdate(){ - init(); - testSignVerifyWithHmac(KMType.SHA2_256, true); - cleanUp(); - } - - @Test - public void testSignVerifyWithHmacSHA256(){ - init(); - testSignVerifyWithHmac(KMType.SHA2_256, false); - cleanUp(); - } - - @Test - public void testSignVerifyWithEcdsaSHA256WithUpdate(){ - init(); - testSignVerifyWithEcdsa(KMType.SHA2_256, true); - cleanUp(); - } - @Test - public void testSignVerifyWithEcdsaSHA256(){ - init(); - testSignVerifyWithEcdsa(KMType.SHA2_256, false); - cleanUp(); - } - @Test - public void testSignVerifyWithRsaSHA256Pkcs1(){ - init(); - testSignVerifyWithRsa(KMType.SHA2_256, KMType.RSA_PKCS1_1_5_SIGN,false, true); - cleanUp(); - } - @Test - public void testSignVerifyWithRsaSHA256Pss(){ - init(); - testSignVerifyWithRsa(KMType.SHA2_256, KMType.RSA_PSS,false, true); - cleanUp(); - } - - @Test - public void testSignVerifyWithRsaSHA256Pkcs1WithUpdate(){ - init(); - testSignVerifyWithRsa(KMType.SHA2_256, KMType.RSA_PKCS1_1_5_SIGN,true, true); - cleanUp(); - } - - @Test - public void testProvisionSuccess(){ - AID appletAID1 = AIDUtil.create("A000000062"); - simulator.installApplet(appletAID1, KMKeymasterApplet.class); - // Select applet - simulator.selectApplet(appletAID1); - // provision attest key - provisionCmd(simulator); - cleanUp(); - } - - @Test - public void testAttestRsaKey(){ - init(); - short key = generateRsaKey(null,null); - short keyBlobPtr = KMArray.cast(key).get((short)1); - byte[] keyBlob= new byte[KMByteBlob.cast(keyBlobPtr).length()]; - Util.arrayCopyNonAtomic( - KMByteBlob.cast(keyBlobPtr).getBuffer(), - KMByteBlob.cast(keyBlobPtr).getStartOff(), - keyBlob,(short)0, (short)keyBlob.length); - testAttestKey(keyBlob); - cleanUp(); - } - - @Test - public void testAttestEcKey(){ - init(); - short key = generateEcKey(null,null); - short keyBlobPtr = KMArray.cast(key).get((short)1); - byte[] keyBlob= new byte[KMByteBlob.cast(keyBlobPtr).length()]; - Util.arrayCopyNonAtomic( - KMByteBlob.cast(keyBlobPtr).getBuffer(), - KMByteBlob.cast(keyBlobPtr).getStartOff(), - keyBlob,(short)0, (short)keyBlob.length); - testAttestKey(keyBlob); - cleanUp(); - } - - public void testAttestKey(byte[] keyBlob){ - /* - short key = generateRsaKey(null,null); - short keyBlobPtr = KMArray.cast(key).get((short)1); - byte[] keyBlob= new byte[KMByteBlob.cast(keyBlobPtr).length()]; - Util.arrayCopyNonAtomic( - KMByteBlob.cast(keyBlobPtr).getBuffer(), - KMByteBlob.cast(keyBlobPtr).getStartOff(), - keyBlob,(short)0, (short)keyBlob.length); - */ - short arrPtr = KMArray.instance((short)2); - KMArray.cast(arrPtr).add((short)0, KMByteTag.instance(KMType.ATTESTATION_APPLICATION_ID, - KMByteBlob.instance(attAppId,(short)0,(short)attAppId.length))); - KMArray.cast(arrPtr).add((short)1, KMByteTag.instance(KMType.ATTESTATION_CHALLENGE, - KMByteBlob.instance(attChallenge,(short)0,(short)attChallenge.length))); - short keyParams = KMKeyParameters.instance(arrPtr); - short args = KMArray.instance((short)2); - KMArray.cast(args).add((short)0, KMByteBlob.instance(keyBlob,(short)0,(short)keyBlob.length)); - KMArray.cast(args).add((short)1, keyParams); - CommandAPDU apdu = encodeApdu((byte)INS_ATTEST_KEY_CMD, args); - //print(apdu.getBytes(),(short)0,(short)apdu.getBytes().length); - ResponseAPDU response = simulator.transmitCommand(apdu); - short ret = KMArray.instance((short) 2); - short arrBlobs = KMArray.instance((short)1); - KMArray.cast(arrBlobs).add((short)0, KMByteBlob.exp()); - KMArray.cast(ret).add((short)0, KMInteger.exp()); - KMArray.cast(ret).add((short)1, arrBlobs); - byte[] respBuf = response.getBytes(); - short len = (short) respBuf.length; - //(respBuf,(short)0,(short)respBuf.length); - ret = decoder.decode(ret, respBuf, (short) 0, len); - short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - Assert.assertEquals(error, KMError.OK); - arrBlobs = KMArray.cast(ret).get((short)1); - short cert = KMArray.cast(arrBlobs).get((short)0); - //printCert(KMByteBlob.cast(cert).getBuffer(),KMByteBlob.cast(cert).getStartOff(),KMByteBlob.cast(cert).length()); - } - - @Test - public void testUpgradeKey(){ - init(); - short ret = generateHmacKey(null, null); - short keyBlobPtr = KMArray.cast(ret).get((short)1); - byte[] keyBlob= new byte[KMByteBlob.cast(keyBlobPtr).length()]; - Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), - keyBlob,(short)0, (short)keyBlob.length); - short keyCharacteristics = KMArray.cast(ret).get((short)2); - short hwParams = KMKeyCharacteristics.cast(keyCharacteristics).getHardwareEnforced(); - short swParams = KMKeyCharacteristics.cast(keyCharacteristics).getSoftwareEnforced(); - short osVersion = KMKeyParameters.findTag(KMType.UINT_TAG,KMType.OS_VERSION,hwParams); - osVersion = KMIntegerTag.cast(osVersion).getValue(); - short osPatch = KMKeyParameters.findTag(KMType.UINT_TAG,KMType.OS_PATCH_LEVEL,hwParams); - osPatch = KMIntegerTag.cast(osPatch).getValue(); - Assert.assertEquals(KMInteger.cast(osVersion).getShort(), 1); - Assert.assertEquals(KMInteger.cast(osPatch).getShort(), 1); - setBootParams(simulator,(short) 2,(short)2, (short)1, (short)1); - ret = upgradeKey(KMByteBlob.instance(keyBlob, (short)0, (short)keyBlob.length),null, null); - keyBlobPtr = KMArray.cast(ret).get((short)1); - ret = getKeyCharacteristics(keyBlobPtr); - keyCharacteristics = KMArray.cast(ret).get((short)1); - hwParams = KMKeyCharacteristics.cast(keyCharacteristics).getHardwareEnforced(); - osVersion = KMKeyParameters.findTag(KMType.UINT_TAG,KMType.OS_VERSION,hwParams); - osVersion = KMIntegerTag.cast(osVersion).getValue(); - osPatch = KMKeyParameters.findTag(KMType.UINT_TAG,KMType.OS_PATCH_LEVEL,hwParams); - osPatch = KMIntegerTag.cast(osPatch).getValue(); - Assert.assertEquals(KMInteger.cast(osVersion).getShort(), 2); - Assert.assertEquals(KMInteger.cast(osPatch).getShort(), 2); - cleanUp(); - } - - @Test - public void testDestroyAttIds(){ - init(); - CommandAPDU commandAPDU = new CommandAPDU(0x80, INS_DESTROY_ATT_IDS_CMD, 0x40, 0x00); - ResponseAPDU response = simulator.transmitCommand(commandAPDU); - byte[] respBuf = response.getBytes(); - Assert.assertEquals(respBuf[0], 0); - cleanUp(); - } - - private short upgradeKey(short keyBlobPtr, byte[] clientId, byte[] appData){ - short tagCount = 0; - short clientIdTag = 0; - short appDataTag = 0; - if(clientId != null) tagCount++; - if(appData != null) tagCount++; - short keyParams = KMArray.instance(tagCount); - short tagIndex=0; - if(clientId != null)KMArray.cast(keyBlobPtr).add(tagIndex++, - KMByteTag.instance(KMType.APPLICATION_ID, KMByteBlob.instance(clientId,(short)0,(short)clientId.length))); - if(appData != null)KMArray.cast(keyParams).add(tagIndex++, - KMByteTag.instance(KMType.APPLICATION_DATA, KMByteBlob.instance(appData,(short)0,(short)appData.length))); - keyParams = KMKeyParameters.instance(keyParams); - short arr = KMArray.instance((short)2); - KMArray.cast(arr).add((short)0,keyBlobPtr); - KMArray.cast(arr).add((short)1,keyParams); - CommandAPDU apdu = encodeApdu((byte)INS_UPGRADE_KEY_CMD, arr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - short ret = KMArray.instance((short) 2); - KMArray.cast(ret).add((short) 0, KMInteger.exp()); - KMArray.cast(ret).add((short)1, KMByteBlob.exp()); - byte[] respBuf = response.getBytes(); - short len = (short) respBuf.length; - ret = decoder.decode(ret, respBuf, (short) 0, len); - short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - Assert.assertEquals(error, KMError.OK); - return ret; - } - @Test - public void testSignVerifyWithRsaSHA256PssWithUpdate(){ - init(); - testSignVerifyWithRsa(KMType.SHA2_256, KMType.RSA_PSS,true, true); - cleanUp(); - } - @Test - public void testAbortOperation(){ - init(); - short aesDesKeyArr = generateAesDesKey(KMType.AES, (short)128,null, null, false);; - short keyBlobPtr = KMArray.cast(aesDesKeyArr).get((short)1); - byte[] keyBlob= new byte[KMByteBlob.cast(keyBlobPtr).length()]; - Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), - keyBlob,(short)0, (short)keyBlob.length); - byte[] nonce = new byte[16]; - cryptoProvider.newRandomNumber(nonce,(short)0,(short)16); - short inParams = getAesDesParams(KMType.AES,KMType.ECB, KMType.PKCS7, nonce); - byte[] plainData= "Hello World 123!".getBytes(); - short ret = begin(KMType.ENCRYPT, KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), KMKeyParameters.instance(inParams), (short)0); - short opHandle = KMArray.cast(ret).get((short) 2); - opHandle = KMInteger.cast(opHandle).getShort(); - abort(KMInteger.uint_16(opHandle)); - short dataPtr = KMByteBlob.instance(plainData, (short) 0, (short) plainData.length); - ret = update(KMInteger.uint_16(opHandle), dataPtr, (short) 0, (short) 0, (short) 0); - Assert.assertEquals(KMError.INVALID_OPERATION_HANDLE,ret); - cleanUp(); - } - - public void testEncryptDecryptWithAesDes(byte alg, byte blockMode, byte padding, boolean update){ - short aesDesKeyArr; - boolean aesGcmFlag = false; - if(alg == KMType.AES){ - if(blockMode == KMType.GCM){ - aesDesKeyArr = generateAesGcmKey((short)128,null,null); - aesGcmFlag = true; - } else { - aesDesKeyArr = generateAesDesKey(alg, (short) 128, null, null, false); - } - } else{ - aesDesKeyArr = generateAesDesKey(alg, (short)168,null, null, false); - } - short keyBlobPtr = KMArray.cast(aesDesKeyArr).get((short)1); - byte[] keyBlob= new byte[KMByteBlob.cast(keyBlobPtr).length()]; - Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), - keyBlob,(short)0, (short)keyBlob.length); - byte[] nonce = new byte[16]; - cryptoProvider.newRandomNumber(nonce,(short)0,(short)16); - short inParams = getAesDesParams(alg,blockMode, padding, nonce); - byte[] plainData= "Hello World 123!".getBytes(); - if(update) plainData= "Hello World 123! Hip Hip Hoorah!".getBytes(); - //Encrypt - short ret = processMessage(plainData, - KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), - KMType.ENCRYPT, - KMKeyParameters.instance(inParams), - (short)0,null,update, aesGcmFlag - ); - inParams = getAesDesParams(alg,blockMode, padding, nonce); - keyBlobPtr = KMArray.cast(ret).get((short)2); - //print(keyBlobPtr); - byte[] cipherData = new byte[KMByteBlob.cast(keyBlobPtr).length()]; - Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), - cipherData,(short)0, (short)cipherData.length); - ret = processMessage(cipherData, - KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), - KMType.DECRYPT, - KMKeyParameters.instance(inParams), - (short)0,null,update, aesGcmFlag - ); - keyBlobPtr = KMArray.cast(ret).get((short)2); - //print(plainData,(short)0,(short)plainData.length); - //print(keyBlobPtr); - short equal = Util.arrayCompare(plainData,(short)0,KMByteBlob.cast(keyBlobPtr).getBuffer(), - KMByteBlob.cast(keyBlobPtr).getStartOff(),(short)plainData.length); - Assert.assertTrue(equal == 0); - } - - public void testEncryptDecryptWithRsa(byte digest, byte padding){ - short rsaKeyArr = generateRsaKey(null, null); - short keyBlobPtr = KMArray.cast(rsaKeyArr).get((short)1); - byte[] keyBlob= new byte[KMByteBlob.cast(keyBlobPtr).length()]; - Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), - keyBlob,(short)0, (short)keyBlob.length); - short inParams = getRsaParams(digest, padding); - byte[] plainData = "Hello World 123!".getBytes(); - //Encrypt - short ret = processMessage(plainData, - KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), - KMType.ENCRYPT, - KMKeyParameters.instance(inParams), - (short)0,null,false, false - ); - inParams = getRsaParams(digest, padding); - keyBlobPtr = KMArray.cast(ret).get((short)2); - byte[] cipherData = new byte[KMByteBlob.cast(keyBlobPtr).length()]; - Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), - cipherData,(short)0, (short)cipherData.length); - ret = processMessage(cipherData, - KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), - KMType.DECRYPT, - KMKeyParameters.instance(inParams), - (short)0,null,false,false - ); - keyBlobPtr = KMArray.cast(ret).get((short)2); - short len = KMByteBlob.cast(keyBlobPtr).length(); - short start = KMByteBlob.cast(keyBlobPtr).getStartOff(); - short equal = Util.arrayCompare(plainData,(short)0,KMByteBlob.cast(keyBlobPtr).getBuffer(), - (short)(start+len-plainData.length),(short)plainData.length); - Assert.assertTrue(equal == 0); - } - - public void testSignVerifyWithRsa(byte digest, byte padding, boolean update, boolean verifyFlag){ - short rsaKeyArr = generateRsaKey(null, null); - short keyBlobPtr = KMArray.cast(rsaKeyArr).get((short)1); - byte[] keyBlob= new byte[KMByteBlob.cast(keyBlobPtr).length()]; - Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), - keyBlob,(short)0, (short)keyBlob.length); - short inParams = getRsaParams(digest, padding); - byte[] plainData = "Hello World 123!".getBytes(); - if(update) plainData= "Hello World 123! Hip Hip Hoorah!".getBytes(); - //Sign - short ret = processMessage(plainData, - KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), - KMType.SIGN, - KMKeyParameters.instance(inParams), - (short)0,null,update,false - ); - inParams = getRsaParams(digest, padding); - keyBlobPtr = KMArray.cast(ret).get((short)2); - byte[] signatureData = new byte[KMByteBlob.cast(keyBlobPtr).length()]; - Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), - signatureData,(short)0, (short)signatureData.length); - if(verifyFlag == false) { - Assert.assertEquals(signatureData.length,256); - return; - } - ret = processMessage(plainData, - KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), - KMType.VERIFY, - KMKeyParameters.instance(inParams), - (short)0,signatureData,update,false - ); - short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - Assert.assertEquals(error, KMError.OK); - } - - public void testSignVerifyWithEcdsa(byte digest, boolean update){ - short ecKeyArr = generateEcKey(null, null); - short keyBlobPtr = KMArray.cast(ecKeyArr).get((short)1); - byte[] keyBlob= new byte[KMByteBlob.cast(keyBlobPtr).length()]; - Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), - keyBlob,(short)0, (short)keyBlob.length); - short inParams = getEcParams(digest); - byte[] plainData = "Hello World 123!".getBytes(); - if(update) plainData= "Hello World 123! Hip Hip Hoorah!".getBytes(); - //Sign - short ret = processMessage(plainData, - KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), - KMType.SIGN, - KMKeyParameters.instance(inParams), - (short)0,null,update,false - ); - inParams = getEcParams(digest); - keyBlobPtr = KMArray.cast(ret).get((short)2); - byte[] signatureData = new byte[KMByteBlob.cast(keyBlobPtr).length()]; - Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), - signatureData,(short)0, (short)signatureData.length); - ret = processMessage(plainData, - KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), - KMType.VERIFY, - KMKeyParameters.instance(inParams), - (short)0,signatureData,update,false - ); - short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - Assert.assertEquals(error, KMError.OK); - } - public void testSignVerifyWithHmac(byte digest, boolean update){ - short hmacKeyArr = generateHmacKey(null, null); - short keyBlobPtr = KMArray.cast(hmacKeyArr).get((short)1); - byte[] keyBlob= new byte[KMByteBlob.cast(keyBlobPtr).length()]; - Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), - keyBlob,(short)0, (short)keyBlob.length); - short inParams = getHmacParams(digest,true); - byte[] plainData = "Hello World 123!".getBytes(); - if(update) plainData= "Hello World 123! Hip Hip Hoorah!".getBytes(); - //Sign - short ret = processMessage(plainData, - KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), - KMType.SIGN, - KMKeyParameters.instance(inParams), - (short)0,null,update,false - ); - inParams = getHmacParams(digest,false); - keyBlobPtr = KMArray.cast(ret).get((short)2); - byte[] signatureData = new byte[KMByteBlob.cast(keyBlobPtr).length()]; - Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), - signatureData,(short)0, (short)signatureData.length); - ret = processMessage(plainData, - KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), - KMType.VERIFY, - KMKeyParameters.instance(inParams), - (short)0,signatureData,update,false - ); - short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - Assert.assertEquals(error, KMError.OK); - } - - private short getAesDesParams(byte alg, byte blockMode, byte padding, byte[] nonce) { - short inParams; - if(blockMode == KMType.GCM){ - inParams = KMArray.instance((short)5); - short byteBlob = KMByteBlob.instance((short)1); - KMByteBlob.cast(byteBlob).add((short)0, blockMode); - KMArray.cast(inParams).add((short)0, KMEnumArrayTag.instance(KMType.BLOCK_MODE, byteBlob)); - byteBlob = KMByteBlob.instance((short)1); - KMByteBlob.cast(byteBlob).add((short)0, padding); - KMArray.cast(inParams).add((short)1, KMEnumArrayTag.instance(KMType.PADDING, byteBlob)); - short nonceLen = 12; - byteBlob = KMByteBlob.instance(nonce,(short)0, nonceLen); - KMArray.cast(inParams).add((short)2, KMByteTag.instance(KMType.NONCE, byteBlob)); - short macLen = KMInteger.uint_16((short)128); - macLen = KMIntegerTag.instance(KMType.UINT_TAG,KMType.MAC_LENGTH,macLen); - KMArray.cast(inParams).add((short)3, macLen); - byte[] authData = "AuthData".getBytes(); - short associatedData = KMByteBlob.instance(authData,(short)0,(short)authData.length); - associatedData = KMByteTag.instance(KMType.ASSOCIATED_DATA,associatedData); - KMArray.cast(inParams).add((short)4, associatedData); - }else if(blockMode == KMType.ECB){ - inParams = KMArray.instance((short)2); - short byteBlob = KMByteBlob.instance((short)1); - KMByteBlob.cast(byteBlob).add((short)0, blockMode); - KMArray.cast(inParams).add((short)0, KMEnumArrayTag.instance(KMType.BLOCK_MODE, byteBlob)); - byteBlob = KMByteBlob.instance((short)1); - KMByteBlob.cast(byteBlob).add((short)0, padding); - KMArray.cast(inParams).add((short)1, KMEnumArrayTag.instance(KMType.PADDING, byteBlob)); - }else{ - inParams = KMArray.instance((short)3); - short byteBlob = KMByteBlob.instance((short)1); - KMByteBlob.cast(byteBlob).add((short)0, blockMode); - KMArray.cast(inParams).add((short)0, KMEnumArrayTag.instance(KMType.BLOCK_MODE, byteBlob)); - byteBlob = KMByteBlob.instance((short)1); - KMByteBlob.cast(byteBlob).add((short)0, padding); - KMArray.cast(inParams).add((short)1, KMEnumArrayTag.instance(KMType.PADDING, byteBlob)); - short nonceLen = 16; - if(alg == KMType.DES) nonceLen = 8; - byteBlob = KMByteBlob.instance(nonce,(short)0, nonceLen); - KMArray.cast(inParams).add((short)2, KMByteTag.instance(KMType.NONCE, byteBlob)); - } - return inParams; - } - - private short getRsaParams(byte digest, byte padding) { - short inParams = KMArray.instance((short)2); - short byteBlob = KMByteBlob.instance((short)1); - KMByteBlob.cast(byteBlob).add((short)0, digest); - KMArray.cast(inParams).add((short)0, KMEnumArrayTag.instance(KMType.DIGEST, byteBlob)); - byteBlob = KMByteBlob.instance((short)1); - KMByteBlob.cast(byteBlob).add((short)0, padding); - KMArray.cast(inParams).add((short)1, KMEnumArrayTag.instance(KMType.PADDING, byteBlob)); - return inParams; - } - - private short getEcParams(byte digest) { - short inParams = KMArray.instance((short)1); - short byteBlob = KMByteBlob.instance((short)1); - KMByteBlob.cast(byteBlob).add((short)0, digest); - KMArray.cast(inParams).add((short)0, KMEnumArrayTag.instance(KMType.DIGEST, byteBlob)); - return inParams; - } - private short getHmacParams(byte digest, boolean sign) { - short paramsize = (short) (sign ? 2 : 1); - short inParams = KMArray.instance((short)paramsize); - short byteBlob = KMByteBlob.instance((short)1); - KMByteBlob.cast(byteBlob).add((short)0, digest); - KMArray.cast(inParams).add((short)0, KMEnumArrayTag.instance(KMType.DIGEST, byteBlob)); - short macLength = KMIntegerTag.instance(KMType.UINT_TAG,KMType.MAC_LENGTH, KMInteger.uint_16((short)/*256*/160)); - if(sign) - KMArray.cast(inParams).add((short)1, macLength); - return inParams; - } - - public short processMessage( - byte[] data, - short keyBlob, - byte keyPurpose, - short inParams, - short hwToken, - byte[] signature, - boolean updateFlag, - boolean aesGcmFlag) { - short beginResp = begin(keyPurpose, keyBlob, inParams, hwToken); - short opHandle = KMArray.cast(beginResp).get((short) 2); - opHandle = KMInteger.cast(opHandle).getShort(); - short dataPtr = KMByteBlob.instance(data, (short) 0, (short) data.length); - short ret = KMType.INVALID_VALUE; - byte[] outputData = new byte[128]; - short len=0; - inParams = 0; - //Test - short firstDataLen =16; - if (keyPurpose == KMType.DECRYPT) { - firstDataLen = 32; - } - - //Test - - if (updateFlag) { - dataPtr = KMByteBlob.instance(data, (short) 0, (short) /*16*/firstDataLen); - if(aesGcmFlag){ - byte[] authData = "AuthData".getBytes(); - short associatedData = KMByteBlob.instance(authData,(short)0,(short)authData.length); - associatedData = KMByteTag.instance(KMType.ASSOCIATED_DATA,associatedData); - inParams = KMArray.instance((short)1); - KMArray.cast(inParams).add((short)0, associatedData); - inParams = KMKeyParameters.instance(inParams); - } - ret = update(KMInteger.uint_16(opHandle), dataPtr, inParams, (short) 0, (short) 0); - dataPtr = KMArray.cast(ret).get((short) 3); - if (KMByteBlob.cast(dataPtr).length() > 0) { - Util.arrayCopyNonAtomic( - KMByteBlob.cast(dataPtr).getBuffer(), - KMByteBlob.cast(dataPtr).getStartOff(), - outputData, - (short) 0, - KMByteBlob.cast(dataPtr).length()); - len = KMByteBlob.cast(dataPtr).length(); - dataPtr = KMByteBlob.instance(data, len, (short) (data.length - len)); - }else{ - dataPtr = KMByteBlob.instance(data, (short)/*16*/firstDataLen, (short) (data.length - /*16*/firstDataLen)); - } - } - - if (keyPurpose == KMType.VERIFY) { - ret = finish(KMInteger.uint_16(opHandle), dataPtr, signature, (short) 0, (short) 0, (short) 0); - } else { - ret = finish(KMInteger.uint_16(opHandle), dataPtr, null, (short) 0, (short) 0, (short) 0); - } - if(len >0){ - dataPtr = KMArray.cast(ret).get((short)2); - if(KMByteBlob.cast(dataPtr).length() >0){ - Util.arrayCopyNonAtomic( - KMByteBlob.cast(dataPtr).getBuffer(), - KMByteBlob.cast(dataPtr).getStartOff(), - outputData, - len, - KMByteBlob.cast(dataPtr).length()); - len = (short)(len + KMByteBlob.cast(dataPtr).length()); - } - KMArray.cast(ret).add((short)2, KMByteBlob.instance(outputData,(short)0,len)); - } - return ret; - } - - public short begin(byte keyPurpose, short keyBlob, short keyParmas, short hwToken) { - short arrPtr = KMArray.instance((short)4); - KMArray.cast(arrPtr).add((short)0, KMEnum.instance(KMType.PURPOSE, keyPurpose)); - KMArray.cast(arrPtr).add((short)1, keyBlob); - KMArray.cast(arrPtr).add((short)2, keyParmas); - if(hwToken == 0) { - hwToken = KMHardwareAuthToken.instance(); - } - KMArray.cast(arrPtr).add((short)3, hwToken); - CommandAPDU apdu = encodeApdu((byte)INS_BEGIN_OPERATION_CMD, arrPtr); - //print(apdu.getBytes(),(short)0,(short)apdu.getBytes().length); - ResponseAPDU response = simulator.transmitCommand(apdu); - short ret = KMArray.instance((short) 3); - short outParams = KMKeyParameters.exp(); - KMArray.cast(ret).add((short)0, KMInteger.exp()); - KMArray.cast(ret).add((short)1, outParams); - KMArray.cast(ret).add((short)2, KMInteger.exp()); - byte[] respBuf = response.getBytes(); - short len = (short) respBuf.length; - if(len > 5){ - ret = decoder.decode(ret, respBuf, (short) 0, len); - short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - Assert.assertEquals(error, KMError.OK); - return ret;}else{ - if(len == 3) return respBuf[0]; - if(len == 4) return respBuf[1]; - return Util.getShort(respBuf,(short)0); - } - } - - public short finish(short operationHandle, short data, byte[] signature, short inParams, short hwToken, short verToken) { - if(hwToken == 0) { - hwToken = KMHardwareAuthToken.instance(); - } - if(verToken == 0){ - verToken = KMVerificationToken.instance(); - } - short signatureTag; - if(signature == null){ - signatureTag = KMByteBlob.instance((short)0); - }else{ - signatureTag = KMByteBlob.instance(signature,(short)0,(short)signature.length); - } - if(inParams == 0){ - short arr = KMArray.instance((short)0); - inParams = KMKeyParameters.instance(arr); - } - short arrPtr = KMArray.instance((short)6); - KMArray.cast(arrPtr).add((short)0, operationHandle); - KMArray.cast(arrPtr).add((short)1, inParams); - KMArray.cast(arrPtr).add((short)2, data); - KMArray.cast(arrPtr).add((short)3, signatureTag); - KMArray.cast(arrPtr).add((short)4, hwToken); - KMArray.cast(arrPtr).add((short)5, verToken); - CommandAPDU apdu = encodeApdu((byte)INS_FINISH_OPERATION_CMD, arrPtr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - short ret = KMArray.instance((short) 3); - short outParams = KMKeyParameters.exp(); - KMArray.cast(ret).add((short)0, KMInteger.exp()); - KMArray.cast(ret).add((short)1, outParams); - KMArray.cast(ret).add((short)2, KMByteBlob.exp()); - byte[] respBuf = response.getBytes(); - short len = (short) respBuf.length; - ret = decoder.decode(ret, respBuf, (short) 0, len); - short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - Assert.assertEquals(error, KMError.OK); - return ret; - } - public short update(short operationHandle, short data, short inParams, short hwToken, short verToken) { - if(hwToken == 0) { - hwToken = KMHardwareAuthToken.instance(); - } - if(verToken == 0){ - verToken = KMVerificationToken.instance(); - } - if(inParams == 0){ - short arr = KMArray.instance((short)0); - inParams = KMKeyParameters.instance(arr); - } - short arrPtr = KMArray.instance((short)5); - KMArray.cast(arrPtr).add((short)0, operationHandle); - KMArray.cast(arrPtr).add((short)1, inParams); - KMArray.cast(arrPtr).add((short)2, data); - KMArray.cast(arrPtr).add((short)3, hwToken); - KMArray.cast(arrPtr).add((short)4, verToken); - CommandAPDU apdu = encodeApdu((byte)INS_UPDATE_OPERATION_CMD, arrPtr); - // print(commandAPDU.getBytes()); - ResponseAPDU response = simulator.transmitCommand(apdu); - short ret = KMArray.instance((short) 4); - short outParams = KMKeyParameters.exp(); - KMArray.cast(ret).add((short)0, KMInteger.exp()); - KMArray.cast(ret).add((short)1, KMInteger.exp()); - KMArray.cast(ret).add((short)2, outParams); - KMArray.cast(ret).add((short)3, KMByteBlob.exp()); - byte[] respBuf = response.getBytes(); - short len = (short) respBuf.length; - if (len > 5) { - ret = decoder.decode(ret, respBuf, (short) 0, len); - short error = KMInteger.cast(KMArray.cast(ret).get((short) 0)).getShort(); - Assert.assertEquals(error, KMError.OK); - }else{ - ret = respBuf[1]; - } - return ret; - } - - private void print(short blob){ - print(KMByteBlob.cast(blob).getBuffer(),KMByteBlob.cast(blob).getStartOff(),KMByteBlob.cast(blob).length()); - } - private void print(byte[] buf, short start, short length){ - StringBuilder sb = new StringBuilder(); - for(int i = start; i < (start+length); i++){ - sb.append(String.format(" 0x%02X", buf[i])) ; - } - System.out.println(sb.toString()); - } - private void printCert(byte[] buf, short start, short length){ - StringBuilder sb = new StringBuilder(); - for(int i = start; i < (start+length); i++){ - sb.append(String.format("%02X", buf[i])) ; - } - System.out.println(sb.toString()); - } - - -/* - @Test - public void testApdu(){ - init(); - byte[] cmd = {(byte)0x80,0x11,0x40,0x00,0x00,0x00,0x4C,(byte)0x83,(byte)0xA5,0x1A,0x70,0x00,0x01,(byte)0xF7,0x01,0x1A,0x10, - 0x00,0x00,0x02,0x03,0x1A,0x30,0x00,0x00,0x03,0x19,0x01,0x00,0x1A,0x20,0x00,0x00,0x01,0x42,0x02, - 0x03,0x1A,0x20,0x00,0x00,0x05,0x41,0x04,0x03,0x58,0x24,(byte)0x82,0x58,0x20,0x73,0x7C,0x2E,(byte)0xCD, - 0x7B,(byte)0x8D,0x19,0x40,(byte)0xBF,0x29,0x30,(byte)0xAA,(byte)0x9B,0x4E, - (byte)0xD3,(byte)0xFF,(byte)0x94,0x1E,(byte)0xED,0x09,0x36,0x6B, - (byte)0xC0,0x32,(byte)0x99,(byte)0x98,0x64,(byte)0x81,(byte)0xF3,(byte)0xA4,(byte)0xD8,0x59,0x40}; - CommandAPDU cmdApdu = new CommandAPDU(cmd); - ResponseAPDU resp = simulator.transmitCommand(cmdApdu); - short ret = KMArray.instance((short) 3); - KMArray.cast(ret).add((short) 0, KMInteger.exp()); - KMArray.cast(ret).add((short)1, KMByteBlob.exp()); - short inst = KMKeyCharacteristics.exp(); - KMArray.cast(ret).add((short) 2, inst); - byte[] respBuf = resp.getBytes(); - short len = (short) respBuf.length; - ret = decoder.decode(ret, respBuf, (short) 0, len); - short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - short keyBlobLength = KMByteBlob.cast(KMArray.cast(ret).get((short)1)).length(); - short blobArr = extractKeyBlobArray(KMArray.cast(ret).get((short)1)); - short keyCharacteristics = KMArray.cast(ret).get((short)2); - short hwParams = KMKeyCharacteristics.cast(keyCharacteristics).getHardwareEnforced(); - short swParams = KMKeyCharacteristics.cast(keyCharacteristics).getSoftwareEnforced(); - cleanUp(); - } - */ -} +/* + * Copyright(C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.javacard.test; + +import com.android.javacard.keymaster.KMArray; +import com.android.javacard.keymaster.KMAttestationCert; +import com.android.javacard.keymaster.KMAttestationCertImpl; +import com.android.javacard.keymaster.KMBoolTag; +import com.android.javacard.keymaster.KMByteBlob; +import com.android.javacard.keymaster.KMByteTag; +import com.android.javacard.keymaster.KMJCardSimApplet; +import com.android.javacard.keymaster.KMJCardSimulator; +import com.android.javacard.keymaster.KMSEProvider; +import com.android.javacard.keymaster.KMDecoder; +import com.android.javacard.keymaster.KMEncoder; +import com.android.javacard.keymaster.KMEnum; +import com.android.javacard.keymaster.KMEnumArrayTag; +import com.android.javacard.keymaster.KMEnumTag; +import com.android.javacard.keymaster.KMError; +import com.android.javacard.keymaster.KMHardwareAuthToken; +import com.android.javacard.keymaster.KMHmacSharingParameters; +import com.android.javacard.keymaster.KMInteger; +import com.android.javacard.keymaster.KMIntegerTag; +import com.android.javacard.keymaster.KMKeyCharacteristics; +import com.android.javacard.keymaster.KMKeyParameters; +import com.android.javacard.keymaster.KMKeymasterApplet; +import com.android.javacard.keymaster.KMRepository; +import com.android.javacard.keymaster.KMType; +import com.android.javacard.keymaster.KMVerificationToken; +import com.licel.jcardsim.smartcardio.CardSimulator; +import com.licel.jcardsim.utils.AIDUtil; +import javacard.framework.AID; +import javacard.framework.Util; + +import java.security.spec.PKCS8EncodedKeySpec; + +import javax.smartcardio.CommandAPDU; +import javax.smartcardio.ResponseAPDU; +import org.junit.Assert; +import org.junit.Test; + +public class KMFunctionalTest { + private static final byte INS_BEGIN_KM_CMD = 0x00; + private static final byte INS_PROVISION_ATTESTATION_KEY_CMD = INS_BEGIN_KM_CMD + 1; //0x01 + private static final byte INS_PROVISION_ATTESTATION_CERT_CHAIN_CMD = INS_BEGIN_KM_CMD + 2; //0x02 + private static final byte INS_PROVISION_ATTESTATION_CERT_PARAMS_CMD = INS_BEGIN_KM_CMD + 3; //0x03 + private static final byte INS_PROVISION_ATTEST_IDS_CMD = INS_BEGIN_KM_CMD + 4; //0x04 + private static final byte INS_PROVISION_SHARED_SECRET_CMD = INS_BEGIN_KM_CMD + 5; //0x05 + private static final byte INS_SET_BOOT_PARAMS_CMD = INS_BEGIN_KM_CMD + 6; //0x06 + private static final byte INS_LOCK_PROVISIONING_CMD = INS_BEGIN_KM_CMD + 7; //0x07 + private static final byte INS_GET_PROVISION_STATUS_CMD = INS_BEGIN_KM_CMD + 8; //0x08 + // Top 32 commands are reserved for provisioning. + private static final byte INS_END_KM_PROVISION_CMD = 0x20; + + private static final byte INS_GENERATE_KEY_CMD = INS_END_KM_PROVISION_CMD + 1; //0x21 + private static final byte INS_IMPORT_KEY_CMD = INS_END_KM_PROVISION_CMD + 2; //0x22 + private static final byte INS_IMPORT_WRAPPED_KEY_CMD = INS_END_KM_PROVISION_CMD + 3; //0x23 + private static final byte INS_EXPORT_KEY_CMD = INS_END_KM_PROVISION_CMD + 4; //0x24 + private static final byte INS_ATTEST_KEY_CMD = INS_END_KM_PROVISION_CMD + 5; //0x25 + private static final byte INS_UPGRADE_KEY_CMD = INS_END_KM_PROVISION_CMD + 6; //0x26 + private static final byte INS_DELETE_KEY_CMD = INS_END_KM_PROVISION_CMD + 7; //0x27 + private static final byte INS_DELETE_ALL_KEYS_CMD = INS_END_KM_PROVISION_CMD + 8; //0x28 + private static final byte INS_ADD_RNG_ENTROPY_CMD = INS_END_KM_PROVISION_CMD + 9; //0x29 + private static final byte INS_COMPUTE_SHARED_HMAC_CMD = INS_END_KM_PROVISION_CMD + 10; //0x2A + private static final byte INS_DESTROY_ATT_IDS_CMD = INS_END_KM_PROVISION_CMD + 11; //0x2B + private static final byte INS_VERIFY_AUTHORIZATION_CMD = INS_END_KM_PROVISION_CMD + 12; //0x2C + private static final byte INS_GET_HMAC_SHARING_PARAM_CMD = INS_END_KM_PROVISION_CMD + 13; //0x2D + private static final byte INS_GET_KEY_CHARACTERISTICS_CMD = INS_END_KM_PROVISION_CMD + 14; //0x2E + private static final byte INS_GET_HW_INFO_CMD = INS_END_KM_PROVISION_CMD + 15; //0x2F + private static final byte INS_BEGIN_OPERATION_CMD = INS_END_KM_PROVISION_CMD + 16; //0x30 + private static final byte INS_UPDATE_OPERATION_CMD = INS_END_KM_PROVISION_CMD + 17; //0x31 + private static final byte INS_FINISH_OPERATION_CMD = INS_END_KM_PROVISION_CMD + 18; //0x32 + private static final byte INS_ABORT_OPERATION_CMD = INS_END_KM_PROVISION_CMD + 19; //0x33 + private static final byte INS_DEVICE_LOCKED_CMD = INS_END_KM_PROVISION_CMD + 20;//0x34 + private static final byte INS_EARLY_BOOT_ENDED_CMD = INS_END_KM_PROVISION_CMD + 21; //0x35 + private static final byte INS_GET_CERT_CHAIN_CMD = INS_END_KM_PROVISION_CMD + 22; //0x36 + + private static final byte[] kEcPrivKey = { + (byte) 0x21, (byte) 0xe0, (byte) 0x86, (byte) 0x43, (byte) 0x2a, + (byte) 0x15, (byte) 0x19, (byte) 0x84, (byte) 0x59, (byte) 0xcf, + (byte) 0x36, (byte) 0x3a, (byte) 0x50, (byte) 0xfc, (byte) 0x14, + (byte) 0xc9, (byte) 0xda, (byte) 0xad, (byte) 0xf9, (byte) 0x35, + (byte) 0xf5, (byte) 0x27, (byte) 0xc2, (byte) 0xdf, (byte) 0xd7, + (byte) 0x1e, (byte) 0x4d, (byte) 0x6d, (byte) 0xbc, (byte) 0x42, + (byte) 0xe5, (byte) 0x44 }; + private static final byte[] kEcPubKey = { + (byte) 0x04, (byte) 0xeb, (byte) 0x9e, (byte) 0x79, (byte) 0xf8, + (byte) 0x42, (byte) 0x63, (byte) 0x59, (byte) 0xac, (byte) 0xcb, + (byte) 0x2a, (byte) 0x91, (byte) 0x4c, (byte) 0x89, (byte) 0x86, + (byte) 0xcc, (byte) 0x70, (byte) 0xad, (byte) 0x90, (byte) 0x66, + (byte) 0x93, (byte) 0x82, (byte) 0xa9, (byte) 0x73, (byte) 0x26, + (byte) 0x13, (byte) 0xfe, (byte) 0xac, (byte) 0xcb, (byte) 0xf8, + (byte) 0x21, (byte) 0x27, (byte) 0x4c, (byte) 0x21, (byte) 0x74, + (byte) 0x97, (byte) 0x4a, (byte) 0x2a, (byte) 0xfe, (byte) 0xa5, + (byte) 0xb9, (byte) 0x4d, (byte) 0x7f, (byte) 0x66, (byte) 0xd4, + (byte) 0xe0, (byte) 0x65, (byte) 0x10, (byte) 0x66, (byte) 0x35, + (byte) 0xbc, (byte) 0x53, (byte) 0xb7, (byte) 0xa0, (byte) 0xa3, + (byte) 0xa6, (byte) 0x71, (byte) 0x58, (byte) 0x3e, (byte) 0xdb, + (byte) 0x3e, (byte) 0x11, (byte) 0xae, (byte) 0x10, (byte) 0x14 }; + + private static final byte[] kEcAttestCert = { + 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x78, (byte) 0x30, (byte) 0x82, + (byte) 0x02, (byte) 0x1e, (byte) 0xa0, (byte) 0x03, (byte) 0x02, + (byte) 0x01, (byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x10, 0x01, + (byte) 0x30, (byte) 0x0a, (byte) 0x06, (byte) 0x08, (byte) 0x2a, + (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x04, + (byte) 0x03, (byte) 0x02, (byte) 0x30, (byte) 0x81, (byte) 0x98, 0x31, + (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, + (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, + (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x13, (byte) 0x30, 0x11, + (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08, + (byte) 0x0c, (byte) 0x0a, (byte) 0x43, (byte) 0x61, (byte) 0x6c, + (byte) 0x69, (byte) 0x66, (byte) 0x6f, (byte) 0x72, (byte) 0x6e, 0x69, + (byte) 0x61, (byte) 0x31, (byte) 0x16, (byte) 0x30, (byte) 0x14, + (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x07, + (byte) 0x0c, (byte) 0x0d, (byte) 0x4d, (byte) 0x6f, (byte) 0x75, 0x6e, + (byte) 0x74, (byte) 0x61, (byte) 0x69, (byte) 0x6e, (byte) 0x20, + (byte) 0x56, (byte) 0x69, (byte) 0x65, (byte) 0x77, (byte) 0x31, + (byte) 0x15, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x03, 0x55, + (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x0c, (byte) 0x47, + (byte) 0x6f, (byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65, + (byte) 0x2c, (byte) 0x20, (byte) 0x49, (byte) 0x6e, (byte) 0x63, 0x2e, + (byte) 0x31, (byte) 0x10, (byte) 0x30, (byte) 0x0e, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0b, (byte) 0x0c, + (byte) 0x07, (byte) 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, 0x6f, + (byte) 0x69, (byte) 0x64, (byte) 0x31, (byte) 0x33, (byte) 0x30, + (byte) 0x31, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, + (byte) 0x03, (byte) 0x0c, (byte) 0x2a, (byte) 0x41, (byte) 0x6e, 0x64, + (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x20, + (byte) 0x4b, (byte) 0x65, (byte) 0x79, (byte) 0x73, (byte) 0x74, + (byte) 0x6f, (byte) 0x72, (byte) 0x65, (byte) 0x20, (byte) 0x53, 0x6f, + (byte) 0x66, (byte) 0x74, (byte) 0x77, (byte) 0x61, (byte) 0x72, + (byte) 0x65, (byte) 0x20, (byte) 0x41, (byte) 0x74, (byte) 0x74, + (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x61, (byte) 0x74, 0x69, + (byte) 0x6f, (byte) 0x6e, (byte) 0x20, (byte) 0x52, (byte) 0x6f, + (byte) 0x6f, (byte) 0x74, (byte) 0x30, (byte) 0x1e, (byte) 0x17, + (byte) 0x0d, (byte) 0x31, (byte) 0x36, (byte) 0x30, (byte) 0x31, 0x31, + (byte) 0x31, (byte) 0x30, (byte) 0x30, (byte) 0x34, (byte) 0x36, + (byte) 0x30, (byte) 0x39, (byte) 0x5a, (byte) 0x17, (byte) 0x0d, + (byte) 0x32, (byte) 0x36, (byte) 0x30, (byte) 0x31, (byte) 0x30, 0x38, + (byte) 0x30, (byte) 0x30, (byte) 0x34, (byte) 0x36, (byte) 0x30, + (byte) 0x39, (byte) 0x5a, (byte) 0x30, (byte) 0x81, (byte) 0x88, + (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, 0x03, + (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, + (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x13, (byte) 0x30, + (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, 0x08, + (byte) 0x0c, (byte) 0x0a, (byte) 0x43, (byte) 0x61, (byte) 0x6c, + (byte) 0x69, (byte) 0x66, (byte) 0x6f, (byte) 0x72, (byte) 0x6e, + (byte) 0x69, (byte) 0x61, (byte) 0x31, (byte) 0x15, (byte) 0x30, 0x13, + (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, + (byte) 0x0c, (byte) 0x0c, (byte) 0x47, (byte) 0x6f, (byte) 0x6f, + (byte) 0x67, (byte) 0x6c, (byte) 0x65, (byte) 0x2c, (byte) 0x20, 0x49, + (byte) 0x6e, (byte) 0x63, (byte) 0x2e, (byte) 0x31, (byte) 0x10, + (byte) 0x30, (byte) 0x0e, (byte) 0x06, (byte) 0x03, (byte) 0x55, + (byte) 0x04, (byte) 0x0b, (byte) 0x0c, (byte) 0x07, (byte) 0x41, 0x6e, + (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, + (byte) 0x31, (byte) 0x3b, (byte) 0x30, (byte) 0x39, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x0c, 0x32, + (byte) 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, + (byte) 0x69, (byte) 0x64, (byte) 0x20, (byte) 0x4b, (byte) 0x65, + (byte) 0x79, (byte) 0x73, (byte) 0x74, (byte) 0x6f, (byte) 0x72, 0x65, + (byte) 0x20, (byte) 0x53, (byte) 0x6f, (byte) 0x66, (byte) 0x74, + (byte) 0x77, (byte) 0x61, (byte) 0x72, (byte) 0x65, (byte) 0x20, + (byte) 0x41, (byte) 0x74, (byte) 0x74, (byte) 0x65, (byte) 0x73, 0x74, + (byte) 0x61, (byte) 0x74, (byte) 0x69, (byte) 0x6f, (byte) 0x6e, + (byte) 0x20, (byte) 0x49, (byte) 0x6e, (byte) 0x74, (byte) 0x65, + (byte) 0x72, (byte) 0x6d, (byte) 0x65, (byte) 0x64, (byte) 0x69, 0x61, + (byte) 0x74, (byte) 0x65, (byte) 0x30, (byte) 0x59, (byte) 0x30, + (byte) 0x13, (byte) 0x06, (byte) 0x07, (byte) 0x2a, (byte) 0x86, + (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x02, (byte) 0x01, 0x06, + (byte) 0x08, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0xce, + (byte) 0x3d, (byte) 0x03, (byte) 0x01, (byte) 0x07, (byte) 0x03, + (byte) 0x42, (byte) 0x00, (byte) 0x04, (byte) 0xeb, (byte) 0x9e, 0x79, + (byte) 0xf8, (byte) 0x42, (byte) 0x63, (byte) 0x59, (byte) 0xac, + (byte) 0xcb, (byte) 0x2a, (byte) 0x91, (byte) 0x4c, (byte) 0x89, + (byte) 0x86, (byte) 0xcc, (byte) 0x70, (byte) 0xad, (byte) 0x90, 0x66, + (byte) 0x93, (byte) 0x82, (byte) 0xa9, (byte) 0x73, (byte) 0x26, + (byte) 0x13, (byte) 0xfe, (byte) 0xac, (byte) 0xcb, (byte) 0xf8, + (byte) 0x21, (byte) 0x27, (byte) 0x4c, (byte) 0x21, (byte) 0x74, + (byte) 0x97, (byte) 0x4a, (byte) 0x2a, (byte) 0xfe, (byte) 0xa5, + (byte) 0xb9, (byte) 0x4d, (byte) 0x7f, (byte) 0x66, (byte) 0xd4, + (byte) 0xe0, (byte) 0x65, (byte) 0x10, (byte) 0x66, (byte) 0x35, + (byte) 0xbc, 0x53, (byte) 0xb7, (byte) 0xa0, (byte) 0xa3, (byte) 0xa6, + (byte) 0x71, (byte) 0x58, (byte) 0x3e, (byte) 0xdb, (byte) 0x3e, + (byte) 0x11, (byte) 0xae, (byte) 0x10, (byte) 0x14, (byte) 0xa3, + (byte) 0x66, 0x30, (byte) 0x64, (byte) 0x30, (byte) 0x1d, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e, (byte) 0x04, + (byte) 0x16, (byte) 0x04, (byte) 0x14, (byte) 0x3f, (byte) 0xfc, + (byte) 0xac, (byte) 0xd6, (byte) 0x1a, (byte) 0xb1, (byte) 0x3a, + (byte) 0x9e, (byte) 0x81, (byte) 0x20, (byte) 0xb8, (byte) 0xd5, + (byte) 0x25, (byte) 0x1c, (byte) 0xc5, (byte) 0x65, (byte) 0xbb, + (byte) 0x1e, (byte) 0x91, (byte) 0xa9, (byte) 0x30, (byte) 0x1f, + (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x23, + (byte) 0x04, (byte) 0x18, (byte) 0x30, (byte) 0x16, (byte) 0x80, + (byte) 0x14, (byte) 0xc8, (byte) 0xad, (byte) 0xe9, (byte) 0x77, + (byte) 0x4c, (byte) 0x45, (byte) 0xc3, (byte) 0xa3, (byte) 0xcf, + (byte) 0x0d, (byte) 0x16, (byte) 0x10, (byte) 0xe4, (byte) 0x79, + (byte) 0x43, (byte) 0x3a, (byte) 0x21, (byte) 0x5a, 0x30, (byte) 0xcf, + (byte) 0x30, (byte) 0x12, (byte) 0x06, (byte) 0x03, (byte) 0x55, + (byte) 0x1d, (byte) 0x13, (byte) 0x01, (byte) 0x01, (byte) 0xff, + (byte) 0x04, (byte) 0x08, (byte) 0x30, (byte) 0x06, 0x01, (byte) 0x01, + (byte) 0xff, (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x30, + (byte) 0x0e, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, + (byte) 0x0f, (byte) 0x01, (byte) 0x01, (byte) 0xff, 0x04, (byte) 0x04, + (byte) 0x03, (byte) 0x02, (byte) 0x02, (byte) 0x84, (byte) 0x30, + (byte) 0x0a, (byte) 0x06, (byte) 0x08, (byte) 0x2a, (byte) 0x86, + (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x04, 0x03, (byte) 0x02, + (byte) 0x03, (byte) 0x48, (byte) 0x00, (byte) 0x30, (byte) 0x45, + (byte) 0x02, (byte) 0x20, (byte) 0x4b, (byte) 0x8a, (byte) 0x9b, + (byte) 0x7b, (byte) 0xee, (byte) 0x82, (byte) 0xbc, (byte) 0xc0, + (byte) 0x33, (byte) 0x87, (byte) 0xae, (byte) 0x2f, (byte) 0xc0, + (byte) 0x89, (byte) 0x98, (byte) 0xb4, (byte) 0xdd, (byte) 0xc3, + (byte) 0x8d, (byte) 0xab, (byte) 0x27, (byte) 0x2a, (byte) 0x45, + (byte) 0x9f, (byte) 0x69, (byte) 0x0c, (byte) 0xc7, (byte) 0xc3, + (byte) 0x92, (byte) 0xd4, (byte) 0x0f, (byte) 0x8e, (byte) 0x02, + (byte) 0x21, (byte) 0x00, (byte) 0xee, (byte) 0xda, (byte) 0x01, + (byte) 0x5d, (byte) 0xb6, (byte) 0xf4, (byte) 0x32, (byte) 0xe9, + (byte) 0xd4, (byte) 0x84, (byte) 0x3b, (byte) 0x62, (byte) 0x4c, + (byte) 0x94, (byte) 0x04, (byte) 0xef, (byte) 0x3a, (byte) 0x7c, + (byte) 0xcc, (byte) 0xbd, 0x5e, (byte) 0xfb, (byte) 0x22, (byte) 0xbb, + (byte) 0xe7, (byte) 0xfe, (byte) 0xb9, (byte) 0x77, (byte) 0x3f, + (byte) 0x59, (byte) 0x3f, (byte) 0xfb, }; + + private static final byte[] kEcAttestRootCert = { + 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x8b, (byte) 0x30, + (byte) 0x82, (byte) 0x02, (byte) 0x32, (byte) 0xa0, (byte) 0x03, + (byte) 0x02, (byte) 0x01, (byte) 0x02, (byte) 0x02, (byte) 0x09, + (byte) 0x00, (byte) 0xa2, (byte) 0x05, (byte) 0x9e, (byte) 0xd1, + (byte) 0x0e, (byte) 0x43, (byte) 0x5b, (byte) 0x57, (byte) 0x30, + (byte) 0x0a, (byte) 0x06, (byte) 0x08, (byte) 0x2a, (byte) 0x86, + (byte) 0x48, (byte) 0xce, 0x3d, (byte) 0x04, (byte) 0x03, + (byte) 0x02, (byte) 0x30, (byte) 0x81, (byte) 0x98, (byte) 0x31, + (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, + (byte) 0x55, (byte) 0x04, (byte) 0x06, 0x13, (byte) 0x02, + (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x13, (byte) 0x30, + (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, + (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x43, 0x61, + (byte) 0x6c, (byte) 0x69, (byte) 0x66, (byte) 0x6f, (byte) 0x72, + (byte) 0x6e, (byte) 0x69, (byte) 0x61, (byte) 0x31, (byte) 0x16, + (byte) 0x30, (byte) 0x14, (byte) 0x06, (byte) 0x03, (byte) 0x55, + 0x04, (byte) 0x07, (byte) 0x0c, (byte) 0x0d, (byte) 0x4d, + (byte) 0x6f, (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61, + (byte) 0x69, (byte) 0x6e, (byte) 0x20, (byte) 0x56, (byte) 0x69, + (byte) 0x65, 0x77, (byte) 0x31, (byte) 0x15, (byte) 0x30, + (byte) 0x13, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, + (byte) 0x0a, (byte) 0x0c, (byte) 0x0c, (byte) 0x47, (byte) 0x6f, + (byte) 0x6f, (byte) 0x67, 0x6c, (byte) 0x65, (byte) 0x2c, + (byte) 0x20, (byte) 0x49, (byte) 0x6e, (byte) 0x63, (byte) 0x2e, + (byte) 0x31, (byte) 0x10, (byte) 0x30, (byte) 0x0e, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x04, 0x0b, (byte) 0x0c, + (byte) 0x07, (byte) 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, + (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x31, (byte) 0x33, + (byte) 0x30, (byte) 0x31, (byte) 0x06, (byte) 0x03, 0x55, + (byte) 0x04, (byte) 0x03, (byte) 0x0c, (byte) 0x2a, (byte) 0x41, + (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, + (byte) 0x64, (byte) 0x20, (byte) 0x4b, (byte) 0x65, (byte) 0x79, + 0x73, (byte) 0x74, (byte) 0x6f, (byte) 0x72, (byte) 0x65, + (byte) 0x20, (byte) 0x53, (byte) 0x6f, (byte) 0x66, (byte) 0x74, + (byte) 0x77, (byte) 0x61, (byte) 0x72, (byte) 0x65, (byte) 0x20, + (byte) 0x41, 0x74, (byte) 0x74, (byte) 0x65, (byte) 0x73, + (byte) 0x74, (byte) 0x61, (byte) 0x74, (byte) 0x69, (byte) 0x6f, + (byte) 0x6e, (byte) 0x20, (byte) 0x52, (byte) 0x6f, (byte) 0x6f, + (byte) 0x74, (byte) 0x30, 0x1e, (byte) 0x17, (byte) 0x0d, + (byte) 0x31, (byte) 0x36, (byte) 0x30, (byte) 0x31, (byte) 0x31, + (byte) 0x31, (byte) 0x30, (byte) 0x30, (byte) 0x34, (byte) 0x33, + (byte) 0x35, (byte) 0x30, (byte) 0x5a, 0x17, (byte) 0x0d, + (byte) 0x33, (byte) 0x36, (byte) 0x30, (byte) 0x31, (byte) 0x30, + (byte) 0x36, (byte) 0x30, (byte) 0x30, (byte) 0x34, (byte) 0x33, + (byte) 0x35, (byte) 0x30, (byte) 0x5a, (byte) 0x30, (byte) 0x81, + (byte) 0x98, (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, + (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, + (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31, + 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, + (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x0a, + (byte) 0x43, (byte) 0x61, (byte) 0x6c, (byte) 0x69, (byte) 0x66, + (byte) 0x6f, 0x72, (byte) 0x6e, (byte) 0x69, (byte) 0x61, + (byte) 0x31, (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x07, (byte) 0x0c, + (byte) 0x0d, (byte) 0x4d, 0x6f, (byte) 0x75, (byte) 0x6e, + (byte) 0x74, (byte) 0x61, (byte) 0x69, (byte) 0x6e, (byte) 0x20, + (byte) 0x56, (byte) 0x69, (byte) 0x65, (byte) 0x77, (byte) 0x31, + (byte) 0x15, (byte) 0x30, (byte) 0x13, 0x06, (byte) 0x03, + (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x0c, + (byte) 0x47, (byte) 0x6f, (byte) 0x6f, (byte) 0x67, (byte) 0x6c, + (byte) 0x65, (byte) 0x2c, (byte) 0x20, (byte) 0x49, 0x6e, + (byte) 0x63, (byte) 0x2e, (byte) 0x31, (byte) 0x10, (byte) 0x30, + (byte) 0x0e, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, + (byte) 0x0b, (byte) 0x0c, (byte) 0x07, (byte) 0x41, (byte) 0x6e, + 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, + (byte) 0x31, (byte) 0x33, (byte) 0x30, (byte) 0x31, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x0c, + (byte) 0x2a, 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, + (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x20, (byte) 0x4b, + (byte) 0x65, (byte) 0x79, (byte) 0x73, (byte) 0x74, (byte) 0x6f, + (byte) 0x72, (byte) 0x65, 0x20, (byte) 0x53, (byte) 0x6f, + (byte) 0x66, (byte) 0x74, (byte) 0x77, (byte) 0x61, (byte) 0x72, + (byte) 0x65, (byte) 0x20, (byte) 0x41, (byte) 0x74, (byte) 0x74, + (byte) 0x65, (byte) 0x73, (byte) 0x74, 0x61, (byte) 0x74, + (byte) 0x69, (byte) 0x6f, (byte) 0x6e, 0x77, (byte) 0x1f, + (byte) 0x44, (byte) 0x22, (byte) 0x6d, (byte) 0xbd, (byte) 0xb1, + (byte) 0xaf, (byte) 0xfa, (byte) 0x16, (byte) 0xcb, (byte) 0xc7, + (byte) 0xad, (byte) 0xc5, (byte) 0x77, (byte) 0xd2, (byte) 0x20, + (byte) 0x52, (byte) 0x6f, (byte) 0x6f, (byte) 0x74, (byte) 0x30, + (byte) 0x59, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x07, + 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x3d, + (byte) 0x02, (byte) 0x01, (byte) 0x06, (byte) 0x08, (byte) 0x2a, + (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x03, + (byte) 0x01, 0x07, (byte) 0x03, (byte) 0x42, (byte) 0x00, + (byte) 0x04, (byte) 0xee, (byte) 0x5d, (byte) 0x5e, (byte) 0xc7, + (byte) 0xe1, (byte) 0xc0, (byte) 0xdb, (byte) 0x6d, (byte) 0x03, + (byte) 0xa6, (byte) 0x7e, (byte) 0xe6, (byte) 0xb6, (byte) 0x1b, + (byte) 0xec, (byte) 0x4d, (byte) 0x6a, (byte) 0x5d, (byte) 0x6a, + (byte) 0x68, (byte) 0x2e, (byte) 0x0f, (byte) 0xff, (byte) 0x7f, + (byte) 0x49, (byte) 0x0e, (byte) 0x7d, 0x56, (byte) 0x9c, + (byte) 0xaa, (byte) 0xb7, (byte) 0xb0, (byte) 0x2d, (byte) 0x54, + (byte) 0x01, (byte) 0x5d, (byte) 0x3e, (byte) 0x43, (byte) 0x2b, + (byte) 0x2a, (byte) 0x8e, (byte) 0xd7, (byte) 0x4e, (byte) 0xec, + (byte) 0x48, (byte) 0x75, (byte) 0x41, (byte) 0xa4, (byte) 0xa3, + (byte) 0x63, (byte) 0x30, (byte) 0x61, (byte) 0x30, (byte) 0x1d, + (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e, + 0x04, (byte) 0x16, (byte) 0x04, (byte) 0x14, (byte) 0xc8, + (byte) 0xad, (byte) 0xe9, (byte) 0x77, (byte) 0x4c, (byte) 0x45, + (byte) 0xc3, (byte) 0xa3, (byte) 0xcf, (byte) 0x0d, (byte) 0x16, + (byte) 0x10, (byte) 0xe4, (byte) 0x79, (byte) 0x43, (byte) 0x3a, + (byte) 0x21, (byte) 0x5a, (byte) 0x30, (byte) 0xcf, (byte) 0x30, + (byte) 0x1f, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, + (byte) 0x23, (byte) 0x04, 0x18, (byte) 0x30, (byte) 0x16, + (byte) 0x80, (byte) 0x14, (byte) 0xc8, (byte) 0xad, (byte) 0xe9, + (byte) 0x77, (byte) 0x4c, (byte) 0x45, (byte) 0xc3, (byte) 0xa3, + (byte) 0xcf, (byte) 0x0d, (byte) 0x16, 0x10, (byte) 0xe4, + (byte) 0x79, (byte) 0x43, (byte) 0x3a, (byte) 0x21, (byte) 0x5a, + (byte) 0x30, (byte) 0xcf, (byte) 0x30, (byte) 0x0f, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x13, 0x01, + (byte) 0x01, (byte) 0xff, (byte) 0x04, (byte) 0x05, (byte) 0x30, + (byte) 0x03, (byte) 0x01, (byte) 0x01, (byte) 0xff, (byte) 0x30, + (byte) 0x0e, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, + 0x0f, (byte) 0x01, (byte) 0x01, (byte) 0xff, (byte) 0x04, + (byte) 0x04, (byte) 0x03, (byte) 0x02, (byte) 0x02, (byte) 0x84, + (byte) 0x30, (byte) 0x0a, (byte) 0x06, (byte) 0x08, (byte) 0x2a, + (byte) 0x86, 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x04, + (byte) 0x03, (byte) 0x02, (byte) 0x03, (byte) 0x47, (byte) 0x00, + (byte) 0x30, (byte) 0x44, (byte) 0x02, (byte) 0x20, (byte) 0x35, + (byte) 0x21, (byte) 0xa3, (byte) 0xef, (byte) 0x8b, (byte) 0x34, + (byte) 0x46, (byte) 0x1e, (byte) 0x9c, (byte) 0xd5, (byte) 0x60, + (byte) 0xf3, (byte) 0x1d, (byte) 0x58, (byte) 0x89, (byte) 0x20, + (byte) 0x6a, (byte) 0xdc, (byte) 0xa3, 0x65, (byte) 0x41, + (byte) 0xf6, (byte) 0x0d, (byte) 0x9e, (byte) 0xce, (byte) 0x8a, + (byte) 0x19, (byte) 0x8c, (byte) 0x66, (byte) 0x48, (byte) 0x60, + (byte) 0x7b, (byte) 0x02, (byte) 0x20, (byte) 0x4d, 0x0b, + (byte) 0xf3, (byte) 0x51, (byte) 0xd9, (byte) 0x30, (byte) 0x7c, + (byte) 0x7d, (byte) 0x5b, (byte) 0xda, (byte) 0x35, (byte) 0x34, + (byte) 0x1d, (byte) 0xa8, (byte) 0x47, (byte) 0x1b, (byte) 0x63, + (byte) 0xa5, (byte) 0x85, (byte) 0x65, (byte) 0x3c, (byte) 0xad, + (byte) 0x4f, (byte) 0x24, (byte) 0xa7, (byte) 0xe7, (byte) 0x4d, + (byte) 0xaf, (byte) 0x41, (byte) 0x7d, (byte) 0xf1, + (byte) 0xbf, }; + + private static final byte[] X509Issuer = { + (byte) 0x30, (byte) 0x81, (byte) 0x88, (byte) 0x31, (byte) 0x0b, + (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, + (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x55, + (byte) 0x53, (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11, + (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08, + (byte) 0x0c, (byte) 0x0a, (byte) 0x43, (byte) 0x61, (byte) 0x6c, + (byte) 0x69, (byte) 0x66, (byte) 0x6f, (byte) 0x72, (byte) 0x6e, + (byte) 0x69, (byte) 0x61, (byte) 0x31, (byte) 0x15, (byte) 0x30, + (byte) 0x13, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, + (byte) 0x0a, (byte) 0x0c, (byte) 0x0c, (byte) 0x47, (byte) 0x6f, + (byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65, (byte) 0x2c, + (byte) 0x20, (byte) 0x49, (byte) 0x6e, (byte) 0x63, (byte) 0x2e, + (byte) 0x31, (byte) 0x10, (byte) 0x30, (byte) 0x0e, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0b, (byte) 0x0c, + (byte) 0x07, (byte) 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, + (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x31, (byte) 0x3b, + (byte) 0x30, (byte) 0x39, (byte) 0x06, (byte) 0x03, (byte) 0x55, + (byte) 0x04, (byte) 0x03, (byte) 0x0c, (byte) 0x32, (byte) 0x41, + (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, + (byte) 0x64, (byte) 0x20, (byte) 0x4b, (byte) 0x65, (byte) 0x79, + (byte) 0x73, (byte) 0x74, (byte) 0x6f, (byte) 0x72, (byte) 0x65, + (byte) 0x20, (byte) 0x53, (byte) 0x6f, (byte) 0x66, (byte) 0x74, + (byte) 0x77, (byte) 0x61, (byte) 0x72, (byte) 0x65, (byte) 0x20, + (byte) 0x41, (byte) 0x74, (byte) 0x74, (byte) 0x65, (byte) 0x73, + (byte) 0x74, (byte) 0x61, (byte) 0x74, (byte) 0x69, (byte) 0x6f, + (byte) 0x6e, (byte) 0x20, (byte) 0x49, (byte) 0x6e, (byte) 0x74, + (byte) 0x65, (byte) 0x72, (byte) 0x6d, (byte) 0x65, (byte) 0x64, + (byte) 0x69, (byte) 0x61, (byte) 0x74, (byte) 0x65 }; + // AttestationApplicationId ::= SEQUENCE { + // * packageInfoRecords SET OF PackageInfoRecord, + // * signatureDigests SET OF OCTET_STRING, + // * } + // * + // * PackageInfoRecord ::= SEQUENCE { + // * packageName OCTET_STRING, + // * version INTEGER, + // * } + private static final byte[] attAppId = {0x30, 0x10, 0x31, 0x0B, 0x30, 0x04, 0x05, 'A', 'B', 'C', + 'D', 'E', 0x02, 0x01, 0x01, 0x31, 0x02, 0x04, 0x00}; + private static final byte[] attChallenge = {'c','h','a','l','l','e','n','g','e'}; + private static final byte[] expiryTime = {(byte)0x32, (byte)0x36, (byte)0x30, (byte)0x31, (byte)0x30, (byte)0x38, (byte)0x30, (byte)0x30, (byte)0x34, (byte)0x36, (byte)0x30, (byte)0x39, (byte)0x5a}; + private static final byte[] authKeyId = { (byte)0x80, (byte)0x14, (byte)0xc8, (byte)0xad, (byte)0xe9, (byte)0x77, (byte)0x4c, (byte)0x45, (byte)0xc3, (byte)0xa3, (byte)0xcf, (byte)0x0d, (byte)0x16, (byte)0x10, (byte)0xe4, (byte)0x79, (byte)0x43, (byte)0x3a, (byte)0x21, (byte)0x5a, (byte)0x30, (byte)0xcf}; + + private CardSimulator simulator; + private KMEncoder encoder; + private KMDecoder decoder; + private KMSEProvider cryptoProvider; + + public KMFunctionalTest(){ + cryptoProvider = new KMJCardSimulator(); + simulator = new CardSimulator(); + encoder = new KMEncoder(); + decoder = new KMDecoder(); + } + + private void init(){ + // Create simulator + AID appletAID = AIDUtil.create("A000000062"); + simulator.installApplet(appletAID, KMJCardSimApplet.class); + // Select applet + simulator.selectApplet(appletAID); + // provision attest key + provisionCmd(simulator); + } + + private void setBootParams(CardSimulator simulator, short osVersion, + short osPatchLevel, short vendorPatchLevel, short bootPatchLevel) { + // Argument 1 OS Version + short versionPtr = KMInteger.uint_16(osVersion); + // short versionTagPtr = KMIntegerTag.instance(KMType.UINT_TAG, + // KMType.OS_VERSION,versionPatchPtr); + // Argument 2 OS Patch level + short patchPtr = KMInteger.uint_16(osPatchLevel); + short vendorpatchPtr = KMInteger.uint_16((short) vendorPatchLevel); + short bootpatchPtr = KMInteger.uint_16((short) bootPatchLevel); + // Argument 3 Verified Boot Key + byte[] bootKeyHash = "00011122233344455566677788899900".getBytes(); + short bootKeyPtr = KMByteBlob.instance(bootKeyHash, (short) 0, + (short) bootKeyHash.length); + // Argument 4 Verified Boot Hash + short bootHashPtr = KMByteBlob.instance(bootKeyHash, (short) 0, + (short) bootKeyHash.length); + // Argument 5 Verified Boot State + short bootStatePtr = KMEnum.instance(KMType.VERIFIED_BOOT_STATE, + KMType.VERIFIED_BOOT); + // Argument 6 Device Locked + short deviceLockedPtr = KMEnum.instance(KMType.DEVICE_LOCKED, + KMType.DEVICE_LOCKED_FALSE); + // Arguments + short arrPtr = KMArray.instance((short) 8); + KMArray vals = KMArray.cast(arrPtr); + vals.add((short) 0, versionPtr); + vals.add((short) 1, patchPtr); + vals.add((short) 2, vendorpatchPtr); + vals.add((short) 3, bootpatchPtr); + vals.add((short) 4, bootKeyPtr); + vals.add((short) 5, bootHashPtr); + vals.add((short) 6, bootStatePtr); + vals.add((short) 7, deviceLockedPtr); + CommandAPDU apdu = encodeApdu((byte) INS_SET_BOOT_PARAMS_CMD, arrPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + Assert.assertEquals(0x9000, response.getSW()); + + } + + private void provisionSigningCertificate(CardSimulator simulator) { + short byteBlobPtr = KMByteBlob.instance( + (short) (kEcAttestCert.length + kEcAttestRootCert.length)); + Util.arrayCopyNonAtomic(kEcAttestCert, (short) 0, + KMByteBlob.cast(byteBlobPtr).getBuffer(), + KMByteBlob.cast(byteBlobPtr).getStartOff(), + (short) kEcAttestCert.length); + Util.arrayCopyNonAtomic(kEcAttestRootCert, (short) 0, + KMByteBlob.cast(byteBlobPtr).getBuffer(), + (short) (KMByteBlob.cast(byteBlobPtr).getStartOff() + + kEcAttestCert.length), + (short) kEcAttestRootCert.length); + CommandAPDU apdu = encodeApdu( + (byte) INS_PROVISION_ATTESTATION_CERT_CHAIN_CMD, byteBlobPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + Assert.assertEquals(0x9000, response.getSW()); + } + + private void provisionSigningKey(CardSimulator simulator) { + // KeyParameters. + short arrPtr = KMArray.instance((short) 4); + short ecCurve = KMEnumTag.instance(KMType.ECCURVE, KMType.P_256); + short byteBlob = KMByteBlob.instance((short) 1); + KMByteBlob.cast(byteBlob).add((short) 0, KMType.SHA2_256); + short digest = KMEnumArrayTag.instance(KMType.DIGEST, byteBlob); + short byteBlob2 = KMByteBlob.instance((short) 1); + KMByteBlob.cast(byteBlob2).add((short) 0, KMType.ATTEST_KEY); + short purpose = KMEnumArrayTag.instance(KMType.PURPOSE, byteBlob2); + KMArray.cast(arrPtr).add((short) 0, ecCurve); + KMArray.cast(arrPtr).add((short) 1, digest); + KMArray.cast(arrPtr).add((short) 2, + KMEnumTag.instance(KMType.ALGORITHM, KMType.EC)); + KMArray.cast(arrPtr).add((short) 3, purpose); + short keyParams = KMKeyParameters.instance(arrPtr); + // Note: VTS uses PKCS8 KeyFormat RAW + short keyFormatPtr = KMEnum.instance(KMType.KEY_FORMAT, KMType.RAW); + + // Key + short signKeyPtr = KMArray.instance((short) 2); + KMArray.cast(signKeyPtr).add((short) 0, KMByteBlob.instance(kEcPrivKey, + (short) 0, (short) kEcPrivKey.length)); + KMArray.cast(signKeyPtr).add((short) 1, KMByteBlob.instance(kEcPubKey, + (short) 0, (short) kEcPubKey.length)); + byte[] keyBuf = new byte[120]; + short len = encoder.encode(signKeyPtr, keyBuf, (short) 0); + short signKeyBstr = KMByteBlob.instance(keyBuf, (short) 0, len); + + short finalArrayPtr = KMArray.instance((short) 3); + KMArray.cast(finalArrayPtr).add((short) 0, keyParams); + KMArray.cast(finalArrayPtr).add((short) 1, keyFormatPtr); + KMArray.cast(finalArrayPtr).add((short) 2, signKeyBstr); + + CommandAPDU apdu = encodeApdu((byte) INS_PROVISION_ATTESTATION_KEY_CMD, + finalArrayPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + Assert.assertEquals(0x9000, response.getSW()); + } + + private void provisionCertificateParams(CardSimulator simulator) { + + short arrPtr = KMArray.instance((short) 3); + short byteBlob1 = KMByteBlob.instance(X509Issuer, (short) 0, + (short) X509Issuer.length); + KMArray.cast(arrPtr).add((short) 0, byteBlob1); + short byteBlob2 = KMByteBlob.instance(expiryTime, (short) 0, + (short) expiryTime.length); + KMArray.cast(arrPtr).add((short) 1, byteBlob2); + short byteBlob3 = KMByteBlob.instance(authKeyId, (short) 0, + (short) authKeyId.length); + KMArray.cast(arrPtr).add((short) 2, byteBlob3); + + CommandAPDU apdu = encodeApdu( + (byte) INS_PROVISION_ATTESTATION_CERT_PARAMS_CMD, arrPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + Assert.assertEquals(0x9000, response.getSW()); + } + + private void provisionSharedSecret(CardSimulator simulator) { + byte[] sharedKeySecret = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + short arrPtr = KMArray.instance((short) 1); + short byteBlob = KMByteBlob.instance(sharedKeySecret, (short) 0, + (short) sharedKeySecret.length); + KMArray.cast(arrPtr).add((short) 0, byteBlob); + + CommandAPDU apdu = encodeApdu((byte) INS_PROVISION_SHARED_SECRET_CMD, + arrPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + Assert.assertEquals(0x9000, response.getSW()); + } + + private void provisionAttestIds(CardSimulator simulator) { + short arrPtr = KMArray.instance((short) 8); + + byte[] buf = "Attestation Id".getBytes(); + + KMArray.cast(arrPtr).add((short) 0, + KMByteTag.instance(KMType.ATTESTATION_ID_BRAND, + KMByteBlob.instance(buf, (short) 0, (short) buf.length))); + KMArray.cast(arrPtr).add((short) 1, + KMByteTag.instance(KMType.ATTESTATION_ID_PRODUCT, + KMByteBlob.instance(buf, (short) 0, (short) buf.length))); + KMArray.cast(arrPtr).add((short) 2, + KMByteTag.instance(KMType.ATTESTATION_ID_DEVICE, + KMByteBlob.instance(buf, (short) 0, (short) buf.length))); + KMArray.cast(arrPtr).add((short) 3, + KMByteTag.instance(KMType.ATTESTATION_ID_MODEL, + KMByteBlob.instance(buf, (short) 0, (short) buf.length))); + KMArray.cast(arrPtr).add((short) 4, + KMByteTag.instance(KMType.ATTESTATION_ID_IMEI, + KMByteBlob.instance(buf, (short) 0, (short) buf.length))); + KMArray.cast(arrPtr).add((short) 5, + KMByteTag.instance(KMType.ATTESTATION_ID_MEID, + KMByteBlob.instance(buf, (short) 0, (short) buf.length))); + KMArray.cast(arrPtr).add((short) 6, + KMByteTag.instance(KMType.ATTESTATION_ID_MANUFACTURER, + KMByteBlob.instance(buf, (short) 0, (short) buf.length))); + KMArray.cast(arrPtr).add((short) 7, + KMByteTag.instance(KMType.ATTESTATION_ID_SERIAL, + KMByteBlob.instance(buf, (short) 0, (short) buf.length))); + short keyParams = KMKeyParameters.instance(arrPtr); + short outerArrPtr = KMArray.instance((short) 1); + KMArray.cast(outerArrPtr).add((short) 0, keyParams); + CommandAPDU apdu = encodeApdu((byte) INS_PROVISION_ATTEST_IDS_CMD, + outerArrPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + Assert.assertEquals(0x9000, response.getSW()); + } + + private void provisionLocked(CardSimulator simulator) { + CommandAPDU commandAPDU = new CommandAPDU(0x80, INS_LOCK_PROVISIONING_CMD, + 0x40, 0x00); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(commandAPDU); + Assert.assertEquals(0x9000, response.getSW()); + } + + private void provisionCmd(CardSimulator simulator) { + provisionSigningKey(simulator); + provisionSigningCertificate(simulator); + provisionCertificateParams(simulator); + provisionSharedSecret(simulator); + provisionAttestIds(simulator); + // set bootup parameters + setBootParams(simulator,(short)1,(short)1, (short)0, (short)0); + provisionLocked(simulator); + } + + private void cleanUp(){ + AID appletAID = AIDUtil.create("A000000062"); + // Delete i.e. uninstall applet + simulator.deleteApplet(appletAID); + } + + + private CommandAPDU encodeApdu(byte ins, short cmd){ + byte[] buf = new byte[2500]; + buf[0] = (byte)0x80; + buf[1] = ins; + buf[2] = (byte)0x40; + buf[3] = (byte)0x00; + buf[4] = 0; + short len = encoder.encode(cmd, buf, (short) 7); + Util.setShort(buf, (short)5, len); + byte[] apdu = new byte[7+len]; + Util.arrayCopyNonAtomic(buf,(short)0,apdu,(short)0,(short)(7+len)); + //CommandAPDU commandAPDU = new CommandAPDU(0x80, 0x10, 0x40, 0x00, buf, 0, actualLen); + return new CommandAPDU(apdu); + } + + @Test + public void testAesImportKeySuccess() { + init(); + byte[] aesKeySecret = new byte[] {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + short arrPtr = KMArray.instance((short)5); + short boolTag = KMBoolTag.instance(KMType.NO_AUTH_REQUIRED); + short keySize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, KMInteger.uint_16((short)128)); + short byteBlob = KMByteBlob.instance((short)1); + KMByteBlob.cast(byteBlob).add((short)0, KMType.ECB); + short blockMode = KMEnumArrayTag.instance(KMType.BLOCK_MODE, byteBlob); + byteBlob = KMByteBlob.instance((short)1); + KMByteBlob.cast(byteBlob).add((short)0, KMType.PKCS7); + short paddingMode = KMEnumArrayTag.instance(KMType.PADDING, byteBlob); + KMArray.cast(arrPtr).add((short)0, boolTag); + KMArray.cast(arrPtr).add((short)1, keySize); + KMArray.cast(arrPtr).add((short)2, blockMode); + KMArray.cast(arrPtr).add((short)3, paddingMode); + KMArray.cast(arrPtr).add((short)4, KMEnumTag.instance(KMType.ALGORITHM, KMType.AES)); + short keyParams = KMKeyParameters.instance(arrPtr); + short keyFormatPtr = KMEnum.instance(KMType.KEY_FORMAT, KMType.RAW); + short keyBlob = KMArray.instance((short)1); + KMArray.cast(keyBlob).add((short)0, KMByteBlob.instance(aesKeySecret,(short)0,(short)16)); + byte[] blob = new byte[256]; + short len = encoder.encode(keyBlob,blob,(short)0); + keyBlob = KMByteBlob.instance(blob, (short)0, len); + arrPtr = KMArray.instance((short)3); + KMArray arg = KMArray.cast(arrPtr); + arg.add((short) 0, keyParams); + arg.add((short)1, keyFormatPtr); + arg.add((short)2, keyBlob); + CommandAPDU apdu = encodeApdu((byte)INS_IMPORT_KEY_CMD, arrPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + short ret = KMArray.instance((short) 3); + KMArray.cast(ret).add((short) 0, KMInteger.exp()); + KMArray.cast(ret).add((short)1, KMByteBlob.exp()); + short inst = KMKeyCharacteristics.exp(); + KMArray.cast(ret).add((short) 2, inst); + byte[] respBuf = response.getBytes(); + len = (short) respBuf.length; + ret = decoder.decode(ret, respBuf, (short) 0, len); + short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + short keyBlobLength = KMByteBlob.cast(KMArray.cast(ret).get((short)1)).length(); + short keyCharacteristics = KMArray.cast(ret).get((short)2); + short hwParams = KMKeyCharacteristics.cast(keyCharacteristics).getHardwareEnforced(); + short swParams = KMKeyCharacteristics.cast(keyCharacteristics).getSoftwareEnforced(); + Assert.assertEquals(0x9000, response.getSW()); + Assert.assertEquals(error, KMError.OK); + short tag = KMKeyParameters.findTag(KMType.BOOL_TAG, KMType.NO_AUTH_REQUIRED, hwParams); + Assert.assertEquals(KMBoolTag.cast(tag).getVal(),0x01); + tag = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.KEYSIZE, hwParams); + Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getShort(), 128); + tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PADDING, hwParams); + Assert.assertTrue(KMEnumArrayTag.cast(tag).contains(KMType.PKCS7)); + tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.BLOCK_MODE, hwParams); + Assert.assertTrue(KMEnumArrayTag.cast(tag).contains(KMType.ECB)); + tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, hwParams); + Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.AES); + tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ORIGIN, hwParams); + Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.IMPORTED); + cleanUp(); + } + + @Test + public void testHmacImportKeySuccess() { + init(); + byte[] hmacKeySecret = new byte[] {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + short arrPtr = KMArray.instance((short)5); + short boolTag = KMBoolTag.instance(KMType.NO_AUTH_REQUIRED); + short keySize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, KMInteger.uint_16((short)128)); + short byteBlob = KMByteBlob.instance((short)1); + KMByteBlob.cast(byteBlob).add((short)0, KMType.SHA2_256); + short digest = KMEnumArrayTag.instance(KMType.DIGEST, byteBlob); + short minMacLength = KMIntegerTag.instance(KMType.UINT_TAG,KMType.MIN_MAC_LENGTH, KMInteger.uint_16((short)256)); + KMArray.cast(arrPtr).add((short)0, boolTag); + KMArray.cast(arrPtr).add((short)1, keySize); + KMArray.cast(arrPtr).add((short)2, digest); + KMArray.cast(arrPtr).add((short)3, minMacLength); + KMArray.cast(arrPtr).add((short)4, KMEnumTag.instance(KMType.ALGORITHM, KMType.HMAC)); + short keyParams = KMKeyParameters.instance(arrPtr); + short keyFormatPtr = KMEnum.instance(KMType.KEY_FORMAT, KMType.RAW); + short keyBlob = KMArray.instance((short)1); + KMArray.cast(keyBlob).add((short)0, KMByteBlob.instance(hmacKeySecret,(short)0,(short)16)); + byte[] blob = new byte[256]; + short len = encoder.encode(keyBlob,blob,(short)0); + keyBlob = KMByteBlob.instance(blob, (short)0, len); + arrPtr = KMArray.instance((short)3); + KMArray arg = KMArray.cast(arrPtr); + arg.add((short) 0, keyParams); + arg.add((short)1, keyFormatPtr); + arg.add((short)2, keyBlob); + CommandAPDU apdu = encodeApdu((byte)INS_IMPORT_KEY_CMD, arrPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + short ret = KMArray.instance((short) 3); + KMArray.cast(ret).add((short) 0, KMInteger.exp()); + KMArray.cast(ret).add((short)1, KMByteBlob.exp()); + short inst = KMKeyCharacteristics.exp(); + KMArray.cast(ret).add((short) 2, inst); + byte[] respBuf = response.getBytes(); + len = (short) respBuf.length; + ret = decoder.decode(ret, respBuf, (short) 0, len); + short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + short keyBlobLength = KMByteBlob.cast(KMArray.cast(ret).get((short)1)).length(); + short keyCharacteristics = KMArray.cast(ret).get((short)2); + short hwParams = KMKeyCharacteristics.cast(keyCharacteristics).getHardwareEnforced(); + short swParams = KMKeyCharacteristics.cast(keyCharacteristics).getSoftwareEnforced(); + Assert.assertEquals(0x9000, response.getSW()); + Assert.assertEquals(error, KMError.OK); + short tag = KMKeyParameters.findTag(KMType.BOOL_TAG, KMType.NO_AUTH_REQUIRED, hwParams); + Assert.assertEquals(KMBoolTag.cast(tag).getVal(),0x01); + tag = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.KEYSIZE, hwParams); + Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getShort(), 128); + tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.DIGEST, hwParams); + Assert.assertTrue(KMEnumArrayTag.cast(tag).contains(KMType.SHA2_256)); + tag = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, hwParams); + Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getShort(), 256); + tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, hwParams); + Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.HMAC); + tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ORIGIN, hwParams); + Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.IMPORTED); + cleanUp(); + } + + @Test + public void testRsaImportKeySuccess() { + init(); + /* + KeyPair rsaKeyPair = cryptoProvider.createRsaKeyPair(); + byte[] pub = new byte[4]; + short len = ((RSAPublicKey)rsaKeyPair.getPublic()).getExponent(pub,(short)1); + byte[] priv = new byte[256]; + byte[] mod = new byte[256]; + len = ((RSAPrivateKey)rsaKeyPair.getPrivate()).getModulus(mod,(short)0); + len = ((RSAPrivateKey)rsaKeyPair.getPrivate()).getExponent(priv,(short)0); + */ + + byte[] pub = new byte[]{0x00,0x01,0x00,0x01}; + byte[] mod = new byte[256]; + byte[] priv = new byte[256]; + short[] lengths = new short[2]; + cryptoProvider.createAsymmetricKey(KMType.RSA,priv,(short)0,(short)256,mod,(short)0, (short)256,lengths); + short arrPtr = KMArray.instance((short)6); + short boolTag = KMBoolTag.instance(KMType.NO_AUTH_REQUIRED); + short keySize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, KMInteger.uint_16((short)2048)); + short byteBlob = KMByteBlob.instance((short)1); + KMByteBlob.cast(byteBlob).add((short)0, KMType.SHA2_256); + short digest = KMEnumArrayTag.instance(KMType.DIGEST, byteBlob); + short rsaPubExpTag = KMIntegerTag.instance(KMType.ULONG_TAG,KMType.RSA_PUBLIC_EXPONENT, + KMInteger.uint_32(pub, (short)0)); + byteBlob = KMByteBlob.instance((short)1); + KMByteBlob.cast(byteBlob).add((short)0, KMType.RSA_PSS); + short padding = KMEnumArrayTag.instance(KMType.PADDING, byteBlob); + KMArray.cast(arrPtr).add((short)0, boolTag); + KMArray.cast(arrPtr).add((short)1, keySize); + KMArray.cast(arrPtr).add((short)2, digest); + KMArray.cast(arrPtr).add((short)3, rsaPubExpTag); + KMArray.cast(arrPtr).add((short)4, KMEnumTag.instance(KMType.ALGORITHM, KMType.RSA)); + KMArray.cast(arrPtr).add((short)5, padding); + short keyParams = KMKeyParameters.instance(arrPtr); + short keyFormatPtr = KMEnum.instance(KMType.KEY_FORMAT, KMType.RAW);// Note: VTS uses PKCS8 + short keyBlob = KMArray.instance((short)2); + KMArray.cast(keyBlob).add((short)0, KMByteBlob.instance(priv,(short)0,(short)256)); + KMArray.cast(keyBlob).add((short)1, KMByteBlob.instance(mod,(short)0,(short)256)); + byte[] blob = new byte[620]; + short len = encoder.encode(keyBlob,blob,(short)0); + keyBlob = KMByteBlob.instance(blob, (short)0, len); + arrPtr = KMArray.instance((short)3); + KMArray arg = KMArray.cast(arrPtr); + arg.add((short) 0, keyParams); + arg.add((short)1, keyFormatPtr); + arg.add((short)2, keyBlob); + CommandAPDU apdu = encodeApdu((byte)INS_IMPORT_KEY_CMD, arrPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + short ret = KMArray.instance((short) 3); + KMArray.cast(ret).add((short) 0, KMInteger.exp()); + KMArray.cast(ret).add((short)1, KMByteBlob.exp()); + short inst = KMKeyCharacteristics.exp(); + KMArray.cast(ret).add((short) 2, inst); + byte[] respBuf = response.getBytes(); + len = (short) respBuf.length; + ret = decoder.decode(ret, respBuf, (short) 0, len); + short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + short keyBlobLength = KMByteBlob.cast(KMArray.cast(ret).get((short)1)).length(); + short keyCharacteristics = KMArray.cast(ret).get((short)2); + short hwParams = KMKeyCharacteristics.cast(keyCharacteristics).getHardwareEnforced(); + short swParams = KMKeyCharacteristics.cast(keyCharacteristics).getSoftwareEnforced(); + Assert.assertEquals(0x9000, response.getSW()); + Assert.assertEquals(error, KMError.OK); + short tag = KMKeyParameters.findTag(KMType.BOOL_TAG, KMType.NO_AUTH_REQUIRED, hwParams); + Assert.assertEquals(KMBoolTag.cast(tag).getVal(),0x01); + tag = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.KEYSIZE, hwParams); + Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getShort(), 2048); + tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.DIGEST, hwParams); + Assert.assertTrue(KMEnumArrayTag.cast(tag).contains(KMType.SHA2_256)); + tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PADDING, hwParams); + Assert.assertTrue(KMEnumArrayTag.cast(tag).contains(KMType.RSA_PSS)); + tag = KMKeyParameters.findTag(KMType.ULONG_TAG, KMType.RSA_PUBLIC_EXPONENT, hwParams); + Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getSignificantShort(), 0x01); + Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getShort(), 0x01); + tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, hwParams); + Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.RSA); + tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ORIGIN, hwParams); + Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.IMPORTED); + cleanUp(); + } + + @Test + public void testDeviceLocked(){ + init(); + byte[] hmacKey = new byte[32]; + cryptoProvider.newRandomNumber(hmacKey,(short)0,(short)32); + KMRepository.instance().initComputedHmac(hmacKey,(short)0,(short)32); + // generate aes key with unlocked_device_required + short aesKey = generateAesDesKey(KMType.AES,(short)128,null,null, true); + short keyBlobPtr = KMArray.cast(aesKey).get((short)1); + byte[] keyBlob= new byte[KMByteBlob.cast(keyBlobPtr).length()]; + Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), + KMByteBlob.cast(keyBlobPtr).getStartOff(), + keyBlob,(short)0, (short)keyBlob.length); + // encrypt something + short inParams = getAesDesParams(KMType.AES, KMType.ECB, KMType.PKCS7, null); + byte[] plainData= "Hello World 123!".getBytes(); + short ret = processMessage(plainData, + KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), + KMType.ENCRYPT, + KMKeyParameters.instance(inParams), + (short)0,null,false, false + ); + keyBlobPtr = KMArray.cast(ret).get((short)2); + byte[] cipherData = new byte[KMByteBlob.cast(keyBlobPtr).length()]; + Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), + cipherData,(short)0, (short)cipherData.length); + // create verification token + short verToken = KMVerificationToken.instance(); + KMVerificationToken.cast(verToken).setTimestamp(KMInteger.uint_16((short)1)); + verToken = signVerificationToken(verToken); + // device locked request + deviceLock(verToken); + // decrypt should fail + inParams = getAesDesParams(KMType.AES, KMType.ECB, KMType.PKCS7, null); + short beginResp = begin(KMType.DECRYPT, + KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), KMKeyParameters.instance(inParams), (short)0); + Assert.assertEquals(beginResp,KMError.DEVICE_LOCKED); + short hwToken = KMHardwareAuthToken.instance(); + KMHardwareAuthToken.cast(hwToken).setTimestamp(KMInteger.uint_16((byte)2)); + KMHardwareAuthToken.cast(hwToken).setHwAuthenticatorType(KMEnum.instance(KMType.USER_AUTH_TYPE, (byte)KMType.PASSWORD)); + inParams = getAesDesParams(KMType.AES, KMType.ECB, KMType.PKCS7, null); + hwToken = signHwToken(hwToken); + ret = processMessage(cipherData, + KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), + KMType.DECRYPT, + KMKeyParameters.instance(inParams),hwToken,null,false, false + ); + ret = KMArray.cast(ret).get((short)0); + Assert.assertEquals(KMInteger.cast(ret).getShort(), KMError.OK); + cleanUp(); + } + + private short signHwToken(short hwToken){ + short len = 0; + byte[] scratchPad = new byte[256]; + // add 0 + Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0); + len = 1; + // concatenate challenge - 8 bytes + short ptr = KMHardwareAuthToken.cast(hwToken).getChallenge(); + KMInteger.cast(ptr) + .value(scratchPad, (short) (len + (short) (8 - KMInteger.cast(ptr).length()))); + len += 8; + // concatenate user id - 8 bytes + ptr = KMHardwareAuthToken.cast(hwToken).getUserId(); + KMInteger.cast(ptr) + .value(scratchPad, (short) (len + (short) (8 - KMInteger.cast(ptr).length()))); + len += 8; + // concatenate authenticator id - 8 bytes + ptr = KMHardwareAuthToken.cast(hwToken).getAuthenticatorId(); + KMInteger.cast(ptr) + .value(scratchPad, (short) (len + (short) (8 - KMInteger.cast(ptr).length()))); + len += 8; + // concatenate authenticator type - 4 bytes + ptr = KMHardwareAuthToken.cast(hwToken).getHwAuthenticatorType(); + scratchPad[(short) (len + 3)] = KMEnum.cast(ptr).getVal(); + len += 4; + // concatenate timestamp -8 bytes + ptr = KMHardwareAuthToken.cast(hwToken).getTimestamp(); + KMInteger.cast(ptr) + .value(scratchPad, (short) (len + (short) (8 - KMInteger.cast(ptr).length()))); + len += 8; + // hmac the data +/* HMACKey key = + cryptoProvider.createHMACKey( + KMRepository.instance().getComputedHmacKey(), + (short) 0, + (short) KMRepository.instance().getComputedHmacKey().length); + + */ + byte[] mac = new byte[32]; + /* + len = + cryptoProvider.hmacSign(key, scratchPad, (short) 0, len, + mac, + (short)0); + */ + short key = KMRepository.instance().getComputedHmacKey(); + cryptoProvider.hmacSign( + KMByteBlob.cast(key).getBuffer(), + KMByteBlob.cast(key).getStartOff(), + KMByteBlob.cast(key).length(), + scratchPad, (short) 0, len, + mac, + (short)0); + KMHardwareAuthToken.cast(hwToken).setMac(KMByteBlob.instance(mac,(short)0,(short)mac.length)); + return hwToken; + } + private void deviceLock(short verToken) { + short req = KMArray.instance((short)2); + KMArray.cast(req).add((short)0, KMInteger.uint_8((byte)1)); + KMArray.cast(req).add((short)1, verToken); + CommandAPDU apdu = encodeApdu((byte)INS_DEVICE_LOCKED_CMD,req); + ResponseAPDU response = simulator.transmitCommand(apdu); + short ret = KMArray.instance((short) 1); + KMArray.cast(ret).add((short) 0, KMInteger.exp()); + byte[] respBuf = response.getBytes(); + Assert.assertEquals(respBuf[0],KMError.OK); + } + + private short signVerificationToken(short verToken) { + byte[] scratchPad = new byte[256]; + byte[] authVer = "Auth Verification".getBytes(); + //print(authVer,(short)0,(short)authVer.length); + // concatenation length will be 37 + length of verified parameters list - which is typically empty + Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0); + short params = KMVerificationToken.cast(verToken).getParametersVerified(); + // Add "Auth Verification" - 17 bytes. + Util.arrayCopy(authVer,(short)0, scratchPad, (short)0, (short)authVer.length); + short len = (short)authVer.length; + // concatenate challenge - 8 bytes + short ptr = KMVerificationToken.cast(verToken).getChallenge(); + KMInteger.cast(ptr) + .value(scratchPad, (short) (len + (short) (8 - KMInteger.cast(ptr).length()))); + len += 8; + // concatenate timestamp -8 bytes + ptr = KMVerificationToken.cast(verToken).getTimestamp(); + KMInteger.cast(ptr) + .value(scratchPad, (short) (len + (short) (8 - KMInteger.cast(ptr).length()))); + len += 8; + // concatenate security level - 4 bytes + ptr = KMVerificationToken.cast(verToken).getSecurityLevel(); + scratchPad[(short) (len + 3)] = KMEnum.cast(ptr).getVal(); + len += 4; + // concatenate Parameters verified - blob of encoded data. + ptr = KMVerificationToken.cast(verToken).getParametersVerified(); + if (KMByteBlob.cast(ptr).length() != 0) { + len += KMByteBlob.cast(ptr).getValues(scratchPad, (short) 0); + } + // hmac the data + /* HMACKey key = + cryptoProvider.createHMACKey( + KMRepository.instance().getComputedHmacKey(), + (short) 0, + (short) KMRepository.instance().getComputedHmacKey().length); + + */ + ptr = KMVerificationToken.cast(verToken).getMac(); + byte[] mac = new byte[32]; + /*len = + cryptoProvider.hmacSign(key, scratchPad, (short) 0, len, + mac, + (short)0); + */ + short key = KMRepository.instance().getComputedHmacKey(); + cryptoProvider.hmacSign(KMByteBlob.cast(key).getBuffer(), + KMByteBlob.cast(key).getStartOff(), + KMByteBlob.cast(key).length(), + scratchPad, (short) 0, len, + mac, + (short)0); + KMVerificationToken.cast(verToken).setMac(KMByteBlob.instance(mac,(short)0,(short)mac.length)); + return verToken; + } + + @Test + public void testEcImportKeySuccess() { + init(); + /* + KeyPair ecKeyPair = cryptoProvider.createECKeyPair(); + byte[] pub = new byte[128]; + short len = ((ECPublicKey)ecKeyPair.getPublic()).getW(pub,(short)0); + byte[] priv = new byte[128]; + len = ((ECPrivateKey)ecKeyPair.getPrivate()).getS(priv,(short)0); + */ + byte[] pub = new byte[128]; + byte[] priv = new byte[128]; + short[] lengths = new short[2]; + cryptoProvider.createAsymmetricKey(KMType.EC,priv,(short)0,(short)128,pub,(short)0, (short)128,lengths); + short pubBlob = KMByteBlob.instance(pub,(short)0,lengths[1]); + short privBlob = KMByteBlob.instance(priv,(short)0,lengths[0]); + short arrPtr = KMArray.instance((short)5); + short boolTag = KMBoolTag.instance(KMType.NO_AUTH_REQUIRED); + short keySize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, KMInteger.uint_16((short)256)); + short byteBlob = KMByteBlob.instance((short)1); + KMByteBlob.cast(byteBlob).add((short)0, KMType.SHA2_256); + short digest = KMEnumArrayTag.instance(KMType.DIGEST, byteBlob); + short ecCurve = KMEnumTag.instance(KMType.ECCURVE, KMType.P_256); + KMArray.cast(arrPtr).add((short)0, boolTag); + KMArray.cast(arrPtr).add((short)1, keySize); + KMArray.cast(arrPtr).add((short)2, digest); + KMArray.cast(arrPtr).add((short)3, ecCurve); + KMArray.cast(arrPtr).add((short)4, KMEnumTag.instance(KMType.ALGORITHM, KMType.EC)); + short keyParams = KMKeyParameters.instance(arrPtr); + short keyFormatPtr = KMEnum.instance(KMType.KEY_FORMAT, KMType.RAW);// Note: VTS uses PKCS8 + short keyBlob = KMArray.instance((short)2); + KMArray.cast(keyBlob).add((short)0, privBlob); + KMArray.cast(keyBlob).add((short)1, pubBlob); + byte[] blob = new byte[128]; + short len = encoder.encode(keyBlob,blob,(short)0); + keyBlob = KMByteBlob.instance(blob, (short)0, len); + arrPtr = KMArray.instance((short)3); + KMArray arg = KMArray.cast(arrPtr); + arg.add((short) 0, keyParams); + arg.add((short)1, keyFormatPtr); + arg.add((short)2, keyBlob); + CommandAPDU apdu = encodeApdu((byte)INS_IMPORT_KEY_CMD, arrPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + short ret = KMArray.instance((short) 3); + KMArray.cast(ret).add((short) 0, KMInteger.exp()); + KMArray.cast(ret).add((short)1, KMByteBlob.exp()); + short inst = KMKeyCharacteristics.exp(); + KMArray.cast(ret).add((short) 2, inst); + byte[] respBuf = response.getBytes(); + len = (short) respBuf.length; + ret = decoder.decode(ret, respBuf, (short) 0, len); + short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + short keyBlobLength = KMByteBlob.cast(KMArray.cast(ret).get((short)1)).length(); + short blobArr = extractKeyBlobArray(KMArray.cast(ret).get((short)1)); + short keyCharacteristics = KMArray.cast(ret).get((short)2); + short hwParams = KMKeyCharacteristics.cast(keyCharacteristics).getHardwareEnforced(); + short swParams = KMKeyCharacteristics.cast(keyCharacteristics).getSoftwareEnforced(); + Assert.assertEquals(0x9000, response.getSW()); + Assert.assertEquals(error, KMError.OK); + short tag = KMKeyParameters.findTag(KMType.BOOL_TAG, KMType.NO_AUTH_REQUIRED, hwParams); + Assert.assertEquals(KMBoolTag.cast(tag).getVal(),0x01); + tag = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.KEYSIZE, hwParams); + Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getShort(), 256); + tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.DIGEST, hwParams); + Assert.assertTrue(KMEnumArrayTag.cast(tag).contains(KMType.SHA2_256)); + tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ECCURVE, hwParams); + Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.P_256); + tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, hwParams); + Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.EC); + tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ORIGIN, hwParams); + Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.IMPORTED); + cleanUp(); + } + + private short extractKeyBlobArray(short keyBlob) { + short ret = KMArray.instance((short) 5); + KMArray.cast(ret).add(KMKeymasterApplet.KEY_BLOB_SECRET, KMByteBlob.exp()); + KMArray.cast(ret).add(KMKeymasterApplet.KEY_BLOB_AUTH_TAG, KMByteBlob.exp()); + KMArray.cast(ret).add(KMKeymasterApplet.KEY_BLOB_NONCE, KMByteBlob.exp()); + short ptr = KMKeyCharacteristics.exp(); + KMArray.cast(ret).add(KMKeymasterApplet.KEY_BLOB_KEYCHAR, ptr); + KMArray.cast(ret).add(KMKeymasterApplet.KEY_BLOB_PUB_KEY, KMByteBlob.exp()); + ret = + decoder.decodeArray( + ret, + KMByteBlob.cast(keyBlob).getBuffer(), + KMByteBlob.cast(keyBlob).getStartOff(), + KMByteBlob.cast(keyBlob).length()); + short len = KMArray.cast(ret).length(); + ptr = KMArray.cast(ret).get((short)4); +// print(KMByteBlob.cast(ptr).getBuffer(),KMByteBlob.cast(ptr).getStartOff(),KMByteBlob.cast(ptr).length()); + return ret; + } + + @Test + public void testRsaGenerateKeySuccess() { + init(); + short ret = generateRsaKey(null, null); + short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + short keyBlobLength = KMByteBlob.cast(KMArray.cast(ret).get((short)1)).length(); + short keyCharacteristics = KMArray.cast(ret).get((short)2); + short hwParams = KMKeyCharacteristics.cast(keyCharacteristics).getHardwareEnforced(); + short swParams = KMKeyCharacteristics.cast(keyCharacteristics).getSoftwareEnforced(); + Assert.assertEquals(error, KMError.OK); + short tag = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.KEYSIZE, hwParams); + Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getShort(), 2048); + tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.DIGEST, hwParams); + Assert.assertTrue(KMEnumArrayTag.cast(tag).contains(KMType.DIGEST_NONE)); + tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PADDING, hwParams); + Assert.assertTrue(KMEnumArrayTag.cast(tag).contains(KMType.RSA_PKCS1_1_5_ENCRYPT)); + tag = KMKeyParameters.findTag(KMType.ULONG_TAG, KMType.RSA_PUBLIC_EXPONENT, hwParams); + Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getSignificantShort(), 0x01); + Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getShort(), 0x01); + tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, hwParams); + Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.RSA); + tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ORIGIN, hwParams); + Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.GENERATED); + cleanUp(); + } + + private short generateRsaKey(byte[] clientId, byte[] appData){ + byte[] activeAndCreationDateTime = {0,0,0x01,0x73,0x51,0x7C,(byte)0xCC,0x00}; + short tagCount = 11; + if(clientId != null) tagCount++; + if(appData != null) tagCount++; + short arrPtr = KMArray.instance(tagCount); + short keySize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, KMInteger.uint_16((short)2048)); + short byteBlob = KMByteBlob.instance((short)3); + KMByteBlob.cast(byteBlob).add((short)0, KMType.DIGEST_NONE); + KMByteBlob.cast(byteBlob).add((short)1, KMType.SHA2_256); + KMByteBlob.cast(byteBlob).add((short)2, KMType.SHA1); + short digest = KMEnumArrayTag.instance(KMType.DIGEST, byteBlob); + byteBlob = KMByteBlob.instance((short)5); + KMByteBlob.cast(byteBlob).add((short)0, KMType.RSA_PKCS1_1_5_ENCRYPT); + KMByteBlob.cast(byteBlob).add((short)1, KMType.RSA_PKCS1_1_5_SIGN); + KMByteBlob.cast(byteBlob).add((short)2, KMType.RSA_OAEP); + KMByteBlob.cast(byteBlob).add((short)3, KMType.RSA_PSS); + KMByteBlob.cast(byteBlob).add((short)4, KMType.PADDING_NONE); + short padding = KMEnumArrayTag.instance(KMType.PADDING, byteBlob); + byteBlob = KMByteBlob.instance((short)5); + KMByteBlob.cast(byteBlob).add((short)0, KMType.SIGN); + KMByteBlob.cast(byteBlob).add((short)1, KMType.VERIFY); + KMByteBlob.cast(byteBlob).add((short)2, KMType.ENCRYPT); + KMByteBlob.cast(byteBlob).add((short)3, KMType.DECRYPT); + KMByteBlob.cast(byteBlob).add((short)4, KMType.WRAP_KEY); + short purpose = KMEnumArrayTag.instance(KMType.PURPOSE, byteBlob); + byte[] pub = {0,1,0,1}; + short rsaPubExpTag = KMIntegerTag.instance(KMType.ULONG_TAG,KMType.RSA_PUBLIC_EXPONENT, KMInteger.uint_32(pub, (short)0)); + short boolTag = KMBoolTag.instance(KMType.NO_AUTH_REQUIRED); + short tagIndex = 0; + KMArray.cast(arrPtr).add(tagIndex++, purpose); + KMArray.cast(arrPtr).add(tagIndex++, KMBoolTag.instance(KMType.INCLUDE_UNIQUE_ID)); + KMArray.cast(arrPtr).add(tagIndex++, KMBoolTag.instance(KMType.RESET_SINCE_ID_ROTATION)); + KMArray.cast(arrPtr).add(tagIndex++, boolTag); + KMArray.cast(arrPtr).add(tagIndex++, keySize); + KMArray.cast(arrPtr).add(tagIndex++, digest); + KMArray.cast(arrPtr).add(tagIndex++, rsaPubExpTag); + KMArray.cast(arrPtr).add(tagIndex++, KMEnumTag.instance(KMType.ALGORITHM, KMType.RSA)); + KMArray.cast(arrPtr).add(tagIndex++, padding); + short dateTag = KMInteger.uint_64(activeAndCreationDateTime,(short)0); + KMArray.cast(arrPtr).add(tagIndex++, KMIntegerTag.instance(KMType.DATE_TAG,KMType.ACTIVE_DATETIME,dateTag)); + KMArray.cast(arrPtr).add(tagIndex++, KMIntegerTag.instance(KMType.DATE_TAG,KMType.CREATION_DATETIME,dateTag)); + + if(clientId != null)KMArray.cast(arrPtr).add(tagIndex++, + KMByteTag.instance(KMType.APPLICATION_ID, KMByteBlob.instance(clientId,(short)0,(short)clientId.length))); + if(appData != null)KMArray.cast(arrPtr).add(tagIndex++, + KMByteTag.instance(KMType.APPLICATION_DATA, KMByteBlob.instance(appData,(short)0,(short)appData.length))); + short keyParams = KMKeyParameters.instance(arrPtr); + arrPtr = KMArray.instance((short)1); + KMArray arg = KMArray.cast(arrPtr); + arg.add((short) 0, keyParams); + CommandAPDU apdu = encodeApdu((byte)INS_GENERATE_KEY_CMD, arrPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + Assert.assertEquals(0x9000, response.getSW()); + short ret = KMArray.instance((short) 3); + KMArray.cast(ret).add((short) 0, KMInteger.exp()); + KMArray.cast(ret).add((short)1, KMByteBlob.exp()); + short inst = KMKeyCharacteristics.exp(); + KMArray.cast(ret).add((short) 2, inst); + byte[] respBuf = response.getBytes(); + short len = (short) respBuf.length; + ret = decoder.decode(ret, respBuf, (short) 0, len); + return ret; + } + + private short generateAttestationKey(){ + // 15th July 2020 00.00.00 + byte[] activeAndCreationDateTime = {0,0,0x01,0x73,0x51,0x7C,(byte)0xCC,0x00}; + short tagCount = 11; + short arrPtr = KMArray.instance(tagCount); + short keySize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, KMInteger.uint_16((short)2048)); + short byteBlob = KMByteBlob.instance((short)3); + KMByteBlob.cast(byteBlob).add((short)0, KMType.DIGEST_NONE); + KMByteBlob.cast(byteBlob).add((short)1, KMType.SHA2_256); + KMByteBlob.cast(byteBlob).add((short)2, KMType.SHA1); + short digest = KMEnumArrayTag.instance(KMType.DIGEST, byteBlob); + byteBlob = KMByteBlob.instance((short)1); + KMByteBlob.cast(byteBlob).add((short)0, KMType.RSA_PKCS1_1_5_SIGN); + short padding = KMEnumArrayTag.instance(KMType.PADDING, byteBlob); + byteBlob = KMByteBlob.instance((short)1); + KMByteBlob.cast(byteBlob).add((short)0, KMType.ATTEST_KEY); + short purpose = KMEnumArrayTag.instance(KMType.PURPOSE, byteBlob); + byte[] pub = {0,1,0,1}; + short rsaPubExpTag = KMIntegerTag.instance(KMType.ULONG_TAG,KMType.RSA_PUBLIC_EXPONENT, KMInteger.uint_32(pub, (short)0)); + short boolTag = KMBoolTag.instance(KMType.NO_AUTH_REQUIRED); + short tagIndex = 0; + KMArray.cast(arrPtr).add(tagIndex++, purpose); + KMArray.cast(arrPtr).add(tagIndex++, boolTag); + KMArray.cast(arrPtr).add(tagIndex++, KMBoolTag.instance(KMType.INCLUDE_UNIQUE_ID)); + KMArray.cast(arrPtr).add(tagIndex++, KMBoolTag.instance(KMType.RESET_SINCE_ID_ROTATION)); + KMArray.cast(arrPtr).add(tagIndex++, boolTag); + KMArray.cast(arrPtr).add(tagIndex++, keySize); + KMArray.cast(arrPtr).add(tagIndex++, digest); + KMArray.cast(arrPtr).add(tagIndex++, rsaPubExpTag); + KMArray.cast(arrPtr).add(tagIndex++, KMEnumTag.instance(KMType.ALGORITHM, KMType.RSA)); + KMArray.cast(arrPtr).add(tagIndex++, padding); + short dateTag = KMInteger.uint_64(activeAndCreationDateTime,(short)0); + KMArray.cast(arrPtr).add(tagIndex++, KMIntegerTag.instance(KMType.ULONG_TAG,KMType.ACTIVE_DATETIME,dateTag)); + KMArray.cast(arrPtr).add(tagIndex++, KMIntegerTag.instance(KMType.ULONG_TAG,KMType.CREATION_DATETIME,dateTag)); + short keyParams = KMKeyParameters.instance(arrPtr); + arrPtr = KMArray.instance((short)1); + KMArray arg = KMArray.cast(arrPtr); + arg.add((short) 0, keyParams); + CommandAPDU apdu = encodeApdu((byte)INS_GENERATE_KEY_CMD, arrPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + Assert.assertEquals(0x9000, response.getSW()); + short ret = KMArray.instance((short) 3); + KMArray.cast(ret).add((short) 0, KMInteger.exp()); + KMArray.cast(ret).add((short)1, KMByteBlob.exp()); + short inst = KMKeyCharacteristics.exp(); + KMArray.cast(ret).add((short) 2, inst); + byte[] respBuf = response.getBytes(); + short len = (short) respBuf.length; + ret = decoder.decode(ret, respBuf, (short) 0, len); + return ret; + } + + @Test + public void testEcGenerateKeySuccess() { + init(); + short ret = generateEcKey(null, null); + short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + short keyBlobLength = KMByteBlob.cast(KMArray.cast(ret).get((short)1)).length(); + short keyCharacteristics = KMArray.cast(ret).get((short)2); + short hwParams = KMKeyCharacteristics.cast(keyCharacteristics).getHardwareEnforced(); + short swParams = KMKeyCharacteristics.cast(keyCharacteristics).getSoftwareEnforced(); + Assert.assertEquals(error, KMError.OK); + short tag = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.KEYSIZE, hwParams); + Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getShort(), 256); + tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.DIGEST, hwParams); + Assert.assertTrue(KMEnumArrayTag.cast(tag).contains(KMType.DIGEST_NONE)); + tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, hwParams); + Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.EC); + tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ORIGIN, hwParams); + Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.GENERATED); + cleanUp(); + } + public short generateEcKey(byte[] clientId, byte[] appData) { + byte[] activeAndCreationDateTime = {0,0,0x01,0x73,0x51,0x7C,(byte)0xCC,0x00}; + short tagCount = 6; + if(clientId != null) tagCount++; + if(appData != null) tagCount++; + short arrPtr = KMArray.instance(tagCount); + short keySize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, KMInteger.uint_16((short)256)); + short byteBlob = KMByteBlob.instance((short)2); + KMByteBlob.cast(byteBlob).add((short)0, KMType.DIGEST_NONE); + KMByteBlob.cast(byteBlob).add((short)1, KMType.SHA2_256); + short digest = KMEnumArrayTag.instance(KMType.DIGEST, byteBlob); + byteBlob = KMByteBlob.instance((short)2); + KMByteBlob.cast(byteBlob).add((short)0, KMType.SIGN); + KMByteBlob.cast(byteBlob).add((short)1, KMType.VERIFY); + short purpose = KMEnumArrayTag.instance(KMType.PURPOSE, byteBlob); + short boolTag = KMBoolTag.instance(KMType.NO_AUTH_REQUIRED); + short tagIndex = 0; + KMArray.cast(arrPtr).add(tagIndex++, purpose); + KMArray.cast(arrPtr).add(tagIndex++, boolTag); + KMArray.cast(arrPtr).add(tagIndex++, keySize); + KMArray.cast(arrPtr).add(tagIndex++, digest); + KMArray.cast(arrPtr).add(tagIndex++, KMEnumTag.instance(KMType.ALGORITHM, KMType.EC)); + short dateTag = KMInteger.uint_64(activeAndCreationDateTime,(short)0); + KMArray.cast(arrPtr).add(tagIndex++, KMIntegerTag.instance(KMType.DATE_TAG,KMType.CREATION_DATETIME,dateTag)); + if(clientId != null)KMArray.cast(arrPtr).add(tagIndex++, + KMByteTag.instance(KMType.APPLICATION_ID, KMByteBlob.instance(clientId,(short)0,(short)clientId.length))); + if(appData != null)KMArray.cast(arrPtr).add(tagIndex++, + KMByteTag.instance(KMType.APPLICATION_DATA, KMByteBlob.instance(appData,(short)0,(short)appData.length))); + short keyParams = KMKeyParameters.instance(arrPtr); + arrPtr = KMArray.instance((short)1); + KMArray arg = KMArray.cast(arrPtr); + arg.add((short) 0, keyParams); + CommandAPDU apdu = encodeApdu((byte)INS_GENERATE_KEY_CMD, arrPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + Assert.assertEquals(0x9000, response.getSW()); + short ret = KMArray.instance((short) 3); + KMArray.cast(ret).add((short) 0, KMInteger.exp()); + KMArray.cast(ret).add((short)1, KMByteBlob.exp()); + short inst = KMKeyCharacteristics.exp(); + KMArray.cast(ret).add((short) 2, inst); + byte[] respBuf = response.getBytes(); + short len = (short) respBuf.length; + ret = decoder.decode(ret, respBuf, (short) 0, len); + return ret; + } + + @Test + public void testHmacGenerateKeySuccess() { + init(); + short ret = generateHmacKey(null, null); + short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + short keyBlobLength = KMByteBlob.cast(KMArray.cast(ret).get((short)1)).length(); + short keyCharacteristics = KMArray.cast(ret).get((short)2); + short hwParams = KMKeyCharacteristics.cast(keyCharacteristics).getHardwareEnforced(); + short swParams = KMKeyCharacteristics.cast(keyCharacteristics).getSoftwareEnforced(); + Assert.assertEquals(error, KMError.OK); + short tag = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.KEYSIZE, hwParams); + Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getShort(), 128); + tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.DIGEST, hwParams); + Assert.assertTrue(KMEnumArrayTag.cast(tag).contains(KMType.SHA2_256)); + tag = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, hwParams); + Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getShort(), 160); + tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, hwParams); + Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.HMAC); + tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ORIGIN, hwParams); + Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.GENERATED); + cleanUp(); + } + public short generateHmacKey(byte[] clientId, byte[] appData){ + short tagCount = 6; + if(clientId != null) tagCount++; + if(appData != null) tagCount++; + short arrPtr = KMArray.instance(tagCount); + short keySize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, KMInteger.uint_16((short)128)); + short byteBlob = KMByteBlob.instance((short)1); + KMByteBlob.cast(byteBlob).add((short)0, KMType.SHA2_256); + short digest = KMEnumArrayTag.instance(KMType.DIGEST, byteBlob); + byteBlob = KMByteBlob.instance((short)2); + KMByteBlob.cast(byteBlob).add((short)0, KMType.SIGN); + KMByteBlob.cast(byteBlob).add((short)1, KMType.VERIFY); + short purpose = KMEnumArrayTag.instance(KMType.PURPOSE, byteBlob); + short boolTag = KMBoolTag.instance(KMType.NO_AUTH_REQUIRED); + short minMacLen = KMIntegerTag.instance(KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, KMInteger.uint_16((short)/*256*/160)); + short tagIndex = 0; + KMArray.cast(arrPtr).add(tagIndex++, minMacLen); + KMArray.cast(arrPtr).add(tagIndex++, purpose); + KMArray.cast(arrPtr).add(tagIndex++, boolTag); + KMArray.cast(arrPtr).add(tagIndex++, keySize); + KMArray.cast(arrPtr).add(tagIndex++, digest); + KMArray.cast(arrPtr).add(tagIndex++, KMEnumTag.instance(KMType.ALGORITHM, KMType.HMAC)); + if(clientId != null)KMArray.cast(arrPtr).add(tagIndex++, + KMByteTag.instance(KMType.APPLICATION_ID, KMByteBlob.instance(clientId,(short)0,(short)clientId.length))); + if(appData != null)KMArray.cast(arrPtr).add(tagIndex++, + KMByteTag.instance(KMType.APPLICATION_DATA, KMByteBlob.instance(appData,(short)0,(short)appData.length))); + short keyParams = KMKeyParameters.instance(arrPtr); + arrPtr = KMArray.instance((short)1); + KMArray arg = KMArray.cast(arrPtr); + arg.add((short) 0, keyParams); + CommandAPDU apdu = encodeApdu((byte)INS_GENERATE_KEY_CMD, arrPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + short ret = KMArray.instance((short) 3); + KMArray.cast(ret).add((short) 0, KMInteger.exp()); + KMArray.cast(ret).add((short)1, KMByteBlob.exp()); + short inst = KMKeyCharacteristics.exp(); + KMArray.cast(ret).add((short) 2, inst); + byte[] respBuf = response.getBytes(); + short len = (short) respBuf.length; + ret = decoder.decode(ret, respBuf, (short) 0, len); + short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + Assert.assertEquals(0x9000, response.getSW()); + Assert.assertEquals(error, KMError.OK); + return ret; + } + public short generateAesDesKey(byte alg, short keysize, byte[] clientId, byte[] appData, boolean unlockReqd) { + short tagCount = 7; + if(clientId != null) tagCount++; + if(appData != null) tagCount++; + if(unlockReqd)tagCount++; + short arrPtr = KMArray.instance(tagCount); + short boolTag = KMBoolTag.instance(KMType.NO_AUTH_REQUIRED); + short keySize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, KMInteger.uint_16(keysize)); + short byteBlob = KMByteBlob.instance((short)3); + KMByteBlob.cast(byteBlob).add((short)0, KMType.ECB); + KMByteBlob.cast(byteBlob).add((short)1, KMType.CBC); + KMByteBlob.cast(byteBlob).add((short)2, KMType.CTR); + short blockModeTag = KMEnumArrayTag.instance(KMType.BLOCK_MODE, byteBlob); + byteBlob = KMByteBlob.instance((short)2); + KMByteBlob.cast(byteBlob).add((short)0, KMType.PKCS7); + KMByteBlob.cast(byteBlob).add((short)1, KMType.PADDING_NONE); + short paddingMode = KMEnumArrayTag.instance(KMType.PADDING, byteBlob); + byteBlob = KMByteBlob.instance((short)2); + KMByteBlob.cast(byteBlob).add((short)0, KMType.ENCRYPT); + KMByteBlob.cast(byteBlob).add((short)1, KMType.DECRYPT); + short purpose = KMEnumArrayTag.instance(KMType.PURPOSE, byteBlob); + short tagIndex = 0; + KMArray.cast(arrPtr).add(tagIndex++, boolTag); + KMArray.cast(arrPtr).add(tagIndex++, keySize); + KMArray.cast(arrPtr).add(tagIndex++, blockModeTag); + KMArray.cast(arrPtr).add(tagIndex++, paddingMode); + KMArray.cast(arrPtr).add(tagIndex++, KMEnumTag.instance(KMType.ALGORITHM, alg)); + KMArray.cast(arrPtr).add(tagIndex++, purpose); + KMArray.cast(arrPtr).add(tagIndex++, KMBoolTag.instance(KMType.CALLER_NONCE)); + if(unlockReqd)KMArray.cast(arrPtr).add(tagIndex++, KMBoolTag.instance(KMType.UNLOCKED_DEVICE_REQUIRED)); + if(clientId != null)KMArray.cast(arrPtr).add(tagIndex++, + KMByteTag.instance(KMType.APPLICATION_ID, KMByteBlob.instance(clientId,(short)0,(short)clientId.length))); + if(appData != null)KMArray.cast(arrPtr).add(tagIndex++, + KMByteTag.instance(KMType.APPLICATION_DATA, KMByteBlob.instance(appData,(short)0,(short)appData.length))); + short keyParams = KMKeyParameters.instance(arrPtr); + arrPtr = KMArray.instance((short)1); + KMArray arg = KMArray.cast(arrPtr); + arg.add((short) 0, keyParams); + CommandAPDU apdu = encodeApdu((byte)INS_GENERATE_KEY_CMD, arrPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + short ret = KMArray.instance((short) 3); + KMArray.cast(ret).add((short) 0, KMInteger.exp()); + KMArray.cast(ret).add((short)1, KMByteBlob.exp()); + short inst = KMKeyCharacteristics.exp(); + KMArray.cast(ret).add((short) 2, inst); + byte[] respBuf = response.getBytes(); + short len = (short) respBuf.length; + ret = decoder.decode(ret, respBuf, (short) 0, len); + short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + Assert.assertEquals(0x9000, response.getSW()); + Assert.assertEquals(error, KMError.OK); + return ret; + } + public short generateAesGcmKey(short keysize, byte[] clientId, byte[] appData) { + short tagCount = 8; + if(clientId != null) tagCount++; + if(appData != null) tagCount++; + short arrPtr = KMArray.instance(tagCount); + short boolTag = KMBoolTag.instance(KMType.NO_AUTH_REQUIRED); + short keySize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, KMInteger.uint_16(keysize)); + short macLength = KMIntegerTag.instance(KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, KMInteger.uint_16((short)96)); + short byteBlob = KMByteBlob.instance((short)1); + KMByteBlob.cast(byteBlob).add((short)0, KMType.GCM); + short blockModeTag = KMEnumArrayTag.instance(KMType.BLOCK_MODE, byteBlob); + byteBlob = KMByteBlob.instance((short)1); + KMByteBlob.cast(byteBlob).add((short)0, KMType.PADDING_NONE); + short paddingMode = KMEnumArrayTag.instance(KMType.PADDING, byteBlob); + byteBlob = KMByteBlob.instance((short)2); + KMByteBlob.cast(byteBlob).add((short)0, KMType.ENCRYPT); + KMByteBlob.cast(byteBlob).add((short)1, KMType.DECRYPT); + short purpose = KMEnumArrayTag.instance(KMType.PURPOSE, byteBlob); + short tagIndex = 0; + KMArray.cast(arrPtr).add(tagIndex++, boolTag); + KMArray.cast(arrPtr).add(tagIndex++, macLength); + KMArray.cast(arrPtr).add(tagIndex++, keySize); + KMArray.cast(arrPtr).add(tagIndex++, blockModeTag); + KMArray.cast(arrPtr).add(tagIndex++, paddingMode); + KMArray.cast(arrPtr).add(tagIndex++, KMEnumTag.instance(KMType.ALGORITHM, KMType.AES)); + KMArray.cast(arrPtr).add(tagIndex++, purpose); + KMArray.cast(arrPtr).add(tagIndex++, KMBoolTag.instance(KMType.CALLER_NONCE)); + if(clientId != null)KMArray.cast(arrPtr).add(tagIndex++, + KMByteTag.instance(KMType.APPLICATION_ID, KMByteBlob.instance(clientId,(short)0,(short)clientId.length))); + if(appData != null)KMArray.cast(arrPtr).add(tagIndex++, + KMByteTag.instance(KMType.APPLICATION_DATA, KMByteBlob.instance(appData,(short)0,(short)appData.length))); + short keyParams = KMKeyParameters.instance(arrPtr); + arrPtr = KMArray.instance((short)1); + KMArray arg = KMArray.cast(arrPtr); + arg.add((short) 0, keyParams); + CommandAPDU apdu = encodeApdu((byte)INS_GENERATE_KEY_CMD, arrPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + short ret = KMArray.instance((short) 3); + KMArray.cast(ret).add((short) 0, KMInteger.exp()); + KMArray.cast(ret).add((short)1, KMByteBlob.exp()); + short inst = KMKeyCharacteristics.exp(); + KMArray.cast(ret).add((short) 2, inst); + byte[] respBuf = response.getBytes(); + short len = (short) respBuf.length; + ret = decoder.decode(ret, respBuf, (short) 0, len); + short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + Assert.assertEquals(0x9000, response.getSW()); + Assert.assertEquals(error, KMError.OK); + return ret; + } + + @Test + public void testComputeHmacParams(){ + init(); + // Get Hmac parameters + short ret = getHmacSharingParams(); + short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + KMHmacSharingParameters params = KMHmacSharingParameters.cast(KMArray.cast(ret).get((short)1)); + short seed = params.getSeed(); + short nonce = params.getNonce(); + + short params1 = KMHmacSharingParameters.instance(); + KMHmacSharingParameters.cast(params1).setSeed(KMByteBlob.instance((short)0)); + short num = KMByteBlob.instance((short)32); + Util.arrayCopyNonAtomic( + KMByteBlob.cast(nonce).getBuffer(), + KMByteBlob.cast(nonce).getStartOff(), + KMByteBlob.cast(num).getBuffer(), + KMByteBlob.cast(num).getStartOff(), + KMByteBlob.cast(num).length()); + // cryptoProvider.newRandomNumber( +// KMByteBlob.cast(num).getBuffer(), +// KMByteBlob.cast(num).getStartOff(), +// KMByteBlob.cast(num).length()); + KMHmacSharingParameters.cast(params1).setNonce(num); + short params2 = KMHmacSharingParameters.instance(); + KMHmacSharingParameters.cast(params2).setSeed(KMByteBlob.instance((short)0)); + num = KMByteBlob.instance((short)32); + cryptoProvider.newRandomNumber( + KMByteBlob.cast(num).getBuffer(), + KMByteBlob.cast(num).getStartOff(), + KMByteBlob.cast(num).length()); + KMHmacSharingParameters.cast(params2).setNonce(num); + short arr = KMArray.instance((short)2); + KMArray.cast(arr).add((short)0, params1); + KMArray.cast(arr).add((short)1,params2); + short arrPtr = KMArray.instance((short)1); + KMArray.cast(arrPtr).add((short)0,arr); + CommandAPDU apdu = encodeApdu((byte)INS_COMPUTE_SHARED_HMAC_CMD, arrPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + Assert.assertEquals(0x9000, response.getSW()); + ret = KMArray.instance((short) 2); + KMArray.cast(ret).add((short) 0, KMInteger.exp()); + KMArray.cast(ret).add((short)1, KMByteBlob.exp()); + byte[] respBuf = response.getBytes(); + short len = (short) respBuf.length; + ret = decoder.decode(ret, respBuf, (short) 0, len); + error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + Assert.assertEquals(0x9000, response.getSW()); + Assert.assertEquals(error, KMError.OK); + + cleanUp(); + } + @Test + public void testGetHmacSharingParams(){ + init(); + CommandAPDU commandAPDU = new CommandAPDU(0x80, INS_GET_HMAC_SHARING_PARAM_CMD, 0x40, 0x00); + //print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(commandAPDU); + KMDecoder dec = new KMDecoder(); + short ret = KMArray.instance((short) 2); + KMArray.cast(ret).add((short) 0, KMInteger.exp()); + short inst = KMHmacSharingParameters.exp(); + KMArray.cast(ret).add((short) 1, inst); + byte[] respBuf = response.getBytes(); + short len = (short) respBuf.length; + ret = decoder.decode(ret, respBuf, (short) 0, len); + short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + KMHmacSharingParameters params = KMHmacSharingParameters.cast(KMArray.cast(ret).get((short)1)); + short seed = params.getSeed(); + short nonce = params.getNonce(); + Assert.assertTrue(KMByteBlob.cast(seed).length() == 0); + Assert.assertTrue(KMByteBlob.cast(nonce).length() == 32); + //print(seed); + //print(nonce); + Assert.assertEquals(error, KMError.OK); + cleanUp(); + } + public short getHmacSharingParams(){ + CommandAPDU commandAPDU = new CommandAPDU(0x80, INS_GET_HMAC_SHARING_PARAM_CMD, 0x40, 0x00); + //print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(commandAPDU); + KMDecoder dec = new KMDecoder(); + short ret = KMArray.instance((short) 2); + KMArray.cast(ret).add((short) 0, KMInteger.exp()); + short inst = KMHmacSharingParameters.exp(); + KMArray.cast(ret).add((short) 1, inst); + byte[] respBuf = response.getBytes(); + short len = (short) respBuf.length; + ret = decoder.decode(ret, respBuf, (short) 0, len); + return ret; + } + + @Test + public void testImportWrappedKey(){ + init(); + byte[] wrappedKey = new byte[16]; + cryptoProvider.newRandomNumber(wrappedKey,(short)0,(short)16); + byte[] encWrappedKey = new byte[16]; + //AESKey transportKey = cryptoProvider.createAESKey((short)256); + byte[] transportKeyMaterial = new byte[32]; + cryptoProvider.newRandomNumber(transportKeyMaterial,(short)0,(short)32); + //transportKey.setKey(transportKeyMaterial,(short)0); + byte[] nonce = new byte[12]; + cryptoProvider.newRandomNumber(nonce,(short)0,(short)12); + byte[] authData = "Auth Data".getBytes(); + byte[] authTag = new byte[12]; + cryptoProvider.aesGCMEncrypt(transportKeyMaterial,(short)0,(short)32,wrappedKey, + (short)0,(short)16,encWrappedKey,(short)0, + nonce,(short)0, (short)12,authData,(short)0,(short)authData.length, + authTag, (short)0, (short)12); + byte[] maskingKey = {1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0}; + byte[] maskedTransportKey = new byte[32]; + for(int i=0; i< maskingKey.length;i++){ + maskedTransportKey[i] = (byte)(transportKeyMaterial[i] ^ maskingKey[i]); + } + short rsaKeyArr = generateRsaKey(null,null); + short keyBlobPtr = KMArray.cast(rsaKeyArr).get((short)1); + byte[] wrappingKeyBlob= new byte[KMByteBlob.cast(keyBlobPtr).length()]; + Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), + KMByteBlob.cast(keyBlobPtr).getStartOff(), + wrappingKeyBlob,(short)0, (short)wrappingKeyBlob.length); + short inParams = getRsaParams(KMType.SHA2_256, KMType.RSA_OAEP); + short ret = processMessage(maskedTransportKey, + KMByteBlob.instance(wrappingKeyBlob,(short)0, (short)wrappingKeyBlob.length), + KMType.ENCRYPT, + KMKeyParameters.instance(inParams), + (short)0,null,false,false + ); + keyBlobPtr = KMArray.cast(ret).get((short)2); + byte[] encTransportKey = new byte[KMByteBlob.cast(keyBlobPtr).length()]; + Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), + encTransportKey,(short)0, (short)encTransportKey.length); + short tagCount = 7; + short arrPtr = KMArray.instance(tagCount); + short boolTag = KMBoolTag.instance(KMType.NO_AUTH_REQUIRED); + short keySize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, KMInteger.uint_16((short)128)); + short byteBlob = KMByteBlob.instance((short)2); + KMByteBlob.cast(byteBlob).add((short)0, KMType.ECB); + KMByteBlob.cast(byteBlob).add((short)1, KMType.CBC); + short blockModeTag = KMEnumArrayTag.instance(KMType.BLOCK_MODE, byteBlob); + byteBlob = KMByteBlob.instance((short)2); + KMByteBlob.cast(byteBlob).add((short)0, KMType.PKCS7); + KMByteBlob.cast(byteBlob).add((short)1, KMType.PADDING_NONE); + short paddingMode = KMEnumArrayTag.instance(KMType.PADDING, byteBlob); + byteBlob = KMByteBlob.instance((short)2); + KMByteBlob.cast(byteBlob).add((short)0, KMType.ENCRYPT); + KMByteBlob.cast(byteBlob).add((short)1, KMType.DECRYPT); + short purpose = KMEnumArrayTag.instance(KMType.PURPOSE, byteBlob); + short tagIndex = 0; + KMArray.cast(arrPtr).add(tagIndex++, boolTag); + KMArray.cast(arrPtr).add(tagIndex++, keySize); + KMArray.cast(arrPtr).add(tagIndex++, blockModeTag); + KMArray.cast(arrPtr).add(tagIndex++, paddingMode); + KMArray.cast(arrPtr).add(tagIndex++, KMEnumTag.instance(KMType.ALGORITHM, KMType.AES)); + KMArray.cast(arrPtr).add(tagIndex++, purpose); + KMArray.cast(arrPtr).add(tagIndex++, KMBoolTag.instance(KMType.CALLER_NONCE)); + short keyParams = KMKeyParameters.instance(arrPtr); + short nullParams = KMArray.instance((short)0); + nullParams = KMKeyParameters.instance(nullParams); + short arr = KMArray.instance((short)12); + KMArray.cast(arr).add((short) 0, keyParams); // Key Params of wrapped key + KMArray.cast(arr).add((short) 1, KMEnum.instance(KMType.KEY_FORMAT,KMType.RAW)); // Key Format + KMArray.cast(arr).add((short) 2, KMByteBlob.instance(encWrappedKey,(short)0,(short)encWrappedKey.length)); // Wrapped Import Key Blob + KMArray.cast(arr).add((short) 3, KMByteBlob.instance(authTag,(short)0,(short)authTag.length)); // Auth Tag + KMArray.cast(arr).add((short) 4, KMByteBlob.instance(nonce,(short)0,(short)nonce.length)); // IV - Nonce + KMArray.cast(arr).add((short) 5, KMByteBlob.instance(encTransportKey,(short)0,(short)encTransportKey.length)); // Encrypted Transport Key + KMArray.cast(arr).add((short) 6, KMByteBlob.instance(wrappingKeyBlob,(short)0, (short)wrappingKeyBlob.length)); // Wrapping Key KeyBlob + KMArray.cast(arr).add((short) 7, KMByteBlob.instance(maskingKey,(short)0,(short)maskingKey.length)); // Masking Key + KMArray.cast(arr).add((short) 8, nullParams); // Un-wrapping Params + KMArray.cast(arr).add((short) 9, KMByteBlob.instance(authData,(short)0,(short)authData.length)); // Wrapped Key ASSOCIATED AUTH DATA + KMArray.cast(arr).add((short) 10, KMInteger.uint_8((byte)0)); // Password Sid + KMArray.cast(arr).add((short) 11, KMInteger.uint_8((byte)0)); // Biometric Sid + CommandAPDU apdu = encodeApdu((byte)INS_IMPORT_WRAPPED_KEY_CMD, arr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + ret = KMArray.instance((short) 3); + KMArray.cast(ret).add((short) 0, KMInteger.exp()); + KMArray.cast(ret).add((short)1, KMByteBlob.exp()); + short inst = KMKeyCharacteristics.exp(); + KMArray.cast(ret).add((short) 2, inst); + byte[] respBuf = response.getBytes(); + short len = (short) respBuf.length; + ret = decoder.decode(ret, respBuf, (short) 0, len); + short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + short keyBlobLength = KMByteBlob.cast(KMArray.cast(ret).get((short)1)).length(); + short keyCharacteristics = KMArray.cast(ret).get((short)2); + short hwParams = KMKeyCharacteristics.cast(keyCharacteristics).getHardwareEnforced(); + short swParams = KMKeyCharacteristics.cast(keyCharacteristics).getSoftwareEnforced(); + Assert.assertEquals(0x9000, response.getSW()); + Assert.assertEquals(error, KMError.OK); + short tag = KMKeyParameters.findTag(KMType.BOOL_TAG, KMType.NO_AUTH_REQUIRED, hwParams); + Assert.assertEquals(KMBoolTag.cast(tag).getVal(),0x01); + tag = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.KEYSIZE, hwParams); + Assert.assertEquals(KMInteger.cast(KMIntegerTag.cast(tag).getValue()).getShort(), 128); + tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PADDING, hwParams); + Assert.assertTrue(KMEnumArrayTag.cast(tag).contains(KMType.PKCS7)); + tag = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.BLOCK_MODE, hwParams); + Assert.assertTrue(KMEnumArrayTag.cast(tag).contains(KMType.ECB)); + tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, hwParams); + Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.AES); + tag = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ORIGIN, hwParams); + Assert.assertEquals(KMEnumTag.cast(tag).getValue(), KMType.SECURELY_IMPORTED); + cleanUp(); + } + + @Test + public void testGetKeyCharacteristicsWithIdDataSuccess() { + init(); + byte[] clientId = "clientId".getBytes(); + byte[] appData = "appData".getBytes(); + short ret = generateRsaKey(clientId,appData); + short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + Assert.assertEquals(error, KMError.OK); + short keyBlob = KMArray.cast(ret).get((short)1); + + short arrPtr = KMArray.instance((short)3); + KMArray.cast(arrPtr).add((short)0, keyBlob); + KMArray.cast(arrPtr).add((short)1, KMByteBlob.instance(clientId,(short)0, (short)clientId.length)); + KMArray.cast(arrPtr).add((short)2, KMByteBlob.instance(appData,(short)0, (short)appData.length)); + CommandAPDU apdu = encodeApdu((byte)INS_GET_KEY_CHARACTERISTICS_CMD, arrPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + ret = KMArray.instance((short) 2); + KMArray.cast(ret).add((short) 0, KMInteger.exp()); + short inst = KMKeyCharacteristics.exp(); + KMArray.cast(ret).add((short) 1, inst); + byte[] respBuf = response.getBytes(); + short len = (short) respBuf.length; + ret = decoder.decode(ret, respBuf, (short) 0, len); + error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + Assert.assertEquals(error, KMError.OK); + cleanUp(); + } + + @Test + public void testGetKeyCharacteristicsSuccess() { + init(); + short ret = generateRsaKey(null, null); + short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + Assert.assertEquals(error, KMError.OK); + short keyBlob = KMArray.cast(ret).get((short)1); + + short arrPtr = KMArray.instance((short)3); + KMArray.cast(arrPtr).add((short)0, keyBlob); + KMArray.cast(arrPtr).add((short)1, KMByteBlob.instance((short)0)); + KMArray.cast(arrPtr).add((short)2, KMByteBlob.instance((short)0)); + CommandAPDU apdu = encodeApdu((byte)INS_GET_KEY_CHARACTERISTICS_CMD, arrPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + ret = KMArray.instance((short) 2); + KMArray.cast(ret).add((short) 0, KMInteger.exp()); + short inst = KMKeyCharacteristics.exp(); + KMArray.cast(ret).add((short) 1, inst); + byte[] respBuf = response.getBytes(); + short len = (short) respBuf.length; + ret = decoder.decode(ret, respBuf, (short) 0, len); + error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + Assert.assertEquals(error, KMError.OK); + cleanUp(); + } + + @Test + public void testDeleteKeySuccess() { + init(); + short ret = generateRsaKey(null, null); + short keyBlobPtr = KMArray.cast(ret).get((short)1); + byte[] keyBlob = new byte[KMByteBlob.cast(keyBlobPtr).length()]; + short len = KMByteBlob.cast(keyBlobPtr).getValues(keyBlob, (short)0); + ret = getKeyCharacteristics(keyBlobPtr); + short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + Assert.assertEquals(error, KMError.OK); + ret = deleteKey(KMByteBlob.instance(keyBlob,(short)0,(short)keyBlob.length)); + Assert.assertEquals(ret, KMError.OK); +/* ret = getKeyCharacteristics(KMByteBlob.instance(keyBlob,(short)0,(short)keyBlob.length)); + short err = KMByteBlob.cast(ret).get((short)1); + Assert.assertEquals(KMError.INVALID_KEY_BLOB,err); + + */ + cleanUp(); + } + + @Test + public void testDeleteAllKeySuccess() { + init(); + short ret1 = generateRsaKey(null, null); + short keyBlobPtr = KMArray.cast(ret1).get((short)1); + byte[] keyBlob1 = new byte[KMByteBlob.cast(keyBlobPtr).length()]; + short len = KMByteBlob.cast(keyBlobPtr).getValues(keyBlob1, (short)0); + short ret2 = generateRsaKey(null, null); + keyBlobPtr = KMArray.cast(ret2).get((short)1); + byte[] keyBlob2 = new byte[KMByteBlob.cast(keyBlobPtr).length()]; + len = KMByteBlob.cast(keyBlobPtr).getValues(keyBlob2, (short)0); + CommandAPDU apdu = new CommandAPDU(0x80, INS_DELETE_ALL_KEYS_CMD, 0x40, 0x00); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + byte[] respBuf = response.getBytes(); + Assert.assertEquals(respBuf[0], KMError.OK); +/* short ret = getKeyCharacteristics(KMByteBlob.instance(keyBlob1,(short)0,(short)keyBlob1.length)); + short err = KMByteBlob.cast(ret).get((short)1); + Assert.assertEquals(KMError.INVALID_KEY_BLOB,err); + ret = getKeyCharacteristics(KMByteBlob.instance(keyBlob2,(short)0,(short)keyBlob2.length)); + err = KMByteBlob.cast(ret).get((short)1); + Assert.assertEquals(KMError.INVALID_KEY_BLOB,err); + + */ + cleanUp(); + } + + private short deleteKey(short keyBlob) { + short arrPtr = KMArray.instance((short)1); + KMArray.cast(arrPtr).add((short)0, keyBlob); + CommandAPDU apdu = encodeApdu((byte)INS_DELETE_KEY_CMD, arrPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + byte[] respBuf = response.getBytes(); + return respBuf[0]; + } + + private short abort(short opHandle) { + short arrPtr = KMArray.instance((short)1); + KMArray.cast(arrPtr).add((short)0, opHandle); + CommandAPDU apdu = encodeApdu((byte)INS_ABORT_OPERATION_CMD, arrPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + byte[] respBuf = response.getBytes(); + return respBuf[0]; + } + + public short getKeyCharacteristics(short keyBlob){ + short arrPtr = KMArray.instance((short)3); + KMArray.cast(arrPtr).add((short)0, keyBlob); + KMArray.cast(arrPtr).add((short)1, KMByteBlob.instance((short)0)); + KMArray.cast(arrPtr).add((short)2, KMByteBlob.instance((short)0)); + CommandAPDU apdu = encodeApdu((byte)INS_GET_KEY_CHARACTERISTICS_CMD, arrPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + short ret = KMArray.instance((short) 2); + KMArray.cast(ret).add((short) 0, KMInteger.exp()); + short inst = KMKeyCharacteristics.exp(); + KMArray.cast(ret).add((short) 1, inst); + byte[] respBuf = response.getBytes(); + short len = (short) respBuf.length; + if( len > 5) + ret = decoder.decode(ret, respBuf, (short) 0, len); + else + ret = KMByteBlob.instance(respBuf, (short)0, len); + return ret; + } + + @Test + public void testWithAesGcmWithUpdate(){ + init(); + testEncryptDecryptWithAesDes(KMType.AES, KMType.GCM, KMType.PADDING_NONE,true); + cleanUp(); + } + @Test + public void testWithAesEcbPkcs7WithUpdate(){ + init(); + testEncryptDecryptWithAesDes(KMType.AES, KMType.ECB, KMType.PKCS7,true); + cleanUp(); + } + + @Test + public void testWithAesCtrNoPadWithUpdate(){ + init(); + testEncryptDecryptWithAesDes(KMType.AES, KMType.CTR, KMType.PADDING_NONE,true); + cleanUp(); + } + + @Test + public void testWithAesCtrNoPad(){ + init(); + testEncryptDecryptWithAesDes(KMType.AES, KMType.CTR, KMType.PADDING_NONE,false); + cleanUp(); + } + + @Test + public void testWithAesEcbNoPadWithUpdate(){ + init(); + testEncryptDecryptWithAesDes(KMType.AES, KMType.ECB, KMType.PADDING_NONE,true); + cleanUp(); + } + @Test + public void testWithDesEcbPkcs7WithUpdate(){ + init(); + testEncryptDecryptWithAesDes(KMType.DES, KMType.ECB, KMType.PKCS7,true); + cleanUp(); + } + @Test + public void testWithDesEcbNoPadWithUpdate(){ + init(); + testEncryptDecryptWithAesDes(KMType.DES, KMType.ECB, KMType.PADDING_NONE,true); + cleanUp(); + } + @Test + public void testWithAesCbcPkcs7WithUpdate(){ + init(); + testEncryptDecryptWithAesDes(KMType.AES, KMType.CBC, KMType.PKCS7,true); + cleanUp(); + } + @Test + public void testWithAesCbcNoPadWithUpdate(){ + init(); + testEncryptDecryptWithAesDes(KMType.AES, KMType.CBC, KMType.PADDING_NONE,true); + cleanUp(); + } + @Test + public void testWithDesCbcPkcs7WithUpdate(){ + init(); + testEncryptDecryptWithAesDes(KMType.DES, KMType.CBC, KMType.PKCS7,true); + cleanUp(); + } + @Test + public void testWithDesCbcNoPadWithUpdate(){ + init(); + testEncryptDecryptWithAesDes(KMType.DES, KMType.CBC, KMType.PADDING_NONE,true); + cleanUp(); + } + + @Test + public void testWithAesEcbPkcs7(){ + init(); + testEncryptDecryptWithAesDes(KMType.AES, KMType.ECB, KMType.PKCS7,false); + cleanUp(); + } + @Test + public void testWithAesCbcPkcs7(){ + init(); + testEncryptDecryptWithAesDes(KMType.AES, KMType.CBC, KMType.PKCS7,false); + cleanUp(); + } + @Test + public void testWithAesEcbNoPad(){ + init(); + testEncryptDecryptWithAesDes(KMType.AES, KMType.ECB, KMType.PADDING_NONE,false); + cleanUp(); + } + + @Test + public void testWithAesCbcNoPad(){ + init(); + testEncryptDecryptWithAesDes(KMType.AES, KMType.CBC, KMType.PADDING_NONE,false); + cleanUp(); + } + + @Test + public void testWithDesCbcPkcs7(){ + init(); + testEncryptDecryptWithAesDes(KMType.DES, KMType.CBC, KMType.PKCS7,false); + cleanUp(); + } + + @Test + public void testWithDesCbcNoPad(){ + init(); + testEncryptDecryptWithAesDes(KMType.DES, KMType.CBC, KMType.PADDING_NONE,false); + cleanUp(); + } + @Test + public void testWithDesEcbNoPad(){ + init(); + testEncryptDecryptWithAesDes(KMType.DES, KMType.ECB, KMType.PADDING_NONE,false); + cleanUp(); + } + @Test + public void testWithDesEcbPkcs7(){ + init(); + testEncryptDecryptWithAesDes(KMType.DES, KMType.ECB, KMType.PKCS7,false); + cleanUp(); + } + + @Test + public void testWithRsa256Oaep(){ + init(); + testEncryptDecryptWithRsa(KMType.SHA2_256, KMType.RSA_OAEP); + cleanUp(); + } + @Test + public void testWithRsaSha1Oaep(){ + init(); + testEncryptDecryptWithRsa(KMType.SHA1, KMType.RSA_OAEP); + cleanUp(); + } + + @Test + public void testWithRsaNonePkcs1(){ + init(); + testEncryptDecryptWithRsa(KMType.DIGEST_NONE, KMType.RSA_PKCS1_1_5_ENCRYPT); + cleanUp(); + } + + @Test + public void testWithRsaNoneNoPad(){ + init(); + testEncryptDecryptWithRsa(KMType.DIGEST_NONE, KMType.PADDING_NONE); + cleanUp(); + } + + // TODO Signing with no digest is not supported by crypto provider or javacard + @Test + public void testSignWithRsaNoneNoPad(){ + init(); + testSignVerifyWithRsa(KMType.DIGEST_NONE, KMType.PADDING_NONE,false, false); + cleanUp(); + } + + @Test + public void testSignWithRsaNonePkcs1(){ + init(); + testSignVerifyWithRsa(KMType.DIGEST_NONE, KMType.RSA_PKCS1_1_5_SIGN,false, false); + cleanUp(); + } + + @Test + public void testSignVerifyWithHmacSHA256WithUpdate(){ + init(); + testSignVerifyWithHmac(KMType.SHA2_256, true); + cleanUp(); + } + + @Test + public void testSignVerifyWithHmacSHA256(){ + init(); + testSignVerifyWithHmac(KMType.SHA2_256, false); + cleanUp(); + } + + @Test + public void testSignVerifyWithEcdsaSHA256WithUpdate(){ + init(); + testSignVerifyWithEcdsa(KMType.SHA2_256, true); + cleanUp(); + } + @Test + public void testSignVerifyWithEcdsaSHA256(){ + init(); + testSignVerifyWithEcdsa(KMType.SHA2_256, false); + cleanUp(); + } + @Test + public void testSignVerifyWithRsaSHA256Pkcs1(){ + init(); + testSignVerifyWithRsa(KMType.SHA2_256, KMType.RSA_PKCS1_1_5_SIGN,false, true); + cleanUp(); + } + @Test + public void testSignVerifyWithRsaSHA256Pss(){ + init(); + testSignVerifyWithRsa(KMType.SHA2_256, KMType.RSA_PSS,false, true); + cleanUp(); + } + + @Test + public void testSignVerifyWithRsaSHA256Pkcs1WithUpdate(){ + init(); + testSignVerifyWithRsa(KMType.SHA2_256, KMType.RSA_PKCS1_1_5_SIGN,true, true); + cleanUp(); + } + + @Test + public void testProvisionSuccess(){ + AID appletAID1 = AIDUtil.create("A000000062"); + simulator.installApplet(appletAID1, KMJCardSimApplet.class); + // Select applet + simulator.selectApplet(appletAID1); + // provision attest key + provisionCmd(simulator); + cleanUp(); + } + + @Test + public void testAttestRsaKey(){ + init(); + short key = generateRsaKey(null,null); + short keyBlobPtr = KMArray.cast(key).get((short)1); + byte[] keyBlob= new byte[KMByteBlob.cast(keyBlobPtr).length()]; + Util.arrayCopyNonAtomic( + KMByteBlob.cast(keyBlobPtr).getBuffer(), + KMByteBlob.cast(keyBlobPtr).getStartOff(), + keyBlob,(short)0, (short)keyBlob.length); + testAttestKey(keyBlob); + cleanUp(); + } + + @Test + public void testAttestEcKey(){ + init(); + short key = generateEcKey(null,null); + short keyBlobPtr = KMArray.cast(key).get((short)1); + byte[] keyBlob= new byte[KMByteBlob.cast(keyBlobPtr).length()]; + Util.arrayCopyNonAtomic( + KMByteBlob.cast(keyBlobPtr).getBuffer(), + KMByteBlob.cast(keyBlobPtr).getStartOff(), + keyBlob,(short)0, (short)keyBlob.length); + testAttestKey(keyBlob); + cleanUp(); + } + + public void testAttestKey(byte[] keyBlob){ + /* + short key = generateRsaKey(null,null); + short keyBlobPtr = KMArray.cast(key).get((short)1); + byte[] keyBlob= new byte[KMByteBlob.cast(keyBlobPtr).length()]; + Util.arrayCopyNonAtomic( + KMByteBlob.cast(keyBlobPtr).getBuffer(), + KMByteBlob.cast(keyBlobPtr).getStartOff(), + keyBlob,(short)0, (short)keyBlob.length); + */ + short arrPtr = KMArray.instance((short)2); + KMArray.cast(arrPtr).add((short)0, KMByteTag.instance(KMType.ATTESTATION_APPLICATION_ID, + KMByteBlob.instance(attAppId,(short)0,(short)attAppId.length))); + KMArray.cast(arrPtr).add((short)1, KMByteTag.instance(KMType.ATTESTATION_CHALLENGE, + KMByteBlob.instance(attChallenge,(short)0,(short)attChallenge.length))); + short keyParams = KMKeyParameters.instance(arrPtr); + short args = KMArray.instance((short)2); + KMArray.cast(args).add((short)0, KMByteBlob.instance(keyBlob,(short)0,(short)keyBlob.length)); + KMArray.cast(args).add((short)1, keyParams); + CommandAPDU apdu = encodeApdu((byte)INS_ATTEST_KEY_CMD, args); + //print(apdu.getBytes(),(short)0,(short)apdu.getBytes().length); + ResponseAPDU response = simulator.transmitCommand(apdu); + short ret = KMArray.instance((short) 2); + short arrBlobs = KMArray.instance((short)1); + KMArray.cast(arrBlobs).add((short)0, KMByteBlob.exp()); + KMArray.cast(ret).add((short)0, KMInteger.exp()); + KMArray.cast(ret).add((short)1, arrBlobs); + byte[] respBuf = response.getBytes(); + short len = (short) respBuf.length; + //(respBuf,(short)0,(short)respBuf.length); + ret = decoder.decode(ret, respBuf, (short) 0, len); + short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + Assert.assertEquals(error, KMError.OK); + arrBlobs = KMArray.cast(ret).get((short)1); + short cert = KMArray.cast(arrBlobs).get((short)0); + //printCert(KMByteBlob.cast(cert).getBuffer(),KMByteBlob.cast(cert).getStartOff(),KMByteBlob.cast(cert).length()); + } + + @Test + public void testUpgradeKey(){ + init(); + short ret = generateHmacKey(null, null); + short keyBlobPtr = KMArray.cast(ret).get((short)1); + byte[] keyBlob= new byte[KMByteBlob.cast(keyBlobPtr).length()]; + Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), + keyBlob,(short)0, (short)keyBlob.length); + short keyCharacteristics = KMArray.cast(ret).get((short)2); + short hwParams = KMKeyCharacteristics.cast(keyCharacteristics).getHardwareEnforced(); + short swParams = KMKeyCharacteristics.cast(keyCharacteristics).getSoftwareEnforced(); + short osVersion = KMKeyParameters.findTag(KMType.UINT_TAG,KMType.OS_VERSION,hwParams); + osVersion = KMIntegerTag.cast(osVersion).getValue(); + short osPatch = KMKeyParameters.findTag(KMType.UINT_TAG,KMType.OS_PATCH_LEVEL,hwParams); + osPatch = KMIntegerTag.cast(osPatch).getValue(); + Assert.assertEquals(KMInteger.cast(osVersion).getShort(), 1); + Assert.assertEquals(KMInteger.cast(osPatch).getShort(), 1); + setBootParams(simulator,(short) 2,(short)2, (short)1, (short)1); + ret = upgradeKey(KMByteBlob.instance(keyBlob, (short)0, (short)keyBlob.length),null, null); + keyBlobPtr = KMArray.cast(ret).get((short)1); + ret = getKeyCharacteristics(keyBlobPtr); + keyCharacteristics = KMArray.cast(ret).get((short)1); + hwParams = KMKeyCharacteristics.cast(keyCharacteristics).getHardwareEnforced(); + osVersion = KMKeyParameters.findTag(KMType.UINT_TAG,KMType.OS_VERSION,hwParams); + osVersion = KMIntegerTag.cast(osVersion).getValue(); + osPatch = KMKeyParameters.findTag(KMType.UINT_TAG,KMType.OS_PATCH_LEVEL,hwParams); + osPatch = KMIntegerTag.cast(osPatch).getValue(); + Assert.assertEquals(KMInteger.cast(osVersion).getShort(), 2); + Assert.assertEquals(KMInteger.cast(osPatch).getShort(), 2); + cleanUp(); + } + + @Test + public void testDestroyAttIds(){ + init(); + CommandAPDU commandAPDU = new CommandAPDU(0x80, INS_DESTROY_ATT_IDS_CMD, 0x40, 0x00); + ResponseAPDU response = simulator.transmitCommand(commandAPDU); + byte[] respBuf = response.getBytes(); + Assert.assertEquals(respBuf[0], 0); + cleanUp(); + } + + private short upgradeKey(short keyBlobPtr, byte[] clientId, byte[] appData){ + short tagCount = 0; + short clientIdTag = 0; + short appDataTag = 0; + if(clientId != null) tagCount++; + if(appData != null) tagCount++; + short keyParams = KMArray.instance(tagCount); + short tagIndex=0; + if(clientId != null)KMArray.cast(keyBlobPtr).add(tagIndex++, + KMByteTag.instance(KMType.APPLICATION_ID, KMByteBlob.instance(clientId,(short)0,(short)clientId.length))); + if(appData != null)KMArray.cast(keyParams).add(tagIndex++, + KMByteTag.instance(KMType.APPLICATION_DATA, KMByteBlob.instance(appData,(short)0,(short)appData.length))); + keyParams = KMKeyParameters.instance(keyParams); + short arr = KMArray.instance((short)2); + KMArray.cast(arr).add((short)0,keyBlobPtr); + KMArray.cast(arr).add((short)1,keyParams); + CommandAPDU apdu = encodeApdu((byte)INS_UPGRADE_KEY_CMD, arr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + short ret = KMArray.instance((short) 2); + KMArray.cast(ret).add((short) 0, KMInteger.exp()); + KMArray.cast(ret).add((short)1, KMByteBlob.exp()); + byte[] respBuf = response.getBytes(); + short len = (short) respBuf.length; + ret = decoder.decode(ret, respBuf, (short) 0, len); + short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + Assert.assertEquals(error, KMError.OK); + return ret; + } + @Test + public void testSignVerifyWithRsaSHA256PssWithUpdate(){ + init(); + testSignVerifyWithRsa(KMType.SHA2_256, KMType.RSA_PSS,true, true); + cleanUp(); + } + @Test + public void testAbortOperation(){ + init(); + short aesDesKeyArr = generateAesDesKey(KMType.AES, (short)128,null, null, false);; + short keyBlobPtr = KMArray.cast(aesDesKeyArr).get((short)1); + byte[] keyBlob= new byte[KMByteBlob.cast(keyBlobPtr).length()]; + Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), + keyBlob,(short)0, (short)keyBlob.length); + byte[] nonce = new byte[16]; + cryptoProvider.newRandomNumber(nonce,(short)0,(short)16); + short inParams = getAesDesParams(KMType.AES,KMType.ECB, KMType.PKCS7, nonce); + byte[] plainData= "Hello World 123!".getBytes(); + short ret = begin(KMType.ENCRYPT, KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), KMKeyParameters.instance(inParams), (short)0); + short opHandle = KMArray.cast(ret).get((short) 2); + opHandle = KMInteger.cast(opHandle).getShort(); + abort(KMInteger.uint_16(opHandle)); + short dataPtr = KMByteBlob.instance(plainData, (short) 0, (short) plainData.length); + ret = update(KMInteger.uint_16(opHandle), dataPtr, (short) 0, (short) 0, (short) 0); + Assert.assertEquals(KMError.INVALID_OPERATION_HANDLE,ret); + cleanUp(); + } + + public void testEncryptDecryptWithAesDes(byte alg, byte blockMode, byte padding, boolean update){ + short aesDesKeyArr; + boolean aesGcmFlag = false; + if(alg == KMType.AES){ + if(blockMode == KMType.GCM){ + aesDesKeyArr = generateAesGcmKey((short)128,null,null); + aesGcmFlag = true; + } else { + aesDesKeyArr = generateAesDesKey(alg, (short) 128, null, null, false); + } + } else{ + aesDesKeyArr = generateAesDesKey(alg, (short)168,null, null, false); + } + short keyBlobPtr = KMArray.cast(aesDesKeyArr).get((short)1); + byte[] keyBlob= new byte[KMByteBlob.cast(keyBlobPtr).length()]; + Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), + keyBlob,(short)0, (short)keyBlob.length); + byte[] nonce = new byte[16]; + cryptoProvider.newRandomNumber(nonce,(short)0,(short)16); + short inParams = getAesDesParams(alg,blockMode, padding, nonce); + byte[] plainData= "Hello World 123!".getBytes(); + if(update) plainData= "Hello World 123! Hip Hip Hoorah!".getBytes(); + //Encrypt + short ret = processMessage(plainData, + KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), + KMType.ENCRYPT, + KMKeyParameters.instance(inParams), + (short)0,null,update, aesGcmFlag + ); + inParams = getAesDesParams(alg,blockMode, padding, nonce); + keyBlobPtr = KMArray.cast(ret).get((short)2); + //print(keyBlobPtr); + byte[] cipherData = new byte[KMByteBlob.cast(keyBlobPtr).length()]; + Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), + cipherData,(short)0, (short)cipherData.length); + ret = processMessage(cipherData, + KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), + KMType.DECRYPT, + KMKeyParameters.instance(inParams), + (short)0,null,update, aesGcmFlag + ); + keyBlobPtr = KMArray.cast(ret).get((short)2); + //print(plainData,(short)0,(short)plainData.length); + //print(keyBlobPtr); + short equal = Util.arrayCompare(plainData,(short)0,KMByteBlob.cast(keyBlobPtr).getBuffer(), + KMByteBlob.cast(keyBlobPtr).getStartOff(),(short)plainData.length); + Assert.assertTrue(equal == 0); + } + + public void testEncryptDecryptWithRsa(byte digest, byte padding){ + short rsaKeyArr = generateRsaKey(null, null); + short keyBlobPtr = KMArray.cast(rsaKeyArr).get((short)1); + byte[] keyBlob= new byte[KMByteBlob.cast(keyBlobPtr).length()]; + Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), + keyBlob,(short)0, (short)keyBlob.length); + short inParams = getRsaParams(digest, padding); + byte[] plainData = "Hello World 123!".getBytes(); + //Encrypt + short ret = processMessage(plainData, + KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), + KMType.ENCRYPT, + KMKeyParameters.instance(inParams), + (short)0,null,false, false + ); + inParams = getRsaParams(digest, padding); + keyBlobPtr = KMArray.cast(ret).get((short)2); + byte[] cipherData = new byte[KMByteBlob.cast(keyBlobPtr).length()]; + Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), + cipherData,(short)0, (short)cipherData.length); + ret = processMessage(cipherData, + KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), + KMType.DECRYPT, + KMKeyParameters.instance(inParams), + (short)0,null,false,false + ); + keyBlobPtr = KMArray.cast(ret).get((short)2); + short len = KMByteBlob.cast(keyBlobPtr).length(); + short start = KMByteBlob.cast(keyBlobPtr).getStartOff(); + short equal = Util.arrayCompare(plainData,(short)0,KMByteBlob.cast(keyBlobPtr).getBuffer(), + (short)(start+len-plainData.length),(short)plainData.length); + Assert.assertTrue(equal == 0); + } + + public void testSignVerifyWithRsa(byte digest, byte padding, boolean update, boolean verifyFlag){ + short rsaKeyArr = generateRsaKey(null, null); + short keyBlobPtr = KMArray.cast(rsaKeyArr).get((short)1); + byte[] keyBlob= new byte[KMByteBlob.cast(keyBlobPtr).length()]; + Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), + keyBlob,(short)0, (short)keyBlob.length); + short inParams = getRsaParams(digest, padding); + byte[] plainData = "Hello World 123!".getBytes(); + if(update) plainData= "Hello World 123! Hip Hip Hoorah!".getBytes(); + //Sign + short ret = processMessage(plainData, + KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), + KMType.SIGN, + KMKeyParameters.instance(inParams), + (short)0,null,update,false + ); + inParams = getRsaParams(digest, padding); + keyBlobPtr = KMArray.cast(ret).get((short)2); + byte[] signatureData = new byte[KMByteBlob.cast(keyBlobPtr).length()]; + Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), + signatureData,(short)0, (short)signatureData.length); + if(verifyFlag == false) { + Assert.assertEquals(signatureData.length,256); + return; + } + ret = processMessage(plainData, + KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), + KMType.VERIFY, + KMKeyParameters.instance(inParams), + (short)0,signatureData,update,false + ); + short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + Assert.assertEquals(error, KMError.OK); + } + + public void testSignVerifyWithEcdsa(byte digest, boolean update){ + short ecKeyArr = generateEcKey(null, null); + short keyBlobPtr = KMArray.cast(ecKeyArr).get((short)1); + byte[] keyBlob= new byte[KMByteBlob.cast(keyBlobPtr).length()]; + Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), + keyBlob,(short)0, (short)keyBlob.length); + short inParams = getEcParams(digest); + byte[] plainData = "Hello World 123!".getBytes(); + if(update) plainData= "Hello World 123! Hip Hip Hoorah!".getBytes(); + //Sign + short ret = processMessage(plainData, + KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), + KMType.SIGN, + KMKeyParameters.instance(inParams), + (short)0,null,update,false + ); + inParams = getEcParams(digest); + keyBlobPtr = KMArray.cast(ret).get((short)2); + byte[] signatureData = new byte[KMByteBlob.cast(keyBlobPtr).length()]; + Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), + signatureData,(short)0, (short)signatureData.length); + ret = processMessage(plainData, + KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), + KMType.VERIFY, + KMKeyParameters.instance(inParams), + (short)0,signatureData,update,false + ); + short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + Assert.assertEquals(error, KMError.OK); + } + public void testSignVerifyWithHmac(byte digest, boolean update){ + short hmacKeyArr = generateHmacKey(null, null); + short keyBlobPtr = KMArray.cast(hmacKeyArr).get((short)1); + byte[] keyBlob= new byte[KMByteBlob.cast(keyBlobPtr).length()]; + Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), + keyBlob,(short)0, (short)keyBlob.length); + short inParams = getHmacParams(digest,true); + byte[] plainData = "Hello World 123!".getBytes(); + if(update) plainData= "Hello World 123! Hip Hip Hoorah!".getBytes(); + //Sign + short ret = processMessage(plainData, + KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), + KMType.SIGN, + KMKeyParameters.instance(inParams), + (short)0,null,update,false + ); + inParams = getHmacParams(digest,false); + keyBlobPtr = KMArray.cast(ret).get((short)2); + byte[] signatureData = new byte[KMByteBlob.cast(keyBlobPtr).length()]; + Util.arrayCopyNonAtomic(KMByteBlob.cast(keyBlobPtr).getBuffer(), KMByteBlob.cast(keyBlobPtr).getStartOff(), + signatureData,(short)0, (short)signatureData.length); + ret = processMessage(plainData, + KMByteBlob.instance(keyBlob,(short)0, (short)keyBlob.length), + KMType.VERIFY, + KMKeyParameters.instance(inParams), + (short)0,signatureData,update,false + ); + short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + Assert.assertEquals(error, KMError.OK); + } + + private short getAesDesParams(byte alg, byte blockMode, byte padding, byte[] nonce) { + short inParams; + if(blockMode == KMType.GCM){ + inParams = KMArray.instance((short)5); + short byteBlob = KMByteBlob.instance((short)1); + KMByteBlob.cast(byteBlob).add((short)0, blockMode); + KMArray.cast(inParams).add((short)0, KMEnumArrayTag.instance(KMType.BLOCK_MODE, byteBlob)); + byteBlob = KMByteBlob.instance((short)1); + KMByteBlob.cast(byteBlob).add((short)0, padding); + KMArray.cast(inParams).add((short)1, KMEnumArrayTag.instance(KMType.PADDING, byteBlob)); + short nonceLen = 12; + byteBlob = KMByteBlob.instance(nonce,(short)0, nonceLen); + KMArray.cast(inParams).add((short)2, KMByteTag.instance(KMType.NONCE, byteBlob)); + short macLen = KMInteger.uint_16((short)128); + macLen = KMIntegerTag.instance(KMType.UINT_TAG,KMType.MAC_LENGTH,macLen); + KMArray.cast(inParams).add((short)3, macLen); + byte[] authData = "AuthData".getBytes(); + short associatedData = KMByteBlob.instance(authData,(short)0,(short)authData.length); + associatedData = KMByteTag.instance(KMType.ASSOCIATED_DATA,associatedData); + KMArray.cast(inParams).add((short)4, associatedData); + }else if(blockMode == KMType.ECB){ + inParams = KMArray.instance((short)2); + short byteBlob = KMByteBlob.instance((short)1); + KMByteBlob.cast(byteBlob).add((short)0, blockMode); + KMArray.cast(inParams).add((short)0, KMEnumArrayTag.instance(KMType.BLOCK_MODE, byteBlob)); + byteBlob = KMByteBlob.instance((short)1); + KMByteBlob.cast(byteBlob).add((short)0, padding); + KMArray.cast(inParams).add((short)1, KMEnumArrayTag.instance(KMType.PADDING, byteBlob)); + }else{ + inParams = KMArray.instance((short)3); + short byteBlob = KMByteBlob.instance((short)1); + KMByteBlob.cast(byteBlob).add((short)0, blockMode); + KMArray.cast(inParams).add((short)0, KMEnumArrayTag.instance(KMType.BLOCK_MODE, byteBlob)); + byteBlob = KMByteBlob.instance((short)1); + KMByteBlob.cast(byteBlob).add((short)0, padding); + KMArray.cast(inParams).add((short)1, KMEnumArrayTag.instance(KMType.PADDING, byteBlob)); + short nonceLen = 16; + if(alg == KMType.DES) nonceLen = 8; + byteBlob = KMByteBlob.instance(nonce,(short)0, nonceLen); + KMArray.cast(inParams).add((short)2, KMByteTag.instance(KMType.NONCE, byteBlob)); + } + return inParams; + } + + private short getRsaParams(byte digest, byte padding) { + short inParams = KMArray.instance((short)2); + short byteBlob = KMByteBlob.instance((short)1); + KMByteBlob.cast(byteBlob).add((short)0, digest); + KMArray.cast(inParams).add((short)0, KMEnumArrayTag.instance(KMType.DIGEST, byteBlob)); + byteBlob = KMByteBlob.instance((short)1); + KMByteBlob.cast(byteBlob).add((short)0, padding); + KMArray.cast(inParams).add((short)1, KMEnumArrayTag.instance(KMType.PADDING, byteBlob)); + return inParams; + } + + private short getEcParams(byte digest) { + short inParams = KMArray.instance((short)1); + short byteBlob = KMByteBlob.instance((short)1); + KMByteBlob.cast(byteBlob).add((short)0, digest); + KMArray.cast(inParams).add((short)0, KMEnumArrayTag.instance(KMType.DIGEST, byteBlob)); + return inParams; + } + private short getHmacParams(byte digest, boolean sign) { + short paramsize = (short) (sign ? 2 : 1); + short inParams = KMArray.instance((short)paramsize); + short byteBlob = KMByteBlob.instance((short)1); + KMByteBlob.cast(byteBlob).add((short)0, digest); + KMArray.cast(inParams).add((short)0, KMEnumArrayTag.instance(KMType.DIGEST, byteBlob)); + short macLength = KMIntegerTag.instance(KMType.UINT_TAG,KMType.MAC_LENGTH, KMInteger.uint_16((short)/*256*/160)); + if(sign) + KMArray.cast(inParams).add((short)1, macLength); + return inParams; + } + + public short processMessage( + byte[] data, + short keyBlob, + byte keyPurpose, + short inParams, + short hwToken, + byte[] signature, + boolean updateFlag, + boolean aesGcmFlag) { + short beginResp = begin(keyPurpose, keyBlob, inParams, hwToken); + short opHandle = KMArray.cast(beginResp).get((short) 2); + opHandle = KMInteger.cast(opHandle).getShort(); + short dataPtr = KMByteBlob.instance(data, (short) 0, (short) data.length); + short ret = KMType.INVALID_VALUE; + byte[] outputData = new byte[128]; + short len=0; + inParams = 0; + //Test + short firstDataLen =16; + if (keyPurpose == KMType.DECRYPT) { + firstDataLen = 32; + } + + //Test + + if (updateFlag) { + dataPtr = KMByteBlob.instance(data, (short) 0, (short) /*16*/firstDataLen); + if(aesGcmFlag){ + byte[] authData = "AuthData".getBytes(); + short associatedData = KMByteBlob.instance(authData,(short)0,(short)authData.length); + associatedData = KMByteTag.instance(KMType.ASSOCIATED_DATA,associatedData); + inParams = KMArray.instance((short)1); + KMArray.cast(inParams).add((short)0, associatedData); + inParams = KMKeyParameters.instance(inParams); + } + ret = update(KMInteger.uint_16(opHandle), dataPtr, inParams, (short) 0, (short) 0); + dataPtr = KMArray.cast(ret).get((short) 3); + if (KMByteBlob.cast(dataPtr).length() > 0) { + Util.arrayCopyNonAtomic( + KMByteBlob.cast(dataPtr).getBuffer(), + KMByteBlob.cast(dataPtr).getStartOff(), + outputData, + (short) 0, + KMByteBlob.cast(dataPtr).length()); + len = KMByteBlob.cast(dataPtr).length(); + dataPtr = KMByteBlob.instance(data, len, (short) (data.length - len)); + }else{ + dataPtr = KMByteBlob.instance(data, (short)/*16*/firstDataLen, (short) (data.length - /*16*/firstDataLen)); + } + } + + if (keyPurpose == KMType.VERIFY) { + ret = finish(KMInteger.uint_16(opHandle), dataPtr, signature, (short) 0, (short) 0, (short) 0); + } else { + ret = finish(KMInteger.uint_16(opHandle), dataPtr, null, (short) 0, (short) 0, (short) 0); + } + if(len >0){ + dataPtr = KMArray.cast(ret).get((short)2); + if(KMByteBlob.cast(dataPtr).length() >0){ + Util.arrayCopyNonAtomic( + KMByteBlob.cast(dataPtr).getBuffer(), + KMByteBlob.cast(dataPtr).getStartOff(), + outputData, + len, + KMByteBlob.cast(dataPtr).length()); + len = (short)(len + KMByteBlob.cast(dataPtr).length()); + } + KMArray.cast(ret).add((short)2, KMByteBlob.instance(outputData,(short)0,len)); + } + return ret; + } + + public short begin(byte keyPurpose, short keyBlob, short keyParmas, short hwToken) { + short arrPtr = KMArray.instance((short)4); + KMArray.cast(arrPtr).add((short)0, KMEnum.instance(KMType.PURPOSE, keyPurpose)); + KMArray.cast(arrPtr).add((short)1, keyBlob); + KMArray.cast(arrPtr).add((short)2, keyParmas); + if(hwToken == 0) { + hwToken = KMHardwareAuthToken.instance(); + } + KMArray.cast(arrPtr).add((short)3, hwToken); + CommandAPDU apdu = encodeApdu((byte)INS_BEGIN_OPERATION_CMD, arrPtr); + //print(apdu.getBytes(),(short)0,(short)apdu.getBytes().length); + ResponseAPDU response = simulator.transmitCommand(apdu); + short ret = KMArray.instance((short) 3); + short outParams = KMKeyParameters.exp(); + KMArray.cast(ret).add((short)0, KMInteger.exp()); + KMArray.cast(ret).add((short)1, outParams); + KMArray.cast(ret).add((short)2, KMInteger.exp()); + byte[] respBuf = response.getBytes(); + short len = (short) respBuf.length; + if(len > 5){ + ret = decoder.decode(ret, respBuf, (short) 0, len); + short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + Assert.assertEquals(error, KMError.OK); + return ret;}else{ + if(len == 3) return respBuf[0]; + if(len == 4) return respBuf[1]; + return Util.getShort(respBuf,(short)0); + } + } + + public short finish(short operationHandle, short data, byte[] signature, short inParams, short hwToken, short verToken) { + if(hwToken == 0) { + hwToken = KMHardwareAuthToken.instance(); + } + if(verToken == 0){ + verToken = KMVerificationToken.instance(); + } + short signatureTag; + if(signature == null){ + signatureTag = KMByteBlob.instance((short)0); + }else{ + signatureTag = KMByteBlob.instance(signature,(short)0,(short)signature.length); + } + if(inParams == 0){ + short arr = KMArray.instance((short)0); + inParams = KMKeyParameters.instance(arr); + } + short arrPtr = KMArray.instance((short)6); + KMArray.cast(arrPtr).add((short)0, operationHandle); + KMArray.cast(arrPtr).add((short)1, inParams); + KMArray.cast(arrPtr).add((short)2, data); + KMArray.cast(arrPtr).add((short)3, signatureTag); + KMArray.cast(arrPtr).add((short)4, hwToken); + KMArray.cast(arrPtr).add((short)5, verToken); + CommandAPDU apdu = encodeApdu((byte)INS_FINISH_OPERATION_CMD, arrPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + short ret = KMArray.instance((short) 3); + short outParams = KMKeyParameters.exp(); + KMArray.cast(ret).add((short)0, KMInteger.exp()); + KMArray.cast(ret).add((short)1, outParams); + KMArray.cast(ret).add((short)2, KMByteBlob.exp()); + byte[] respBuf = response.getBytes(); + short len = (short) respBuf.length; + ret = decoder.decode(ret, respBuf, (short) 0, len); + short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + Assert.assertEquals(error, KMError.OK); + return ret; + } + public short update(short operationHandle, short data, short inParams, short hwToken, short verToken) { + if(hwToken == 0) { + hwToken = KMHardwareAuthToken.instance(); + } + if(verToken == 0){ + verToken = KMVerificationToken.instance(); + } + if(inParams == 0){ + short arr = KMArray.instance((short)0); + inParams = KMKeyParameters.instance(arr); + } + short arrPtr = KMArray.instance((short)5); + KMArray.cast(arrPtr).add((short)0, operationHandle); + KMArray.cast(arrPtr).add((short)1, inParams); + KMArray.cast(arrPtr).add((short)2, data); + KMArray.cast(arrPtr).add((short)3, hwToken); + KMArray.cast(arrPtr).add((short)4, verToken); + CommandAPDU apdu = encodeApdu((byte)INS_UPDATE_OPERATION_CMD, arrPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + short ret = KMArray.instance((short) 4); + short outParams = KMKeyParameters.exp(); + KMArray.cast(ret).add((short)0, KMInteger.exp()); + KMArray.cast(ret).add((short)1, KMInteger.exp()); + KMArray.cast(ret).add((short)2, outParams); + KMArray.cast(ret).add((short)3, KMByteBlob.exp()); + byte[] respBuf = response.getBytes(); + short len = (short) respBuf.length; + if (len > 5) { + ret = decoder.decode(ret, respBuf, (short) 0, len); + short error = KMInteger.cast(KMArray.cast(ret).get((short) 0)).getShort(); + Assert.assertEquals(error, KMError.OK); + }else{ + ret = respBuf[1]; + } + return ret; + } + + private void print(short blob){ + print(KMByteBlob.cast(blob).getBuffer(),KMByteBlob.cast(blob).getStartOff(),KMByteBlob.cast(blob).length()); + } + private void print(byte[] buf, short start, short length){ + StringBuilder sb = new StringBuilder(); + for(int i = start; i < (start+length); i++){ + sb.append(String.format(" 0x%02X", buf[i])) ; + } + System.out.println(sb.toString()); + } + private void printCert(byte[] buf, short start, short length){ + StringBuilder sb = new StringBuilder(); + for(int i = start; i < (start+length); i++){ + sb.append(String.format("%02X", buf[i])) ; + } + System.out.println(sb.toString()); + } + + +/* + @Test + public void testApdu(){ + init(); + byte[] cmd = {(byte)0x80,0x11,0x40,0x00,0x00,0x00,0x4C,(byte)0x83,(byte)0xA5,0x1A,0x70,0x00,0x01,(byte)0xF7,0x01,0x1A,0x10, + 0x00,0x00,0x02,0x03,0x1A,0x30,0x00,0x00,0x03,0x19,0x01,0x00,0x1A,0x20,0x00,0x00,0x01,0x42,0x02, + 0x03,0x1A,0x20,0x00,0x00,0x05,0x41,0x04,0x03,0x58,0x24,(byte)0x82,0x58,0x20,0x73,0x7C,0x2E,(byte)0xCD, + 0x7B,(byte)0x8D,0x19,0x40,(byte)0xBF,0x29,0x30,(byte)0xAA,(byte)0x9B,0x4E, + (byte)0xD3,(byte)0xFF,(byte)0x94,0x1E,(byte)0xED,0x09,0x36,0x6B, + (byte)0xC0,0x32,(byte)0x99,(byte)0x98,0x64,(byte)0x81,(byte)0xF3,(byte)0xA4,(byte)0xD8,0x59,0x40}; + CommandAPDU cmdApdu = new CommandAPDU(cmd); + ResponseAPDU resp = simulator.transmitCommand(cmdApdu); + short ret = KMArray.instance((short) 3); + KMArray.cast(ret).add((short) 0, KMInteger.exp()); + KMArray.cast(ret).add((short)1, KMByteBlob.exp()); + short inst = KMKeyCharacteristics.exp(); + KMArray.cast(ret).add((short) 2, inst); + byte[] respBuf = resp.getBytes(); + short len = (short) respBuf.length; + ret = decoder.decode(ret, respBuf, (short) 0, len); + short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + short keyBlobLength = KMByteBlob.cast(KMArray.cast(ret).get((short)1)).length(); + short blobArr = extractKeyBlobArray(KMArray.cast(ret).get((short)1)); + short keyCharacteristics = KMArray.cast(ret).get((short)2); + short hwParams = KMKeyCharacteristics.cast(keyCharacteristics).getHardwareEnforced(); + short swParams = KMKeyCharacteristics.cast(keyCharacteristics).getSoftwareEnforced(); + cleanUp(); + } + */ +} diff --git a/Applet/JavaCardKeymaster.scr b/Applet/JavaCardKeymaster.scr deleted file mode 100644 index 6380faa2..00000000 --- a/Applet/JavaCardKeymaster.scr +++ /dev/null @@ -1,50 +0,0 @@ -output on; - -//create applet instance -0x80 0xB8 0x00 0x00 0x0c 0x0a 0xa0 0x00 0x00 0x00 0x62 0x03 0x01 0xc 0x01 0x01 0x00 0x7F; - -// Select JavaCardKeymaster //aid/A000000062/03010C0101 - 0x00 0xa4 0x04 0x00 0x0a 0xa0 0x00 0x00 0x00 0x62 0x03 0x01 0xc 0x01 0x01 0x7F; - -// Send provision command - this will change in future - 0x80 0x23 0x40 0x00 0x3B 0x83 0xA1 0x1A 0x10 0x00 0x00 0x02 0x01 0x00 0x58 0x30 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F 0x7F; - -// Send Set Boot Params command - 0x80 0x24 0x40 0x00 0x49 0x86 0x01 0x01 0x58 0x20 0x30 0x30 0x30 0x31 0x31 0x31 0x32 0x32 0x32 0x33 0x33 0x33 0x34 0x34 0x34 0x35 0x35 0x35 0x36 0x36 0x36 0x37 0x37 0x37 0x38 0x38 0x38 0x39 0x39 0x39 0x30 0x30 0x58 0x20 0x30 0x30 0x30 0x31 0x31 0x31 0x32 0x32 0x32 0x33 0x33 0x33 0x34 0x34 0x34 0x35 0x35 0x35 0x36 0x36 0x36 0x37 0x37 0x37 0x38 0x38 0x38 0x39 0x39 0x39 0x30 0x30 0x02 0x00 0x7F; - -// Send getHardwareInfo command - 0x80 0x1E 0x40 0x00 0x00 0x7F; - -// Send AddRngEntropy command - 0x80 0x18 0x40 0x00 0x23 0x81 0x58 0x20 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x7F; - -// Generate Key - RSA Key command - 0x80 0x10 0x40 0x00 0x22 0x81 0xA4 0x1A 0x10 0x00 0x00 0x02 0x01 0x1A 0x30 0x00 0x00 0x03 0x19 0x08 0x00 0x1A 0x50 0x00 0x00 0xC8 0x1A 0x00 0x01 0x00 0x01 0x1A 0x20 0x00 0x00 0x01 0x42 0x02 0x03 0x7F; - -// Generate Key - AES Key command - 0x80 0x10 0x40 0x00 0x23 0x81 0xA4 0x1A 0x10 0x00 0x00 0x02 0x18 0x20 0x1A 0x30 0x00 0x00 0x03 0x19 0x01 0x00 0x1A 0x50 0x00 0x00 0xC8 0x1A 0x00 0x01 0x00 0x01 0x1A 0x20 0x00 0x00 0x01 0x42 0x02 0x03 0x7F; - -// Generate Key - ECC Key command - 0x80 0x10 0x40 0x00 0x22 0x81 0xA4 0x1A 0x10 0x00 0x00 0x02 0x03 0x1A 0x30 0x00 0x00 0x03 0x19 0x01 0x00 0x1A 0x50 0x00 0x00 0xC8 0x1A 0x00 0x01 0x00 0x01 0x1A 0x20 0x00 0x00 0x01 0x42 0x02 0x03 0x7F; - -// Generate Key - DES Key command - 0x80 0x10 0x40 0x00 0x22 0x81 0xA4 0x1A 0x10 0x00 0x00 0x02 0x18 0x21 0x1A 0x30 0x00 0x00 0x03 0x18 0xA8 0x1A 0x50 0x00 0x00 0xC8 0x1A 0x00 0x01 0x00 0x01 0x1A 0x20 0x00 0x00 0x01 0x42 0x02 0x03 0x7F; - -// Generate Key - HMAC Key command - 0x80 0x10 0x40 0x00 0x32 0x81 0xA6 0x1A 0x10 0x00 0x00 0x02 0x18 0x80 0x1A 0x30 0x00 0x01 0xF5 0x1A 0x01 0x02 0x03 0x04 0x1A 0x90 0x00 0x02 0x59 0x44 0x54 0x65 0x73 0x74 0x1A 0x30 0x00 0x00 0x08 0x18 0x80 0x1A 0x30 0x00 0x00 0x03 0x18 0x80 0x1A 0x20 0x00 0x00 0x05 0x41 0x04 0x7F; - -// Import RSA Key - 0x80 0x11 0x40 0x00 0xB4 0x83 0xA5 0x1A 0x10 0x00 0x00 0x02 0x01 0x1A 0x30 0x00 0x01 0xF5 0x1A 0x01 0x02 0x03 0x04 0x1A 0x90 0x00 0x02 0x59 0x44 0x54 0x65 0x73 0x74 0x1A 0x50 0x00 0x00 0xC8 0x1A 0x00 0x01 0x00 0x01 0x1A 0x70 0x00 0x01 0xF7 0x01 0x03 0x58 0x85 0x82 0x58 0x40 0x80 0x9A 0x87 0x4C 0xE1 0xA0 0x71 0x44 0xAE 0x45 0xDD 0x8D 0x1C 0x05 0xB4 0xD0 0x44 0x23 0xDD 0x42 0xA7 0xC9 0x53 0x44 0xAC 0x31 0x4A 0x22 0x4A 0x02 0x65 0xA0 0xAA 0x21 0xA8 0x30 0x94 0x7D 0x13 0xA1 0xBC 0x89 0x81 0xB5 0x54 0xDE 0x75 0x82 0xB9 0x0B 0x1A 0x7A 0x81 0x0C 0x51 0xE0 0x2F 0x91 0x97 0xD4 0xE8 0x33 0x27 0x61 0x58 0x40 0x92 0x6C 0x79 0x17 0xBB 0x36 0x6F 0xB7 0x58 0x25 0x84 0x98 0xA9 0x56 0x07 0xE6 0x07 0xF6 0x26 0x92 0x15 0xF6 0x21 0x9F 0x6C 0xF0 0xB4 0xE7 0x20 0x42 0xAC 0xB6 0xD8 0x30 0x61 0x06 0xC9 0x3B 0x30 0x67 0x1E 0x8D 0x74 0x11 0x8B 0x06 0x98 0xAB 0x8D 0x6A 0x6C 0xCD 0xB7 0x2F 0xC3 0xA8 0x30 0xC7 0x68 0x03 0x4F 0x72 0xC7 0x5B 0x7F; - -// Import EC Key - 0x80 0x11 0x40 0x00 0x7D 0x83 0xA4 0x1A 0x10 0x00 0x00 0x02 0x03 0x1A 0x30 0x00 0x01 0xF5 0x1A 0x01 0x02 0x03 0x04 0x1A 0x90 0x00 0x02 0x59 0x44 0x54 0x65 0x73 0x74 0x1A 0x50 0x00 0x00 0xC8 0x1A 0x00 0x01 0x00 0x01 0x03 0x58 0x54 0x83 0x58 0x18 0xA6 0x68 0xDE 0xEC 0x65 0x6C 0xFB 0xEE 0xAA 0x43 0xEF 0x97 0x9D 0x10 0x82 0xF0 0x99 0x5F 0x10 0xF3 0xEE 0x9C 0x38 0x57 0x58 0x31 0x04 0x3A 0xF8 0xF4 0xFA 0x1F 0xE4 0x4D 0x62 0xA1 0xCD 0x26 0x8E 0x1A 0x5A 0xAA 0xF5 0xA8 0x94 0xE3 0x8B 0x4C 0xCE 0x49 0xA1 0x57 0x25 0x81 0x6D 0xBE 0x5C 0x3B 0x07 0x95 0xB6 0x89 0x24 0x6E 0x9D 0x25 0x22 0xE6 0x5F 0x41 0xCC 0x59 0xCE 0x25 0x0C 0x1A 0x10 0x00 0x00 0x0A 0x01 0x7F; - -// Import AES Key - 0x80 0x11 0x40 0x00 0x3F 0x83 0xA5 0x1A 0x10 0x00 0x00 0x02 0x18 0x20 0x1A 0x30 0x00 0x01 0xF5 0x1A 0x01 0x02 0x03 0x04 0x1A 0x90 0x00 0x02 0x59 0x44 0x54 0x65 0x73 0x74 0x1A 0x30 0x00 0x00 0x03 0x18 0x80 0x1A 0x20 0x00 0x00 0x05 0x41 0x04 0x03 0x52 0x81 0x50 0x95 0xE6 0x79 0x36 0x64 0xA5 0xEC 0x72 0xBF 0x01 0x4C 0x83 0x6C 0xCD 0xCF 0x51 0x7F; - -// Import Hmac Key - 0x80 0x11 0x40 0x00 0x46 0x83 0xA6 0x1A 0x10 0x00 0x00 0x02 0x18 0x80 0x1A 0x30 0x00 0x01 0xF5 0x1A 0x01 0x02 0x03 0x04 0x1A 0x90 0x00 0x02 0x59 0x44 0x54 0x65 0x73 0x74 0x1A 0x30 0x00 0x00 0x03 0x18 0x80 0x1A 0x20 0x00 0x00 0x05 0x41 0x04 0x1A 0x30 0x00 0x00 0x08 0x18 0x80 0x03 0x52 0x81 0x50 0xFC 0xA6 0x8F 0x58 0x68 0x93 0xDE 0xD0 0xC0 0x74 0x1C 0x6F 0x1D 0x39 0x2E 0x4A 0x7F; - -// Import Des Key - 0x80 0x11 0x40 0x00 0x3F 0x83 0xA5 0x1A 0x10 0x00 0x00 0x02 0x18 0x21 0x1A 0x30 0x00 0x01 0xF5 0x1A 0x01 0x02 0x03 0x04 0x1A 0x90 0x00 0x02 0x59 0x44 0x54 0x65 0x73 0x74 0x1A 0x30 0x00 0x00 0x03 0x18 0xA8 0x1A 0x20 0x00 0x00 0x05 0x41 0x04 0x03 0x52 0x81 0x50 0x8B 0xD4 0xD5 0x84 0x37 0x39 0xC0 0x1B 0xDB 0xED 0x3C 0x68 0x99 0x3A 0xDC 0x3D 0x7F; - diff --git a/Applet/README.md b/Applet/README.md index 5cc80048..9d592fd2 100644 --- a/Applet/README.md +++ b/Applet/README.md @@ -1,6 +1,6 @@ -# JavaCardKeymaster Applet - -This directory contains the implementation of the Keymaster 4.1 -interface, in the form of a JavaCard 3.1 applet which runs in a secure -element. It must be deployed in conjuction with the associated HAL, -which serves to intermediate between Android Keystore and this applet. +# JavaCardKeymaster Applet + +This directory contains the implementation of the Keymaster 4.1 +interface, in the form of a JavaCard 3.1 applet which runs in a secure +element. It must be deployed in conjuction with the associated HAL, +which serves to intermediate between Android Keystore and this applet. diff --git a/Applet/api_export_files_3.0.5/javacardx/framework/util/intx/javacard/intx.exp b/Applet/api_export_files_3.0.5/javacardx/framework/util/intx/javacard/intx.exp deleted file mode 100644 index ed00a3956fa9bdda80e435ec91f4b31a3efe62c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 339 zcmaKkJyOFk5QX2`i4_BZ07F4RMI%=_02QV(!wiL~NVN$fgo;&Q zQc$4gTfIMgeSD?~jtOeX3tPD$moDWM6``-|Ix?Htu(2{dE`OBnS5Z-^ikff|2ktz( zuCXr0FTLkCDeJl{#&N|yuej|bsc+`|!lq?6Gq;nuora6zo^T%3Df@@DdGx%ruTOqq zR-tK40g>NirZJC_UqA2ajXI~1) afK!2#B9cUqqL&K#$a=`3Fc4dg9r^|h>PuDt diff --git a/Applet/api_export_files_3.1.0/java/io/javacard/io.exp b/Applet/api_export_files_3.1.0/java/io/javacard/io.exp deleted file mode 100644 index 36b9d18b5de6cc36a93aec729d6767375ab34682..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 242 zcmZ9FOA5k35JampnlWlLAl@NatgSu$w zuBv{8$L-D>1O#`iv??bA7Dh{Z%H2^E2f{F%=i(&dLg;mzq`Az>QM4iqDpi?ymP{|1 z+?L8{js_w4k8`-6cm-K(_U0_oLUOczj4w``z~2Qvp$p=Qs} Sf`P+B$G*UMDbFnym*~@|T!-5kj?jJz+D}_Lx6v_XZR0 z%G1^(LV11HhBQJ&?cR^W;FS$LZbSB8a5;DRvlM}ELk^*)D(+%miYeFfJi@WculymO z_hQ+5x(H%_7-_JG&{VJ!hHPQb8we*#-|!KWV#ZfheetGWpp4MaWbApjf$${{wX?So z4wdP8EQ-1;lA72-I8ve$3OSx~DO`>0BGeV>b2lcn(7^s$4|-u=2BCi08iMoJqeQm? zwBG?>08|S_pkIcT^re>b)j*nCh_tkSZJGNl-%v4=9FeM-I7If$Bv0hPObSHmX7UYVIh)D= diff --git a/Applet/api_export_files_3.1.0/java/rmi/javacard/rmi.exp b/Applet/api_export_files_3.1.0/java/rmi/javacard/rmi.exp deleted file mode 100644 index 8c6952376e8ecb8638c21dc6ea152906f094fc24..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 337 zcmZ9IOAY}+5QhKiK^u(MAdbLl4nXWIBoc{;g*o(ld$i=uLI~ zUse5;!t?&H7+QqNMx2Fr*eY)-w>pv>AXF1E5aG(3_#3&5I2a+ZxQA&k=VnIr&zH3EEYFda80}n3~VqNplPg(4D5^y PY>YrABLg!~IS>E - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - + + + - - + + + + \ No newline at end of file diff --git a/Applet/default.output b/Applet/default.output deleted file mode 100644 index 6e4f103f..00000000 --- a/Applet/default.output +++ /dev/null @@ -1,20 +0,0 @@ -CLA: 00, INS: a4, P1: 04, P2: 00, Lc: 09, a0, 00, 00, 00, 62, 03, 01, 08, 01, Le: 00, SW1: 90, SW2: 00 -CAP file download section. Output suppressed. -OUTPUT OFF; -OUTPUT ON; -CLA: 80, INS: b8, P1: 00, P2: 00, Lc: 0c, 0a, a0, 00, 00, 00, 62, 03, 01, 0c, 01, 01, 00, Le: 0a, a0, 00, 00, 00, 62, 03, 01, 0c, 01, 01, SW1: 90, SW2: 00 -CLA: 00, INS: a4, P1: 04, P2: 00, Lc: 0a, a0, 00, 00, 00, 62, 03, 01, 0c, 01, 01, Le: 00, SW1: 90, SW2: 00 -CLA: 80, INS: 23, P1: 40, P2: 00, Lc: 3b, 83, a1, 1a, 10, 00, 00, 02, 01, 00, 58, 30, 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 1a, 1b, 1c, 1d, 1e, 1f, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 2a, 2b, 2c, 2d, 2e, 2f, Le: 00, SW1: 69, SW2: 85 -CLA: 80, INS: 24, P1: 40, P2: 00, Lc: 49, 86, 01, 01, 58, 20, 30, 30, 30, 31, 31, 31, 32, 32, 32, 33, 33, 33, 34, 34, 34, 35, 35, 35, 36, 36, 36, 37, 37, 37, 38, 38, 38, 39, 39, 39, 30, 30, 58, 20, 30, 30, 30, 31, 31, 31, 32, 32, 32, 33, 33, 33, 34, 34, 34, 35, 35, 35, 36, 36, 36, 37, 37, 37, 38, 38, 38, 39, 39, 39, 30, 30, 02, 00, Le: 00, SW1: 90, SW2: 00 -CLA: 80, INS: 1e, P1: 40, P2: 00, Lc: 00, Le: 00, SW1: 69, SW2: 86 -CLA: 80, INS: 18, P1: 40, P2: 00, Lc: 23, 81, 58, 20, 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 1a, 1b, 1c, 1d, 1e, 1f, Le: 00, SW1: 69, SW2: 86 -CLA: 80, INS: 10, P1: 40, P2: 00, Lc: 22, 81, a4, 1a, 10, 00, 00, 02, 01, 1a, 30, 00, 00, 03, 19, 08, 00, 1a, 50, 00, 00, c8, 1a, 00, 01, 00, 01, 1a, 20, 00, 00, 01, 42, 02, 03, Le: 00, SW1: 69, SW2: 86 -CLA: 80, INS: 10, P1: 40, P2: 00, Lc: 23, 81, a4, 1a, 10, 00, 00, 02, 18, 20, 1a, 30, 00, 00, 03, 19, 01, 00, 1a, 50, 00, 00, c8, 1a, 00, 01, 00, 01, 1a, 20, 00, 00, 01, 42, 02, 03, Le: 00, SW1: 69, SW2: 86 -CLA: 80, INS: 10, P1: 40, P2: 00, Lc: 22, 81, a4, 1a, 10, 00, 00, 02, 03, 1a, 30, 00, 00, 03, 19, 01, 00, 1a, 50, 00, 00, c8, 1a, 00, 01, 00, 01, 1a, 20, 00, 00, 01, 42, 02, 03, Le: 00, SW1: 69, SW2: 86 -CLA: 80, INS: 10, P1: 40, P2: 00, Lc: 22, 81, a4, 1a, 10, 00, 00, 02, 18, 21, 1a, 30, 00, 00, 03, 18, a8, 1a, 50, 00, 00, c8, 1a, 00, 01, 00, 01, 1a, 20, 00, 00, 01, 42, 02, 03, Le: 00, SW1: 69, SW2: 86 -CLA: 80, INS: 10, P1: 40, P2: 00, Lc: 32, 81, a6, 1a, 10, 00, 00, 02, 18, 80, 1a, 30, 00, 01, f5, 1a, 01, 02, 03, 04, 1a, 90, 00, 02, 59, 44, 54, 65, 73, 74, 1a, 30, 00, 00, 08, 18, 80, 1a, 30, 00, 00, 03, 18, 80, 1a, 20, 00, 00, 05, 41, 04, Le: 00, SW1: 69, SW2: 85 -CLA: 80, INS: 11, P1: 40, P2: 00, Lc: b4, 83, a5, 1a, 10, 00, 00, 02, 01, 1a, 30, 00, 01, f5, 1a, 01, 02, 03, 04, 1a, 90, 00, 02, 59, 44, 54, 65, 73, 74, 1a, 50, 00, 00, c8, 1a, 00, 01, 00, 01, 1a, 70, 00, 01, f7, 01, 03, 58, 85, 82, 58, 40, 80, 9a, 87, 4c, e1, a0, 71, 44, ae, 45, dd, 8d, 1c, 05, b4, d0, 44, 23, dd, 42, a7, c9, 53, 44, ac, 31, 4a, 22, 4a, 02, 65, a0, aa, 21, a8, 30, 94, 7d, 13, a1, bc, 89, 81, b5, 54, de, 75, 82, b9, 0b, 1a, 7a, 81, 0c, 51, e0, 2f, 91, 97, d4, e8, 33, 27, 61, 58, 40, 92, 6c, 79, 17, bb, 36, 6f, b7, 58, 25, 84, 98, a9, 56, 07, e6, 07, f6, 26, 92, 15, f6, 21, 9f, 6c, f0, b4, e7, 20, 42, ac, b6, d8, 30, 61, 06, c9, 3b, 30, 67, 1e, 8d, 74, 11, 8b, 06, 98, ab, 8d, 6a, 6c, cd, b7, 2f, c3, a8, 30, c7, 68, 03, 4f, 72, c7, 5b, Le: 00, SW1: 69, SW2: 85 -CLA: 80, INS: 11, P1: 40, P2: 00, Lc: 7d, 83, a4, 1a, 10, 00, 00, 02, 03, 1a, 30, 00, 01, f5, 1a, 01, 02, 03, 04, 1a, 90, 00, 02, 59, 44, 54, 65, 73, 74, 1a, 50, 00, 00, c8, 1a, 00, 01, 00, 01, 03, 58, 54, 83, 58, 18, a6, 68, de, ec, 65, 6c, fb, ee, aa, 43, ef, 97, 9d, 10, 82, f0, 99, 5f, 10, f3, ee, 9c, 38, 57, 58, 31, 04, 3a, f8, f4, fa, 1f, e4, 4d, 62, a1, cd, 26, 8e, 1a, 5a, aa, f5, a8, 94, e3, 8b, 4c, ce, 49, a1, 57, 25, 81, 6d, be, 5c, 3b, 07, 95, b6, 89, 24, 6e, 9d, 25, 22, e6, 5f, 41, cc, 59, ce, 25, 0c, 1a, 10, 00, 00, 0a, 01, Le: 00, SW1: 69, SW2: 85 -CLA: 80, INS: 11, P1: 40, P2: 00, Lc: 3f, 83, a5, 1a, 10, 00, 00, 02, 18, 20, 1a, 30, 00, 01, f5, 1a, 01, 02, 03, 04, 1a, 90, 00, 02, 59, 44, 54, 65, 73, 74, 1a, 30, 00, 00, 03, 18, 80, 1a, 20, 00, 00, 05, 41, 04, 03, 52, 81, 50, 95, e6, 79, 36, 64, a5, ec, 72, bf, 01, 4c, 83, 6c, cd, cf, 51, Le: 00, SW1: 69, SW2: 85 -CLA: 80, INS: 11, P1: 40, P2: 00, Lc: 46, 83, a6, 1a, 10, 00, 00, 02, 18, 80, 1a, 30, 00, 01, f5, 1a, 01, 02, 03, 04, 1a, 90, 00, 02, 59, 44, 54, 65, 73, 74, 1a, 30, 00, 00, 03, 18, 80, 1a, 20, 00, 00, 05, 41, 04, 1a, 30, 00, 00, 08, 18, 80, 03, 52, 81, 50, fc, a6, 8f, 58, 68, 93, de, d0, c0, 74, 1c, 6f, 1d, 39, 2e, 4a, Le: 00, SW1: 69, SW2: 85 -CLA: 80, INS: 11, P1: 40, P2: 00, Lc: 3f, 83, a5, 1a, 10, 00, 00, 02, 18, 21, 1a, 30, 00, 01, f5, 1a, 01, 02, 03, 04, 1a, 90, 00, 02, 59, 44, 54, 65, 73, 74, 1a, 30, 00, 00, 03, 18, a8, 1a, 20, 00, 00, 05, 41, 04, 03, 52, 81, 50, 8b, d4, d5, 84, 37, 39, c0, 1b, db, ed, 3c, 68, 99, 3a, dc, 3d, Le: 00, SW1: 69, SW2: 85 diff --git a/Applet/powerdown.scr b/Applet/powerdown.scr deleted file mode 100644 index 7dca615e..00000000 --- a/Applet/powerdown.scr +++ /dev/null @@ -1,4 +0,0 @@ - -// output on; - -powerdown; \ No newline at end of file diff --git a/Applet/powerup.scr b/Applet/powerup.scr deleted file mode 100644 index 79990dc4..00000000 --- a/Applet/powerup.scr +++ /dev/null @@ -1,9 +0,0 @@ -powerup; - -// Select the installer applet -0x00 0xA4 0x04 0x00 0x09 0xA0 0x00 0x00 0x00 0x62 0x03 0x01 0x08 0x01 0x7F; - -// Turn output off during CAP file download -echo "CAP file download section. Output suppressed."; - -output off; diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMArray.java b/Applet/src/com/android/javacard/keymaster/KMArray.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMArray.java rename to Applet/src/com/android/javacard/keymaster/KMArray.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java b/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java rename to Applet/src/com/android/javacard/keymaster/KMAttestationCert.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMBoolTag.java b/Applet/src/com/android/javacard/keymaster/KMBoolTag.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMBoolTag.java rename to Applet/src/com/android/javacard/keymaster/KMBoolTag.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMByteBlob.java b/Applet/src/com/android/javacard/keymaster/KMByteBlob.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMByteBlob.java rename to Applet/src/com/android/javacard/keymaster/KMByteBlob.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMByteTag.java b/Applet/src/com/android/javacard/keymaster/KMByteTag.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMByteTag.java rename to Applet/src/com/android/javacard/keymaster/KMByteTag.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMDecoder.java b/Applet/src/com/android/javacard/keymaster/KMDecoder.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMDecoder.java rename to Applet/src/com/android/javacard/keymaster/KMDecoder.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMEncoder.java b/Applet/src/com/android/javacard/keymaster/KMEncoder.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMEncoder.java rename to Applet/src/com/android/javacard/keymaster/KMEncoder.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMEnum.java b/Applet/src/com/android/javacard/keymaster/KMEnum.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMEnum.java rename to Applet/src/com/android/javacard/keymaster/KMEnum.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMEnumArrayTag.java b/Applet/src/com/android/javacard/keymaster/KMEnumArrayTag.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMEnumArrayTag.java rename to Applet/src/com/android/javacard/keymaster/KMEnumArrayTag.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMEnumTag.java b/Applet/src/com/android/javacard/keymaster/KMEnumTag.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMEnumTag.java rename to Applet/src/com/android/javacard/keymaster/KMEnumTag.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMError.java b/Applet/src/com/android/javacard/keymaster/KMError.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMError.java rename to Applet/src/com/android/javacard/keymaster/KMError.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMException.java b/Applet/src/com/android/javacard/keymaster/KMException.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMException.java rename to Applet/src/com/android/javacard/keymaster/KMException.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMHardwareAuthToken.java b/Applet/src/com/android/javacard/keymaster/KMHardwareAuthToken.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMHardwareAuthToken.java rename to Applet/src/com/android/javacard/keymaster/KMHardwareAuthToken.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMHmacSharingParameters.java b/Applet/src/com/android/javacard/keymaster/KMHmacSharingParameters.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMHmacSharingParameters.java rename to Applet/src/com/android/javacard/keymaster/KMHmacSharingParameters.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMInteger.java b/Applet/src/com/android/javacard/keymaster/KMInteger.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMInteger.java rename to Applet/src/com/android/javacard/keymaster/KMInteger.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMIntegerArrayTag.java b/Applet/src/com/android/javacard/keymaster/KMIntegerArrayTag.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMIntegerArrayTag.java rename to Applet/src/com/android/javacard/keymaster/KMIntegerArrayTag.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMIntegerTag.java b/Applet/src/com/android/javacard/keymaster/KMIntegerTag.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMIntegerTag.java rename to Applet/src/com/android/javacard/keymaster/KMIntegerTag.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeyCharacteristics.java b/Applet/src/com/android/javacard/keymaster/KMKeyCharacteristics.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMKeyCharacteristics.java rename to Applet/src/com/android/javacard/keymaster/KMKeyCharacteristics.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java b/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java rename to Applet/src/com/android/javacard/keymaster/KMKeyParameters.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java similarity index 99% rename from Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java rename to Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index cde5de0a..76c97b0e 100644 --- a/Applet/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -32,7 +32,7 @@ * objects. It also implements the keymaster state machine and handles javacard applet life cycle * events. */ -public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLength, OnUpgradeListener { +public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLength { // Constants. public static final byte AES_BLOCK_SIZE = 16; public static final byte DES_BLOCK_SIZE = 8; @@ -150,10 +150,10 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe public static final byte OUTPUT_DATA = 25; public static final byte HW_TOKEN = 26; public static final byte VERIFICATION_TOKEN = 27; - private static final byte SIGNATURE = 28; + protected static final byte SIGNATURE = 28; // AddRngEntropy - private static final short MAX_SEED_SIZE = 2048; + protected static final short MAX_SEED_SIZE = 2048; // Keyblob constants public static final byte KEY_BLOB_SECRET = 0; public static final byte KEY_BLOB_NONCE = 1; @@ -167,23 +167,23 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe private static final short HMAC_SHARED_PARAM_MAX_SIZE = 64; // Keymaster Applet attributes - private static byte keymasterState = ILLEGAL_STATE; - private static KMEncoder encoder; - private static KMDecoder decoder; - private static KMRepository repository; - private static KMSEProvider seProvider; - private static byte[] buffer; - private static short bufferLength; - private static short bufferStartOffset; - private static short[] tmpVariables; - private static short[] data; - private byte provisionStatus = NOT_PROVISIONED; - private static final short MAX_CERT_SIZE = 2048; + protected static byte keymasterState = ILLEGAL_STATE; + protected static KMEncoder encoder; + protected static KMDecoder decoder; + protected static KMRepository repository; + protected static KMSEProvider seProvider; + protected static byte[] buffer; + protected static short bufferLength; + protected static short bufferStartOffset; + protected static short[] tmpVariables; + protected static short[] data; + protected byte provisionStatus = NOT_PROVISIONED; + protected static final short MAX_CERT_SIZE = 2048; /** Registers this applet. */ - protected KMKeymasterApplet() { + protected KMKeymasterApplet(KMSEProvider seImpl) { boolean isUpgrading = UpgradeManager.isUpgrading(); - seProvider = KMSEProviderImpl.instance(isUpgrading); + seProvider = seImpl; repository = new KMRepository(isUpgrading); byte[] buf = JCSystem.makeTransientByteArray((short) 32, JCSystem.CLEAR_ON_DESELECT); data = JCSystem.makeTransientShortArray((short) DATA_ARRAY_SIZE, JCSystem.CLEAR_ON_RESET); @@ -199,18 +199,6 @@ protected KMKeymasterApplet() { decoder = new KMDecoder(); } - /** - * Installs this applet. - * - * @param bArray the array containing installation parameters - * @param bOffset the starting offset in bArray - * @param bLength the length in bytes of the parameter data in bArray - */ - public static void install(byte[] bArray, short bOffset, byte bLength) { - new KMKeymasterApplet().register(bArray, (short) (bOffset + 1), bArray[bOffset]); - //new KMKeymasterApplet().register(); - } - /** * Selects this applet. * @@ -4068,7 +4056,7 @@ private void add(byte[] buf, short op1, short op2, short result) { index--; } } - +/* @Override public void onCleanup() { } @@ -4107,13 +4095,5 @@ public Element onSave() { seProvider.onSave(element); return element; } - - private short computePrimitveDataSize() { - // provisionStatus + keymasterState - return (short) 2; - } - - private short computeObjectCount() { - return (short) 0; - } +*/ } diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMOperation.java b/Applet/src/com/android/javacard/keymaster/KMOperation.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMOperation.java rename to Applet/src/com/android/javacard/keymaster/KMOperation.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMOperationState.java b/Applet/src/com/android/javacard/keymaster/KMOperationState.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMOperationState.java rename to Applet/src/com/android/javacard/keymaster/KMOperationState.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/src/com/android/javacard/keymaster/KMRepository.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMRepository.java rename to Applet/src/com/android/javacard/keymaster/KMRepository.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java b/Applet/src/com/android/javacard/keymaster/KMSEProvider.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMSEProvider.java rename to Applet/src/com/android/javacard/keymaster/KMSEProvider.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMTag.java b/Applet/src/com/android/javacard/keymaster/KMTag.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMTag.java rename to Applet/src/com/android/javacard/keymaster/KMTag.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMType.java b/Applet/src/com/android/javacard/keymaster/KMType.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMType.java rename to Applet/src/com/android/javacard/keymaster/KMType.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMUpgradable.java b/Applet/src/com/android/javacard/keymaster/KMUpgradable.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMUpgradable.java rename to Applet/src/com/android/javacard/keymaster/KMUpgradable.java diff --git a/Applet/Applet/src/com/android/javacard/keymaster/KMVerificationToken.java b/Applet/src/com/android/javacard/keymaster/KMVerificationToken.java similarity index 100% rename from Applet/Applet/src/com/android/javacard/keymaster/KMVerificationToken.java rename to Applet/src/com/android/javacard/keymaster/KMVerificationToken.java From 028e182f29d42d2140fb9886c5ac46db09f4f2ef Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Sun, 29 Nov 2020 23:03:59 +0000 Subject: [PATCH 38/42] Added new function isUpgrading inside KMSEProvider Corrected the values of extended errorCodes. Removed the hard-coded tags in KMAttestationCertImpl --- .../javacard/keymaster/KMAndroidSEApplet.java | 2 +- .../keymaster/KMAndroidSEProvider.java | 11 ++++++++--- .../keymaster/KMAttestationCertImpl.java | 18 ++++++++++++------ .../javacard/keymaster/KMJCardSimulator.java | 6 ++++++ .../android/javacard/keymaster/KMError.java | 10 +++++----- .../javacard/keymaster/KMKeymasterApplet.java | 3 +-- .../javacard/keymaster/KMSEProvider.java | 7 +++++++ 7 files changed, 40 insertions(+), 17 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java index 1d24f580..99dd47ce 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java @@ -7,7 +7,7 @@ public class KMAndroidSEApplet extends KMKeymasterApplet implements OnUpgradeListener { KMAndroidSEApplet(){ - super(new KMAndroidSEProvider(true)); + super(new KMAndroidSEProvider()); } /** * Installs this applet. diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java index db1cd7f5..9d9812c1 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java @@ -16,6 +16,8 @@ package com.android.javacard.keymaster; import org.globalplatform.upgrade.Element; +import org.globalplatform.upgrade.UpgradeManager; + import javacard.framework.JCSystem; import javacard.framework.Util; import javacard.security.AESKey; @@ -163,7 +165,7 @@ public static KMAndroidSEProvider getInstance() { return androidSEProvider; } - public KMAndroidSEProvider(boolean isUpgrading) { + public KMAndroidSEProvider() { // Re-usable AES,DES and HMAC keys in persisted memory. aesKeys = new AESKey[2]; aesKeys[KEYSIZE_128_OFFSET] = (AESKey) KeyBuilder.buildKey( @@ -199,7 +201,7 @@ public KMAndroidSEProvider(boolean isUpgrading) { // Random number generator initialisation. rng = RandomData.getInstance(RandomData.ALG_KEYGENERATION); //Allocate buffer for certificate chain. - if(!isUpgrading) + if(!isUpgrading()) certificateChain = new byte[CERT_CHAIN_MAX_SIZE]; androidSEProvider = this; } @@ -1204,5 +1206,8 @@ public short getBackupObjectCount() { return (short) 1; } - + @Override + public boolean isUpgrading() { + return UpgradeManager.isUpgrading(); + } } diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java index 1e50f620..40bd751b 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -482,9 +482,9 @@ private static void pushSWParams() { short last = stackPtr; // ATTESTATION_APPLICATION_ID 709 is softwareEnforced. short[] tagIds = { - 709, 706, 705, 704, 703, 702, 701, 601, 600, 509, 508, 507, 506, 505, 504, 503, 402, 401, 400, - 303, 200, 10, 6, 5, 3, 2, 1 - }; + KMType.ATTESTATION_APPLICATION_ID, KMType.CREATION_DATETIME, + KMType.USAGE_EXPIRE_DATETIME, KMType.ORIGINATION_EXPIRE_DATETIME, + KMType.ACTIVE_DATETIME, KMType.UNLOCKED_DEVICE_REQUIRED }; byte index = 0; do { /* @@ -502,9 +502,15 @@ private static void pushHWParams() { short last = stackPtr; // Attestation ids are not included. As per VTS attestation ids are not supported currenlty. short[] tagIds = { - 706, 705, 704, 703, 702, 701, 601, 600, 509, 508, 507, 506, 505, 504, 503, 402, 401, 400, 303, - 200, 10, 6, 5, 3, 2, 1 - }; + KMType.BOOT_PATCH_LEVEL, KMType.VENDOR_PATCH_LEVEL, + KMType.OS_PATCH_LEVEL, KMType.OS_VERSION, KMType.ROOT_OF_TRUST, + KMType.ORIGIN, KMType.APPLICATION_ID, + KMType.TRUSTED_CONFIRMATION_REQUIRED, + KMType.TRUSTED_USER_PRESENCE_REQUIRED, KMType.ALLOW_WHILE_ON_BODY, + KMType.AUTH_TIMEOUT, KMType.USER_AUTH_TYPE, KMType.NO_AUTH_REQUIRED, + KMType.ROLLBACK_RESISTANCE, KMType.RSA_PUBLIC_EXPONENT, + KMType.ECCURVE, KMType.PADDING, KMType.DIGEST, KMType.KEYSIZE, + KMType.ALGORITHM, KMType.PURPOSE }; byte index = 0; do { // if(pushAttIds(tagIds[index])) continue; diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java index 446f8bd2..70311e51 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java @@ -1312,4 +1312,10 @@ public short getBackupObjectCount() { // TODO Auto-generated method stub return 0; } + + @Override + public boolean isUpgrading() { + // TODO Auto-generated method stub + return false; + } } diff --git a/Applet/src/com/android/javacard/keymaster/KMError.java b/Applet/src/com/android/javacard/keymaster/KMError.java index 043fae96..e70dc8c2 100644 --- a/Applet/src/com/android/javacard/keymaster/KMError.java +++ b/Applet/src/com/android/javacard/keymaster/KMError.java @@ -87,9 +87,9 @@ public class KMError { //Extended errors public static short SW_CONDITIONS_NOT_SATISFIED = 1001; public static short UNSUPPORTED_CLA = 1002; - public static short INVALID_P1P2 = 1002; - public static short UNSUPPORTED_INSTRUCTION = 1002; - public static short CMD_NOT_ALLOWED = 1002; - public static short SW_WRONG_LENGTH = 1002; - public static short INVALID_DATA = 1002; + public static short INVALID_P1P2 = 1003; + public static short UNSUPPORTED_INSTRUCTION = 1004; + public static short CMD_NOT_ALLOWED = 1005; + public static short SW_WRONG_LENGTH = 1006; + public static short INVALID_DATA = 1007; } diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 76c97b0e..9b78c56c 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -26,7 +26,6 @@ import javacard.security.CryptoException; import javacardx.apdu.ExtendedLength; -import org.globalplatform.upgrade.*; /** * KMKeymasterApplet implements the javacard applet. It creates repository and other install time * objects. It also implements the keymaster state machine and handles javacard applet life cycle @@ -182,8 +181,8 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe /** Registers this applet. */ protected KMKeymasterApplet(KMSEProvider seImpl) { - boolean isUpgrading = UpgradeManager.isUpgrading(); seProvider = seImpl; + boolean isUpgrading = seImpl.isUpgrading(); repository = new KMRepository(isUpgrading); byte[] buf = JCSystem.makeTransientByteArray((short) 32, JCSystem.CLEAR_ON_DESELECT); data = JCSystem.makeTransientShortArray((short) DATA_ARRAY_SIZE, JCSystem.CLEAR_ON_RESET); diff --git a/Applet/src/com/android/javacard/keymaster/KMSEProvider.java b/Applet/src/com/android/javacard/keymaster/KMSEProvider.java index e0ee49dc..b3e9c266 100644 --- a/Applet/src/com/android/javacard/keymaster/KMSEProvider.java +++ b/Applet/src/com/android/javacard/keymaster/KMSEProvider.java @@ -476,4 +476,11 @@ KMOperation initAsymmetricOperation( * @param resetBootFlag is false if event has been handled */ void clearDeviceBooted(boolean resetBootFlag); + + /** + * This function tells if applet is upgrading or not. + * + * @return true if upgrading, otherwise false. + */ + boolean isUpgrading(); } From 6b6256644f33cd989ecdcd24e1c68118dae5a521 Mon Sep 17 00:00:00 2001 From: BKSSMVenkateswarlu <40534495+BKSSMVenkateswarlu@users.noreply.github.com> Date: Mon, 30 Nov 2020 20:43:14 +0000 Subject: [PATCH 39/42] Update README.md Updated README file. --- Applet/README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Applet/README.md b/Applet/README.md index 9d592fd2..76af5b05 100644 --- a/Applet/README.md +++ b/Applet/README.md @@ -1,6 +1,19 @@ # JavaCardKeymaster Applet This directory contains the implementation of the Keymaster 4.1 -interface, in the form of a JavaCard 3.1 applet which runs in a secure +interface, in the form of a JavaCard 3.0.5 applet which runs in a secure element. It must be deployed in conjuction with the associated HAL, which serves to intermediate between Android Keystore and this applet. + +# Supported Features! + + - Support for AndroidSEProvider, which is compliant to JavaCard platform, Classic Edition 3.0.5. + - Keymaster 4.1 supported functions for required VTS compliance. + - Support for SE Provisioning and bootup + - Support for Global platoform Amendment H in AndroidSEProvider. + - Unit test using JCardSim. + +#### Building for source +- Install Javacard 3.0.5 classic sdk. +- set JC_HOME_SIMULATOR environment variable to the installed sdk. +- Give ant build from Applet folder. From 1a06199381bd5d492bbe7b16509e25538abe6748 Mon Sep 17 00:00:00 2001 From: BKSSMVenkateswarlu <40534495+BKSSMVenkateswarlu@users.noreply.github.com> Date: Mon, 30 Nov 2020 21:00:14 +0000 Subject: [PATCH 40/42] Update README.md Updated the links for Applet Design document and HAL design document. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dd532000..670e94a1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ # JavaCardKeymaster JavaCard implementation of the [Android Keymaster 4.1 HAL](https://android.googlesource.com/platform/hardware/interfaces/+/master/keymaster/4.1/IKeymasterDevice.hal) (most of the specification is in the [Android Keymaster 4.0 HAL](https://android.googlesource.com/platform/hardware/interfaces/+/master/keymaster/4.0/IKeymasterDevice.hal)), intended for creation of StrongBox Keymaster instances to support the [Android Hardware-backed Keystore](https://source.android.com/security/keystore). -Here is the [JavaCard Applet design doc](https://docs.google.com/document/d/1mIv895E3imKfzxS9weWQxP3jZIxS-7OPmh4fxdjOPm0/edit#heading=h.xgjl2srtytjt) and the [HAL design doc](https://docs.google.com/document/d/1ExaoEOU3mkjhoMIcAhD_Z6kPp5yyfjpnfBpUQHiSomw/edit#heading=h.gjdgxs) (the content will move here when it stablizes, for now these are a limited-access links). +Here is the [JavaCard Applet design doc](https://docs.google.com/document/d/1bTAmhDqCNq1HYzChNDv8kLJEi64cwTIZ2PfdMMz3o8U/edit#heading=h.gjdgxs) and the [HAL design doc](https://docs.google.com/document/d/1-1MLJ781wAPJ2YxCdCtHMepld8F8KVAxpPtCw9J3b3o/edit#heading=h.gjdgxs) (the content will move here when it stablizes, for now these are a limited-access links). From 0b26602c3d23baa246ad6737a9f1882ef36b5219 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Mon, 30 Nov 2020 21:20:40 +0000 Subject: [PATCH 41/42] Added a protected function validateApduHeader so that subclass of KMKemasterApplet can override it. --- .../javacard/keymaster/KMKeymasterApplet.java | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 9b78c56c..43ada045 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -246,6 +246,23 @@ private short mapISOErrorToKMError(short reason) { } } + protected void validateApduHeader(APDU apdu) { + // Read the apdu header and buffer. + byte[] apduBuffer = apdu.getBuffer(); + byte apduClass = apduBuffer[ISO7816.OFFSET_CLA]; + short P1P2 = Util.getShort(apduBuffer, ISO7816.OFFSET_P1); + + // Validate APDU Header. + if ((apduClass != CLA_ISO7816_NO_SM_NO_CHAN)) { + ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED); + } + + // Validate P1P2. + if (P1P2 != KMKeymasterApplet.KM_HAL_VERSION) { + ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); + } + } + /** * Processes an incoming APDU and handles it using command objects. * @@ -267,24 +284,17 @@ public void process(APDU apdu) { return; } } - // Read the apdu header and buffer. + // Validate APDU Header. + validateApduHeader(apdu); + byte[] apduBuffer = apdu.getBuffer(); - byte apduClass = apduBuffer[ISO7816.OFFSET_CLA]; byte apduIns = apduBuffer[ISO7816.OFFSET_INS]; - short P1P2 = Util.getShort(apduBuffer, ISO7816.OFFSET_P1); - buffer = repository.getHeap(); - // Validate APDU Header. - if ((apduClass != CLA_ISO7816_NO_SM_NO_CHAN)) { - ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED); - } - if (P1P2 != KMKeymasterApplet.KM_HAL_VERSION) { - ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); - } // Validate whether INS can be supported if (!(apduIns > INS_BEGIN_KM_CMD && apduIns < INS_END_KM_CMD)) { ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); } + buffer = repository.getHeap(); // Process the apdu if (keymasterState == KMKeymasterApplet.IN_PROVISION_STATE) { switch (apduIns) { From 438583ac6897a8f0187605242a3c9dcf6a849d50 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Tue, 1 Dec 2020 09:44:02 +0000 Subject: [PATCH 42/42] 1. Moved provision and setbootparams in a separate file. 2. Added getCertificateChain function which parses the chain of certificates. 3. Bug fixes. --- HAL/keymaster/4.1/CommonUtils.cpp | 50 ++ .../4.1/JavacardKeymaster4Device.cpp | 504 +++------------- HAL/keymaster/4.1/Provision.cpp | 558 ++++++++++++++++++ HAL/keymaster/Android.bp | 1 + HAL/keymaster/include/CommonUtils.h | 2 + .../include/JavacardKeymaster4Device.h | 10 - HAL/keymaster/include/Provision.h | 36 ++ 7 files changed, 738 insertions(+), 423 deletions(-) create mode 100644 HAL/keymaster/4.1/Provision.cpp create mode 100644 HAL/keymaster/include/Provision.h diff --git a/HAL/keymaster/4.1/CommonUtils.cpp b/HAL/keymaster/4.1/CommonUtils.cpp index 67993957..a6d2b7ab 100644 --- a/HAL/keymaster/4.1/CommonUtils.cpp +++ b/HAL/keymaster/4.1/CommonUtils.cpp @@ -27,6 +27,10 @@ #include #include +#define TAG_SEQUENCE 0x30 +#define LENGTH_MASK 0x80 +#define LENGTH_VALUE_MASK 0x7F + namespace keymaster { namespace V4_1 { namespace javacard { @@ -222,6 +226,52 @@ pubModulus) { return ErrorCode::OK; } +ErrorCode getCertificateChain(std::vector& chainBuffer, std::vector>& certChain) { + uint8_t *data = chainBuffer.data(); + int index = 0; + uint32_t length = 0; + while (index < chainBuffer.size()) { + std::vector temp; + if(data[index] == TAG_SEQUENCE) { + //read next byte + if (0 == (data[index+1] & LENGTH_MASK)) { + length = (uint32_t)data[index]; + //Add SEQ and Length fields + length += 2; + } else { + int additionalBytes = data[index+1] & LENGTH_VALUE_MASK; + if (additionalBytes == 0x01) { + length = data[index+2]; + //Add SEQ and Length fields + length += 3; + } else if (additionalBytes == 0x02) { + length = (data[index+2] << 8 | data[index+3]); + //Add SEQ and Length fields + length += 4; + } else if (additionalBytes == 0x04) { + length = data[index+2] << 24; + length |= data[index+3] << 16; + length |= data[index+4] << 8; + length |= data[index+5]; + //Add SEQ and Length fields + length += 6; + } else { + //Length is larger than uint32_t max limit. + return ErrorCode::UNKNOWN_ERROR; + } + } + temp.insert(temp.end(), (data+index), (data+index+length)); + index += length; + + certChain.push_back(std::move(temp)); + } else { + //SEQUENCE TAG MISSING. + return ErrorCode::UNKNOWN_ERROR; + } + } + return ErrorCode::OK; +} + } // namespace javacard } // namespace V4_1 diff --git a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp index 501880a8..23583024 100644 --- a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp +++ b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -44,16 +45,14 @@ #define APDU_P1 0x40 #define APDU_P2 0x00 #define APDU_RESP_STATUS_OK 0x9000 -#define ROOT_RSA_KEY "/data/data/rsa_key.der" -#define ROOT_RSA_CERT "/data/data/certificate_rsa.der" -/*This property is used to check if javacard is already provisioned or not */ -#define KM_JAVACARD_PROVISIONED_PROPERTY "keymaster.javacard.provisioned" + +#define INS_BEGIN_KM_CMD 0x00 +#define INS_END_KM_PROVISION_CMD 0x20 +#define INS_END_KM_CMD 0x7F namespace keymaster { namespace V4_1 { namespace javacard { -//This key is used as master key for computing Hmac shared secret. -constexpr uint8_t kFakeKeyAgreementKey[32] = {}; static std::unique_ptr pTransportFactory = nullptr; constexpr size_t kOperationTableSize = 4; @@ -63,34 +62,29 @@ struct KM_AUTH_LIST_Delete { }; enum class Instruction { - INS_GENERATE_KEY_CMD = 0x10, - INS_IMPORT_KEY_CMD = 0x11, - INS_IMPORT_WRAPPED_KEY_CMD = 0x12, - INS_EXPORT_KEY_CMD = 0x13, - INS_ATTEST_KEY_CMD = 0x14, - INS_UPGRADE_KEY_CMD = 0x15, - INS_DELETE_KEY_CMD = 0x16, - INS_DELETE_ALL_KEYS_CMD = 0x17, - INS_ADD_RNG_ENTROPY_CMD = 0x18, - INS_COMPUTE_SHARED_HMAC_CMD = 0x19, - INS_DESTROY_ATT_IDS_CMD = 0x1A, - INS_VERIFY_AUTHORIZATION_CMD = 0x1B, - INS_GET_HMAC_SHARING_PARAM_CMD = 0x1C, - INS_GET_KEY_CHARACTERISTICS_CMD = 0x1D, - INS_GET_HW_INFO_CMD = 0x1E, - INS_BEGIN_OPERATION_CMD = 0x1F, - INS_UPDATE_OPERATION_CMD = 0x20, - INS_FINISH_OPERATION_CMD = 0x21, - INS_ABORT_OPERATION_CMD = 0x22, - INS_PROVISION_ATTEST_IDS_ROOT_KEY_CMD = 0x23, - INS_SET_BOOT_PARAMS_CMD = 0x24, - INS_DEVICE_LOCKED_CMD = 0x25, - INS_EARLY_BOOT_ENDED_CMD = 0x26, - INS_BACKUP_CMD = 0x27, - INS_RESTORE_CMD = 0x28, - INS_PROVISION_SHARED_SECRET_CMD = 0x29, - INS_PROVISION_CERT_CHAIN_CMD = 0x2A, - INS_GET_CERT_CHAIN_CMD = 0x2B + // Keymaster commands + INS_GENERATE_KEY_CMD = INS_END_KM_PROVISION_CMD+1, + INS_IMPORT_KEY_CMD = INS_END_KM_PROVISION_CMD+2, + INS_IMPORT_WRAPPED_KEY_CMD = INS_END_KM_PROVISION_CMD+3, + INS_EXPORT_KEY_CMD = INS_END_KM_PROVISION_CMD+4, + INS_ATTEST_KEY_CMD = INS_END_KM_PROVISION_CMD+5, + INS_UPGRADE_KEY_CMD = INS_END_KM_PROVISION_CMD+6, + INS_DELETE_KEY_CMD = INS_END_KM_PROVISION_CMD+7, + INS_DELETE_ALL_KEYS_CMD = INS_END_KM_PROVISION_CMD+8, + INS_ADD_RNG_ENTROPY_CMD = INS_END_KM_PROVISION_CMD+9, + INS_COMPUTE_SHARED_HMAC_CMD = INS_END_KM_PROVISION_CMD+10, + INS_DESTROY_ATT_IDS_CMD = INS_END_KM_PROVISION_CMD+11, + INS_VERIFY_AUTHORIZATION_CMD = INS_END_KM_PROVISION_CMD+12, + INS_GET_HMAC_SHARING_PARAM_CMD = INS_END_KM_PROVISION_CMD+13, + INS_GET_KEY_CHARACTERISTICS_CMD = INS_END_KM_PROVISION_CMD+14, + INS_GET_HW_INFO_CMD = INS_END_KM_PROVISION_CMD+15, + INS_BEGIN_OPERATION_CMD = INS_END_KM_PROVISION_CMD+16, + INS_UPDATE_OPERATION_CMD = INS_END_KM_PROVISION_CMD+17, + INS_FINISH_OPERATION_CMD = INS_END_KM_PROVISION_CMD+18, + INS_ABORT_OPERATION_CMD = INS_END_KM_PROVISION_CMD+19, + INS_DEVICE_LOCKED_CMD = INS_END_KM_PROVISION_CMD+20, + INS_EARLY_BOOT_ENDED_CMD = INS_END_KM_PROVISION_CMD+21, + INS_GET_CERT_CHAIN_CMD = INS_END_KM_PROVISION_CMD+22 }; static inline std::unique_ptr& getTransportFactoryInstance() { @@ -102,29 +96,6 @@ static inline std::unique_ptr& getTransportFacto return pTransportFactory; } -static inline bool readDataFromFile(const char *filename, std::vector& data) { - FILE *fp; - bool ret = true; - fp = fopen(filename, "rb"); - if(fp == NULL) { - LOG(ERROR) << "Failed to open file: " << filename; - return false; - } - fseek(fp, 0L, SEEK_END); - long int filesize = ftell(fp); - rewind(fp); - std::unique_ptr buf(new uint8_t[filesize]); - if( 0 == fread(buf.get(), filesize, 1, fp)) { - LOG(ERROR) << "No Content in the file: " << filename; - ret = false; - } - if(true == ret) { - data.insert(data.begin(), buf.get(), buf.get() + filesize); - } - fclose(fp); - return ret; -} - static inline bool findTag(const hidl_vec& params, Tag tag) { size_t size = params.size(); for(size_t i = 0; i < size; ++i) { @@ -145,84 +116,6 @@ static inline bool getTag(const hidl_vec& params, Tag tag, KeyPara return false; } -static inline X509* parseDerCertificate(const char* filename) { - X509 *x509 = NULL; - std::vector certData; - - /* Read the Root certificate */ - if(!readDataFromFile(filename, certData)) { - LOG(ERROR) << " Failed to read the Root certificate"; - return NULL; - } - /* Create BIO instance from certificate data */ - BIO *bio = BIO_new_mem_buf(certData.data(), certData.size()); - if(bio == NULL) { - LOG(ERROR) << " Failed to create BIO from buffer."; - return NULL; - } - /* Create X509 instance from BIO */ - x509 = d2i_X509_bio(bio, NULL); - if(x509 == NULL) { - LOG(ERROR) << " Failed to get X509 instance from BIO."; - return NULL; - } - BIO_free(bio); - return x509; -} - -static inline void getDerSubjectName(X509* x509, std::vector& subject) { - uint8_t *subjectDer = NULL; - X509_NAME* asn1Subject = X509_get_subject_name(x509); - if(asn1Subject == NULL) { - LOG(ERROR) << " Failed to read the subject."; - return; - } - /* Convert X509_NAME to der encoded subject */ - int len = i2d_X509_NAME(asn1Subject, &subjectDer); - if (len < 0) { - LOG(ERROR) << " Failed to get readable name from X509_NAME."; - return; - } - subject.insert(subject.begin(), subjectDer, subjectDer+len); -} - -static inline void getAuthorityKeyIdentifier(X509* x509, std::vector& authKeyId) { - long xlen; - int tag, xclass; - - int loc = X509_get_ext_by_NID(x509, NID_authority_key_identifier, -1); - X509_EXTENSION *ext = X509_get_ext(x509, loc); - if(ext == NULL) { - LOG(ERROR) << " Failed to read authority key identifier."; - return; - } - - ASN1_OCTET_STRING *asn1AuthKeyId = X509_EXTENSION_get_data(ext); - const uint8_t *strAuthKeyId = ASN1_STRING_get0_data(asn1AuthKeyId); - int strAuthKeyIdLen = ASN1_STRING_length(asn1AuthKeyId); - int ret = ASN1_get_object(&strAuthKeyId, &xlen, &tag, &xclass, strAuthKeyIdLen); - if (ret == 0x80 || strAuthKeyId == NULL) { - LOG(ERROR) << "Failed to get the auth key identifier from ASN1 sequence."; - return; - } - authKeyId.insert(authKeyId.begin(), strAuthKeyId, strAuthKeyId + xlen); -} - -static inline void getNotAfter(X509* x509, std::vector& notAfterDate) { - const ASN1_TIME* notAfter = X509_get0_notAfter(x509); - if(notAfter == NULL) { - LOG(ERROR) << " Failed to read expiry time."; - return; - } - int strNotAfterLen = ASN1_STRING_length(notAfter); - const uint8_t *strNotAfter = ASN1_STRING_get0_data(notAfter); - if(strNotAfter == NULL) { - LOG(ERROR) << " Failed to read expiry time from ASN1 string."; - return; - } - notAfterDate.insert(notAfterDate.begin(), strNotAfter, strNotAfter + strNotAfterLen); -} - ErrorCode encodeParametersVerified(const VerificationToken& verificationToken, std::vector& asn1ParamsVerified) { if (verificationToken.parametersVerified.size() > 0) { AuthorizationSet paramSet; @@ -362,65 +255,16 @@ uint16_t getStatus(std::vector& inputData) { return (inputData.at(inputData.size()-2) << 8) | (inputData.at(inputData.size()-1)); } -ErrorCode initiateProvision() { - /* This is just a reference implemenation */ - std::string brand("Google"); - std::string device("Pixel 3A"); - std::string product("Pixel"); - std::string serial("UGYJFDjFeRuBEH"); - std::string imei("987080543071019"); - std::string meid("27863510227963"); - std::string manufacturer("Foxconn"); - std::string model("HD1121"); - AuthorizationSet authSet(AuthorizationSetBuilder() - .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA) - .Authorization(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN) - .Authorization(TAG_DIGEST, KM_DIGEST_SHA_2_256) - .Authorization(TAG_KEY_SIZE, 2048) - .Authorization(TAG_PURPOSE, static_cast(0x7F)) /* The value 0x7F is not present in types.hal */ - .Authorization(TAG_ATTESTATION_ID_BRAND, brand.data(), brand.size()) - .Authorization(TAG_ATTESTATION_ID_DEVICE, device.data(), device.size()) - .Authorization(TAG_ATTESTATION_ID_PRODUCT, product.data(), product.size()) - .Authorization(TAG_ATTESTATION_ID_SERIAL, serial.data(), serial.size()) - .Authorization(TAG_ATTESTATION_ID_IMEI, imei.data(), imei.size()) - .Authorization(TAG_ATTESTATION_ID_MEID, meid.data(), meid.size()) - .Authorization(TAG_ATTESTATION_ID_MANUFACTURER, manufacturer.data(), manufacturer.size()) - .Authorization(TAG_ATTESTATION_ID_MODEL, model.data(), model.size())); - - hidl_vec keyParams = kmParamSet2Hidl(authSet); - std::vector data; - if(!readDataFromFile(ROOT_RSA_KEY, data)) { - LOG(ERROR) << " Failed to read the Root rsa key"; - return ErrorCode::UNKNOWN_ERROR; - } - return JavacardKeymaster4Device::provision(keyParams, KeyFormat::PKCS8, data); -} - -Return setBootParams() { - std::vector verifiedBootKey(32, 0); - std::vector verifiedBootKeyHash(32, 0); - - return JavacardKeymaster4Device::setBootParams(GetOsVersion(), GetOsPatchlevel(), verifiedBootKey, verifiedBootKeyHash, - KM_VERIFIED_BOOT_UNVERIFIED, 0/*deviceLocked*/); -} - ErrorCode sendData(Instruction ins, std::vector& inData, std::vector& response, bool -extendedOutput=false) { + extendedOutput=false) { ErrorCode ret = ErrorCode::UNKNOWN_ERROR; std::vector apdu; - if(!android::base::GetBoolProperty(KM_JAVACARD_PROVISIONED_PROPERTY, false)) { - - if(ErrorCode::OK != (ret = initiateProvision())) { - LOG(ERROR) << "Failed to provision the device"; - return ret; - } - - if(ErrorCode::OK != (ret = setBootParams())) { - LOG(ERROR) << "Failed to set boot params"; - return ret; - } - android::base::SetProperty(KM_JAVACARD_PROVISIONED_PROPERTY, "true"); + // TODO In real scenario the provision happens in the factory. In that case this + // below code is not required. This is just used for simulation. + if (ErrorCode::OK != (ret = provision(getTransportFactoryInstance()))) { + LOG(ERROR) << "Failed to provision the device"; + return ret; } ret = constructApduMessage(ins, inData, apdu, extendedOutput); @@ -430,174 +274,13 @@ extendedOutput=false) { return (ErrorCode::SECURE_HW_COMMUNICATION_FAILED); } - if((response.size() < 2) || (getStatus(response) != APDU_RESP_STATUS_OK)) { + // Response size should be greater than 2. Cbor output data followed by two bytes of APDU status. + if((response.size() <= 2) || (getStatus(response) != APDU_RESP_STATUS_OK)) { return (ErrorCode::UNKNOWN_ERROR); } return (ErrorCode::OK);//success } -ErrorCode JavacardKeymaster4Device::provision(const hidl_vec& keyParams, KeyFormat keyFormat, const hidl_vec& - keyData) { - cppbor::Array array; - cppbor::Array subArray; - std::unique_ptr item; - std::vector apdu; - hidl_vec keyBlob; - ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; - Instruction ins = Instruction::INS_PROVISION_ATTEST_IDS_ROOT_KEY_CMD; - std::vector response; - CborConverter cborConverter; - X509 *x509 = NULL; - std::vector subject; - std::vector authorityKeyIdentifier; - std::vector notAfter; - std::vector masterKey(kFakeKeyAgreementKey, kFakeKeyAgreementKey + - sizeof(kFakeKeyAgreementKey)/sizeof(kFakeKeyAgreementKey[0])); - - /* Subject, AuthorityKeyIdentifier and Expirty time of the root certificate are required by javacard. */ - /* Get X509 certificate instance for the root certificate.*/ - if(NULL == (x509 = parseDerCertificate(ROOT_RSA_CERT))) { - return errorCode; - } - - if(ErrorCode::OK != (errorCode = prepareCborArrayFromKeyData(keyParams, keyFormat, keyData, subArray))) { - return errorCode; - } - /* Get subject in DER */ - getDerSubjectName(x509, subject); - /* Get AuthorityKeyIdentifier */ - getAuthorityKeyIdentifier(x509, authorityKeyIdentifier); - /* Get Expirty Time */ - getNotAfter(x509, notAfter); - /*Free X509 */ - X509_free(x509); - - /* construct cbor */ - cborConverter.addKeyparameters(array, keyParams); - array.add(static_cast(KeyFormat::RAW)); - std::vector encodedArray = subArray.encode(); - cppbor::Bstr bstr(encodedArray.begin(), encodedArray.end()); - array.add(bstr); - array.add(subject); - array.add(notAfter); - array.add(authorityKeyIdentifier); - std::vector cborData = array.encode(); - - if(ErrorCode::OK != (errorCode = constructApduMessage(ins, cborData, apdu))) - return errorCode; - - if(!getTransportFactoryInstance()->sendData(apdu.data(), apdu.size(), response)) { - return (ErrorCode::SECURE_HW_COMMUNICATION_FAILED); - } - - if((response.size() < 2) || (getStatus(response) != APDU_RESP_STATUS_OK)) { - return (ErrorCode::UNKNOWN_ERROR); - } - - if((response.size() > 2)) { - //Skip last 2 bytes in cborData, it contains status. - std::tie(item, errorCode) = cborConverter.decodeData(std::vector(response.begin(), response.end()-2), - true); - } - - if(ErrorCode::OK != errorCode) - return errorCode; - - //Provision master key - ins = Instruction::INS_PROVISION_SHARED_SECRET_CMD; - array = cppbor::Array(); - array.add(masterKey); - cborData = array.encode(); - apdu.clear(); - response.clear(); - - if(ErrorCode::OK != (errorCode = constructApduMessage(ins, cborData, apdu))) - return errorCode; - - if(!getTransportFactoryInstance()->sendData(apdu.data(), apdu.size(), response)) { - return (ErrorCode::SECURE_HW_COMMUNICATION_FAILED); - } - - if((response.size() < 2) || (getStatus(response) != APDU_RESP_STATUS_OK)) { - return (ErrorCode::UNKNOWN_ERROR); - } - - if((response.size() > 2)) { - //Skip last 2 bytes in cborData, it contains status. - std::tie(item, errorCode) = cborConverter.decodeData(std::vector(response.begin(), response.end()-2), - true); - } - - if(ErrorCode::OK != errorCode) - return errorCode; - - //Provsion root certificate - ins = Instruction::INS_PROVISION_CERT_CHAIN_CMD; - std::vector certData; - array = cppbor::Array(); - subArray = cppbor::Array(); - /* Read the Root certificate */ - if(!readDataFromFile(ROOT_RSA_CERT, certData)) { - LOG(ERROR) << " Failed to read the Root certificate"; - return (ErrorCode::UNKNOWN_ERROR); - } - array.add(certData); - cborData = array.encode(); - apdu.clear(); - response.clear(); - - if(ErrorCode::OK != (errorCode = constructApduMessage(ins, cborData, apdu))) - return errorCode; - - if(!getTransportFactoryInstance()->sendData(apdu.data(), apdu.size(), response)) { - return (ErrorCode::SECURE_HW_COMMUNICATION_FAILED); - } - - if((response.size() < 2) || (getStatus(response) != APDU_RESP_STATUS_OK)) { - return (ErrorCode::UNKNOWN_ERROR); - } - - if((response.size() > 2)) { - //Skip last 2 bytes in cborData, it contains status. - std::tie(item, errorCode) = cborConverter.decodeData(std::vector(response.begin(), response.end()-2), - true); - } - - return errorCode; -} - -ErrorCode JavacardKeymaster4Device::setBootParams(uint32_t osVersion, uint32_t osPatchLevel, const std::vector& verifiedBootKey, - std::vector& verifiedBootKeyHash, keymaster_verified_boot_t kmVerifiedBoot, bool deviceLocked) { - cppbor::Array array; - std::vector apdu; - std::vector response; - Instruction ins = Instruction::INS_SET_BOOT_PARAMS_CMD; - array.add(osVersion). - add(osPatchLevel). - /* Verified Boot Key */ - add(verifiedBootKey). - /* Verified Boot Hash */ - add(verifiedBootKeyHash). - /* boot state */ - add(static_cast(kmVerifiedBoot)). - /* device locked */ - add(static_cast(deviceLocked)); - std::vector cborData = array.encode(); - - ErrorCode ret = constructApduMessage(ins, cborData, apdu); - if(ret != ErrorCode::OK) return ret; - - if(!getTransportFactoryInstance()->sendData(apdu.data(), apdu.size(), response)) { - return (ErrorCode::SECURE_HW_COMMUNICATION_FAILED); - } - - if((response.size() < 2) || (getStatus(response) != APDU_RESP_STATUS_OK)) { - return (ErrorCode::UNKNOWN_ERROR); - } - return ErrorCode::OK; - -} - JavacardKeymaster4Device::JavacardKeymaster4Device(): softKm_(new ::keymaster::AndroidKeymaster( []() -> auto { auto context = new JavaCardSoftKeymasterContext(); @@ -621,23 +304,21 @@ Return JavacardKeymaster4Device::getHardwareInfo(getHardwareInfo_cb _hidl_ hidl_string jcKeymasterAuthor; ErrorCode ret = sendData(Instruction::INS_GET_HW_INFO_CMD, input, resp); - if(ret == ErrorCode::SECURE_HW_COMMUNICATION_FAILED) { + if(ret != ErrorCode::OK) { //Socket not connected. _hidl_cb(SecurityLevel::STRONGBOX, JAVACARD_KEYMASTER_NAME, JAVACARD_KEYMASTER_AUTHOR); return Void(); } else { - if((ret == ErrorCode::OK) && (resp.size() > 2)) { - //Skip last 2 bytes in cborData, it contains status. - std::tie(item, ret) = cborConverter_.decodeData(std::vector(resp.begin(), resp.end()-2), - true); - if (item != nullptr) { - std::vector temp; - if(!cborConverter_.getUint64(item, 0, securityLevel) || - !cborConverter_.getBinaryArray(item, 1, jcKeymasterName) || - !cborConverter_.getBinaryArray(item, 2, jcKeymasterAuthor)) { - _hidl_cb(static_cast(securityLevel), jcKeymasterName, jcKeymasterAuthor); - return Void(); - } + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, ret) = cborConverter_.decodeData(std::vector(resp.begin(), resp.end()-2), + true); + if (item != nullptr) { + std::vector temp; + if(!cborConverter_.getUint64(item, 0, securityLevel) || + !cborConverter_.getBinaryArray(item, 1, jcKeymasterName) || + !cborConverter_.getBinaryArray(item, 2, jcKeymasterAuthor)) { + _hidl_cb(static_cast(securityLevel), jcKeymasterName, jcKeymasterAuthor); + return Void(); } } _hidl_cb(static_cast(securityLevel), jcKeymasterName, jcKeymasterAuthor); @@ -655,9 +336,8 @@ Return JavacardKeymaster4Device::getHmacSharingParameters(getHmacSharingPa std::unique_ptr item; HmacSharingParameters hmacSharingParameters; ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; - errorCode = sendData(Instruction::INS_GET_HMAC_SHARING_PARAM_CMD, input, cborData); - if(errorCode == ErrorCode::SECURE_HW_COMMUNICATION_FAILED) { + if(errorCode != ErrorCode::OK) { auto response = softKm_->GetHmacSharingParameters(); ::android::hardware::keymaster::V4_0::HmacSharingParameters params; params.seed.setToExternal(const_cast(response.params.seed.data), @@ -667,14 +347,12 @@ Return JavacardKeymaster4Device::getHmacSharingParameters(getHmacSharingPa _hidl_cb(legacy_enum_conversion(response.error), params); return Void(); } else { - if((errorCode == ErrorCode::OK) && (cborData.size() > 2)) { - //Skip last 2 bytes in cborData, it contains status. - std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborData.begin(), cborData.end()-2), - true); - if (item != nullptr) { - if(!cborConverter_.getHmacSharingParameters(item, 1, hmacSharingParameters)) { - errorCode = ErrorCode::UNKNOWN_ERROR; - } + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborData.begin(), cborData.end()-2), + true); + if (item != nullptr) { + if(!cborConverter_.getHmacSharingParameters(item, 1, hmacSharingParameters)) { + errorCode = ErrorCode::UNKNOWN_ERROR; } } _hidl_cb(errorCode, hmacSharingParameters); @@ -709,7 +387,7 @@ Return JavacardKeymaster4Device::computeSharedHmac(const hidl_vec cborData = array.encode(); errorCode = sendData(Instruction::INS_COMPUTE_SHARED_HMAC_CMD, cborData, cborOutData); - if(errorCode == ErrorCode::SECURE_HW_COMMUNICATION_FAILED) { + if(errorCode != ErrorCode::OK) { ComputeSharedHmacRequest request; request.params_array.params_array = new keymaster::HmacSharingParameters[params.size()]; request.params_array.num_params = params.size(); @@ -730,17 +408,15 @@ Return JavacardKeymaster4Device::computeSharedHmac(const hidl_vec 2)) { - //Skip last 2 bytes in cborData, it contains status. - std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), - true); - if (item != nullptr) { - std::vector bstr; - if(!cborConverter_.getBinaryArray(item, 1, bstr)) { - errorCode = ErrorCode::UNKNOWN_ERROR; - } else { - sharingCheck = bstr; - } + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), + true); + if (item != nullptr) { + std::vector bstr; + if(!cborConverter_.getBinaryArray(item, 1, bstr)) { + errorCode = ErrorCode::UNKNOWN_ERROR; + } else { + sharingCheck = bstr; } } _hidl_cb(errorCode, sharingCheck); @@ -766,8 +442,7 @@ Return JavacardKeymaster4Device::addRngEntropy(const hidl_vec cborData = array.encode(); errorCode = sendData(Instruction::INS_ADD_RNG_ENTROPY_CMD, cborData, cborOutData); - - if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + if(errorCode == ErrorCode::OK) { //Skip last 2 bytes in cborData, it contains status. std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), true); @@ -799,7 +474,7 @@ Return JavacardKeymaster4Device::generateKey(const hidl_vec& errorCode = sendData(Instruction::INS_GENERATE_KEY_CMD, cborData, cborOutData); - if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + if(errorCode == ErrorCode::OK) { //Skip last 2 bytes in cborData, it contains status. std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), true); @@ -845,7 +520,7 @@ Return JavacardKeymaster4Device::importKey(const hidl_vec& k errorCode = sendData(Instruction::INS_IMPORT_KEY_CMD, cborData, cborOutData); - if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + if(errorCode == ErrorCode::OK) { //Skip last 2 bytes in cborData, it contains status. std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), true); @@ -895,12 +570,12 @@ Return JavacardKeymaster4Device::importWrappedKey(const hidl_vec& cborConverter_.addKeyparameters(array, unwrappingParams); array.add(std::vector(wrappedKeyDescription)); array.add(passwordSid); - array.add(biometricSid); /* TODO if biometricSid optional if user not sent this don't encode this cbor format */ + array.add(biometricSid); std::vector cborData = array.encode(); errorCode = sendData(Instruction::INS_IMPORT_WRAPPED_KEY_CMD, cborData, cborOutData); - if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + if(errorCode == ErrorCode::OK) { //Skip last 2 bytes in cborData, it contains status. std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), true); @@ -933,7 +608,7 @@ Return JavacardKeymaster4Device::getKeyCharacteristics(const hidl_vec 2)) { + if(errorCode == ErrorCode::OK) { //Skip last 2 bytes in cborData, it contains status. std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), true); @@ -982,6 +657,8 @@ Return JavacardKeymaster4Device::exportKey(KeyFormat exportFormat, const h return Void(); } + + Return JavacardKeymaster4Device::attestKey(const hidl_vec& keyToAttest, const hidl_vec& attestParams, attestKey_cb _hidl_cb) { cppbor::Array array; std::unique_ptr item; @@ -993,10 +670,9 @@ Return JavacardKeymaster4Device::attestKey(const hidl_vec& keyToA array.add(std::vector(keyToAttest)); cborConverter_.addKeyparameters(array, attestParams); std::vector cborData = array.encode(); - errorCode = sendData(Instruction::INS_ATTEST_KEY_CMD, cborData, cborOutData); - if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + if(errorCode == ErrorCode::OK) { std::vector> temp; std::vector rootCert; //Skip last 2 bytes in cborData, it contains status. @@ -1009,17 +685,20 @@ Return JavacardKeymaster4Device::attestKey(const hidl_vec& keyToA cborData.clear(); cborOutData.clear(); errorCode = sendData(Instruction::INS_GET_CERT_CHAIN_CMD, cborData, cborOutData, true); - if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + if(errorCode == ErrorCode::OK) { //Skip last 2 bytes in cborData, it contains status. std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), true); if (item != nullptr) { - if(!cborConverter_.getMultiBinaryArray(item, 1, temp)) { + std::vector chain; + if(!cborConverter_.getBinaryArray(item, 1, chain)) { errorCode = ErrorCode::UNKNOWN_ERROR; } else { - certChain.resize(temp.size()); - for(int i = 0; i < temp.size(); i++) { - certChain[i] = temp[i]; + if(ErrorCode::OK == (errorCode = getCertificateChain(chain, temp))) { + certChain.resize(temp.size()); + for(int i = 0; i < temp.size(); i++) { + certChain[i] = temp[i]; + } } } } @@ -1044,7 +723,7 @@ Return JavacardKeymaster4Device::upgradeKey(const hidl_vec& keyBl errorCode = sendData(Instruction::INS_UPGRADE_KEY_CMD, cborData, cborOutData); - if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + if(errorCode == ErrorCode::OK) { //Skip last 2 bytes in cborData, it contains status. std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), true); @@ -1067,7 +746,7 @@ Return JavacardKeymaster4Device::deleteKey(const hidl_vec& k std::vector cborData = array.encode(); errorCode = sendData(Instruction::INS_DELETE_KEY_CMD, cborData, cborOutData); - if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + if(errorCode == ErrorCode::OK) { //Skip last 2 bytes in cborData, it contains status. std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), true); @@ -1083,7 +762,7 @@ Return JavacardKeymaster4Device::deleteAllKeys() { errorCode = sendData(Instruction::INS_DELETE_ALL_KEYS_CMD, input, cborOutData); - if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + if(errorCode == ErrorCode::OK) { //Skip last 2 bytes in cborData, it contains status. std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), true); @@ -1099,7 +778,7 @@ Return JavacardKeymaster4Device::destroyAttestationIds() { errorCode = sendData(Instruction::INS_DESTROY_ATT_IDS_CMD, input, cborOutData); - if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + if(errorCode == ErrorCode::OK) { //Skip last 2 bytes in cborData, it contains status. std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), true); @@ -1172,7 +851,7 @@ Return JavacardKeymaster4Device::begin(KeyPurpose purpose, const hidl_vec< errorCode = ErrorCode::UNKNOWN_ERROR; if(getTag(keyCharacteristics.hardwareEnforced, Tag::ALGORITHM, param)) { errorCode = sendData(Instruction::INS_BEGIN_OPERATION_CMD, cborData, cborOutData); - if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + if(errorCode == ErrorCode::OK) { //Skip last 2 bytes in cborData, it contains status. std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), true); @@ -1246,7 +925,7 @@ Return JavacardKeymaster4Device::update(uint64_t operationHandle, const hi errorCode = sendData(Instruction::INS_UPDATE_OPERATION_CMD, cborData, cborOutData); - if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + if(errorCode == ErrorCode::OK) { //Skip last 2 bytes in cborData, it contains status. std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), true); @@ -1358,7 +1037,7 @@ Return JavacardKeymaster4Device::finish(uint64_t operationHandle, const hi errorCode = sendData(ins, cborData, cborOutData); - if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + if(errorCode == ErrorCode::OK) { //Skip last 2 bytes in cborData, it contains status. std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), true); @@ -1408,7 +1087,7 @@ Return JavacardKeymaster4Device::abort(uint64_t operationHandle) { errorCode = sendData(Instruction::INS_ABORT_OPERATION_CMD, cborData, cborOutData); - if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + if(errorCode == ErrorCode::OK) { //Skip last 2 bytes in cborData, it contains status. std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), true); @@ -1437,10 +1116,9 @@ Return<::android::hardware::keymaster::V4_1::ErrorCode> JavacardKeymaster4Device cborConverter_.addVerificationToken(array, verificationToken, asn1ParamsVerified); std::vector cborData = array.encode(); - /* TODO DeviceLocked command handled inside HAL */ ret = sendData(Instruction::INS_DEVICE_LOCKED_CMD, cborData, cborOutData); - if((ret == ErrorCode::OK) && (cborOutData.size() > 2)) { + if(ret == ErrorCode::OK) { //Skip last 2 bytes in cborData, it contains status. std::tie(item, errorCode) = cborConverter_.decodeData<::android::hardware::keymaster::V4_1::ErrorCode>(std::vector(cborOutData.begin(), cborOutData.end()-2), true); @@ -1457,7 +1135,7 @@ Return<::android::hardware::keymaster::V4_1::ErrorCode> JavacardKeymaster4Device ErrorCode ret = sendData(Instruction::INS_EARLY_BOOT_ENDED_CMD, cborInput, cborOutData); - if((ret == ErrorCode::OK) && (cborOutData.size() > 2)) { + if(ret == ErrorCode::OK) { //Skip last 2 bytes in cborData, it contains status. std::tie(item, errorCode) = cborConverter_.decodeData<::android::hardware::keymaster::V4_1::ErrorCode>(std::vector(cborOutData.begin(), cborOutData.end()-2), true); diff --git a/HAL/keymaster/4.1/Provision.cpp b/HAL/keymaster/4.1/Provision.cpp new file mode 100644 index 00000000..34b6420d --- /dev/null +++ b/HAL/keymaster/4.1/Provision.cpp @@ -0,0 +1,558 @@ +/* + ** + ** Copyright 2020, The Android Open Source Project + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ROOT_EC_KEY "/data/data/ec_key.der" +#define INTERMEDIATE_EC_CERT "/data/data/ec_cert.der" +#define ROOT_EC_CERT "/data/data/ec_root_cert.der" +#define INS_BEGIN_KM_CMD 0x00 +#define APDU_CLS 0x80 +#define APDU_P1 0x40 +#define APDU_P2 0x00 +#define APDU_RESP_STATUS_OK 0x9000 + +namespace keymaster { +namespace V4_1 { +namespace javacard { + +constexpr uint8_t kFakeKeyAgreementKey[32] = {}; +enum class Instruction { + // Provisioning commands + INS_PROVISION_ATTESTATION_KEY_CMD = INS_BEGIN_KM_CMD+1, + INS_PROVISION_CERT_CHAIN_CMD = INS_BEGIN_KM_CMD+2, + INS_PROVISION_CERT_PARAMS_CMD = INS_BEGIN_KM_CMD+3, + INS_PROVISION_ATTEST_IDS_CMD = INS_BEGIN_KM_CMD+4, + INS_PROVISION_SHARED_SECRET_CMD = INS_BEGIN_KM_CMD+5, + INS_SET_BOOT_PARAMS_CMD = INS_BEGIN_KM_CMD+6, + INS_LOCK_PROVISIONING_CMD = INS_BEGIN_KM_CMD+7, + INS_GET_PROVISION_STATUS_CMD = INS_BEGIN_KM_CMD+8, +}; + +enum ProvisionStatus { + NOT_PROVISIONED = 0x00, + PROVISION_STATUS_ATTESTATION_KEY = 0x01, + PROVISION_STATUS_ATTESTATION_CERT_CHAIN = 0x02, + PROVISION_STATUS_ATTESTATION_CERT_PARAMS = 0x04, + PROVISION_STATUS_ATTEST_IDS = 0x08, + PROVISION_STATUS_SHARED_SECRET = 0x10, + PROVISION_STATUS_BOOT_PARAM = 0x20, + PROVISION_STATUS_PROVISIONING_LOCKED = 0x40, +}; + +// Static function declarations. +static bool readDataFromFile(const char *filename, std::vector& data); +static ErrorCode constructApduMessage(Instruction& ins, std::vector& inputData, std::vector& apduOut, bool +extendedOutput=false); +static ErrorCode sendProvisionData(std::unique_ptr& transport, Instruction ins, std::vector& inData, std::vector& response, bool +extendedOutput = false); +static ErrorCode provisionAttestationKey(std::unique_ptr& transport); +static ErrorCode provisionAttestationCertificateChain(std::unique_ptr& transport); +static ErrorCode provisionAttestationCertificateParams(std::unique_ptr& transport); +static ErrorCode provisionAttestationIDs(std::unique_ptr& transport); +static ErrorCode provisionSharedSecret(std::unique_ptr& transport); +static ErrorCode getProvisionStatus(std::unique_ptr& transport, std::vector& +response); +static ErrorCode lockProvision(std::unique_ptr& transport); +static ErrorCode setBootParameters(std::unique_ptr& transport); +static uint16_t getStatus(std::vector& inputData); +static bool isSEProvisioned(uint64_t status); + +static inline X509* parseDerCertificate(const char* filename) { + X509 *x509 = NULL; + std::vector certData; + + /* Read the Root certificate */ + if(!readDataFromFile(filename, certData)) { + LOG(ERROR) << " Failed to read the Root certificate"; + return NULL; + } + /* Create BIO instance from certificate data */ + BIO *bio = BIO_new_mem_buf(certData.data(), certData.size()); + if(bio == NULL) { + LOG(ERROR) << " Failed to create BIO from buffer."; + return NULL; + } + /* Create X509 instance from BIO */ + x509 = d2i_X509_bio(bio, NULL); + if(x509 == NULL) { + LOG(ERROR) << " Failed to get X509 instance from BIO."; + return NULL; + } + BIO_free(bio); + return x509; +} + +static inline void getDerSubjectName(X509* x509, std::vector& subject) { + uint8_t *subjectDer = NULL; + X509_NAME* asn1Subject = X509_get_subject_name(x509); + if(asn1Subject == NULL) { + LOG(ERROR) << " Failed to read the subject."; + return; + } + /* Convert X509_NAME to der encoded subject */ + int len = i2d_X509_NAME(asn1Subject, &subjectDer); + if (len < 0) { + LOG(ERROR) << " Failed to get readable name from X509_NAME."; + return; + } + subject.insert(subject.begin(), subjectDer, subjectDer+len); +} + +static inline void getAuthorityKeyIdentifier(X509* x509, std::vector& authKeyId) { + long xlen; + int tag, xclass; + + int loc = X509_get_ext_by_NID(x509, NID_authority_key_identifier, -1); + X509_EXTENSION *ext = X509_get_ext(x509, loc); + if(ext == NULL) { + LOG(ERROR) << " Failed to read authority key identifier."; + return; + } + + ASN1_OCTET_STRING *asn1AuthKeyId = X509_EXTENSION_get_data(ext); + const uint8_t *strAuthKeyId = ASN1_STRING_get0_data(asn1AuthKeyId); + int strAuthKeyIdLen = ASN1_STRING_length(asn1AuthKeyId); + int ret = ASN1_get_object(&strAuthKeyId, &xlen, &tag, &xclass, strAuthKeyIdLen); + if (ret == 0x80 || strAuthKeyId == NULL) { + LOG(ERROR) << "Failed to get the auth key identifier from ASN1 sequence."; + return; + } + authKeyId.insert(authKeyId.begin(), strAuthKeyId, strAuthKeyId + xlen); +} + +static inline void getNotAfter(X509* x509, std::vector& notAfterDate) { + const ASN1_TIME* notAfter = X509_get0_notAfter(x509); + if(notAfter == NULL) { + LOG(ERROR) << " Failed to read expiry time."; + return; + } + int strNotAfterLen = ASN1_STRING_length(notAfter); + const uint8_t *strNotAfter = ASN1_STRING_get0_data(notAfter); + if(strNotAfter == NULL) { + LOG(ERROR) << " Failed to read expiry time from ASN1 string."; + return; + } + notAfterDate.insert(notAfterDate.begin(), strNotAfter, strNotAfter + strNotAfterLen); +} + +static uint16_t getStatus(std::vector& inputData) { + //Last two bytes are the status SW0SW1 + return (inputData.at(inputData.size()-2) << 8) | (inputData.at(inputData.size()-1)); +} + +static bool readDataFromFile(const char *filename, std::vector& data) { + FILE *fp; + bool ret = true; + fp = fopen(filename, "rb"); + if(fp == NULL) { + LOG(ERROR) << "Failed to open file: " << filename; + return false; + } + fseek(fp, 0L, SEEK_END); + long int filesize = ftell(fp); + rewind(fp); + std::unique_ptr buf(new uint8_t[filesize]); + if( 0 == fread(buf.get(), filesize, 1, fp)) { + LOG(ERROR) << "No Content in the file: " << filename; + ret = false; + } + if(true == ret) { + //data.insert(data.begin(), buf.get(), buf.get() + filesize); + data.insert(data.end(), buf.get(), buf.get() + filesize); + } + fclose(fp); + return ret; +} + +static ErrorCode constructApduMessage(Instruction& ins, std::vector& inputData, std::vector& apduOut, bool +extendedOutput) { + apduOut.push_back(static_cast(APDU_CLS)); //CLS + apduOut.push_back(static_cast(ins)); //INS + apduOut.push_back(static_cast(APDU_P1)); //P1 + apduOut.push_back(static_cast(APDU_P2)); //P2 + + if(UCHAR_MAX < inputData.size() && USHRT_MAX >= inputData.size()) { + //Extended length 3 bytes, starts with 0x00 + apduOut.push_back(static_cast(0x00)); + apduOut.push_back(static_cast(inputData.size() >> 8)); + apduOut.push_back(static_cast(inputData.size() & 0xFF)); + //Data + apduOut.insert(apduOut.end(), inputData.begin(), inputData.end()); + //Expected length of output + apduOut.push_back(static_cast(0x00)); + apduOut.push_back(static_cast(0x00)); + apduOut.push_back(static_cast(0x00));//Accepting complete length of output at a time + } else if(0 <= inputData.size() && UCHAR_MAX >= inputData.size()) { + //Short length + apduOut.push_back(static_cast(inputData.size())); + //Data + if(inputData.size() > 0) + apduOut.insert(apduOut.end(), inputData.begin(), inputData.end()); + //Expected length of output + apduOut.push_back(static_cast(0x00));//Accepting complete length of output at a time + if(extendedOutput) + apduOut.push_back(static_cast(0x00)); + + } else { + return (ErrorCode::INSUFFICIENT_BUFFER_SPACE); + } + + return (ErrorCode::OK);//success +} + + + +static ErrorCode sendProvisionData(std::unique_ptr& transport, Instruction ins, std::vector& inData, std::vector& response, bool +extendedOutput) { + ErrorCode ret = ErrorCode::OK; + std::vector apdu; + CborConverter cborConverter; + std::unique_ptr item; + ret = constructApduMessage(ins, inData, apdu, extendedOutput); + if(ret != ErrorCode::OK) return ret; + + if(!transport->sendData(apdu.data(), apdu.size(), response)) { + return (ErrorCode::SECURE_HW_COMMUNICATION_FAILED); + } + + if((response.size() < 2) || (getStatus(response) != APDU_RESP_STATUS_OK)) { + return (ErrorCode::UNKNOWN_ERROR); + } + + if((response.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, ret) = cborConverter.decodeData(std::vector(response.begin(), response.end()-2), + true); + } else { + ret = ErrorCode::UNKNOWN_ERROR; + } + + return ret; +} + +static ErrorCode provisionAttestationKey(std::unique_ptr& transport) { + ErrorCode errorCode = ErrorCode::OK; + CborConverter cborConverter; + cppbor::Array array; + cppbor::Array subArray; + std::vector data; + std::vector privKey; + std::vector pubKey; + Instruction ins = Instruction::INS_PROVISION_ATTESTATION_KEY_CMD; + EcCurve curve; + std::vector response; + + AuthorizationSet authSetKeyParams(AuthorizationSetBuilder() + .Authorization(TAG_ALGORITHM, KM_ALGORITHM_EC) + .Authorization(TAG_DIGEST, KM_DIGEST_SHA_2_256) + .Authorization(TAG_EC_CURVE, KM_EC_CURVE_P_256) + .Authorization(TAG_PURPOSE, static_cast(0x7F))); /* The value 0x7F is not present in types.hal */ + // Read the ECKey from the file. + hidl_vec keyParams = kmParamSet2Hidl(authSetKeyParams); + + if(!readDataFromFile(ROOT_EC_KEY, data)) { + LOG(ERROR) << " Failed to read the Root rsa key"; + return ErrorCode::UNKNOWN_ERROR; + } + if(ErrorCode::OK != (errorCode = ecRawKeyFromPKCS8(data, privKey, pubKey, curve))) { + return errorCode; + } + subArray.add(privKey); + subArray.add(pubKey); + std::vector encodedArray = subArray.encode(); + cppbor::Bstr bstr(encodedArray.begin(), encodedArray.end()); + + //Encode data. + cborConverter.addKeyparameters(array, keyParams); + array.add(static_cast(KeyFormat::RAW)); + array.add(bstr); + + std::vector cborData = array.encode(); + + if(ErrorCode::OK != (errorCode = sendProvisionData(transport, ins, cborData, response))) { + return errorCode; + } + return errorCode; +} + +static ErrorCode provisionAttestationCertificateChain(std::unique_ptr& transport) { + ErrorCode errorCode = ErrorCode::OK; + cppbor::Array array; + Instruction ins = Instruction::INS_PROVISION_CERT_CHAIN_CMD; + std::vector response; + + std::vector certData; + /* Read the Root certificate */ + if(!readDataFromFile(INTERMEDIATE_EC_CERT, certData)) { + LOG(ERROR) << " Failed to read the Root certificate"; + return (ErrorCode::UNKNOWN_ERROR); + } + if(!readDataFromFile(ROOT_EC_CERT, certData)) { + LOG(ERROR) << " Failed to read the Root certificate"; + return (ErrorCode::UNKNOWN_ERROR); + } + cppbor::Bstr certChain(certData.begin(), certData.end()); + std::vector cborData = certChain.encode(); + + if(ErrorCode::OK != (errorCode = sendProvisionData(transport, ins, cborData, response))) { + return errorCode; + } + return errorCode; +} + +static ErrorCode provisionAttestationCertificateParams(std::unique_ptr& transport) { + ErrorCode errorCode = ErrorCode::OK; + cppbor::Array array; + Instruction ins = Instruction::INS_PROVISION_CERT_PARAMS_CMD; + std::vector response; + X509 *x509 = NULL; + std::vector subject; + std::vector authorityKeyIdentifier; + std::vector notAfter; + + /* Subject, AuthorityKeyIdentifier and Expirty time of the root certificate are required by javacard. */ + /* Get X509 certificate instance for the root certificate.*/ + if(NULL == (x509 = parseDerCertificate(INTERMEDIATE_EC_CERT))) { + return errorCode; + } + + /* Get subject in DER */ + getDerSubjectName(x509, subject); + /* Get AuthorityKeyIdentifier */ + getAuthorityKeyIdentifier(x509, authorityKeyIdentifier); + /* Get Expirty Time */ + getNotAfter(x509, notAfter); + /*Free X509 */ + X509_free(x509); + + array = cppbor::Array(); + array.add(subject); + array.add(notAfter); + array.add(authorityKeyIdentifier); + std::vector cborData = array.encode(); + + if(ErrorCode::OK != (errorCode = sendProvisionData(transport, ins, cborData, response))) { + return errorCode; + } + return errorCode; +} + + +static ErrorCode provisionAttestationIDs(std::unique_ptr& transport) { + ErrorCode errorCode = ErrorCode::OK; + CborConverter cborConverter; + cppbor::Array array; + Instruction ins = Instruction::INS_PROVISION_ATTEST_IDS_CMD; + std::vector response; + + std::string brand("Google"); + std::string device("Pixel 3A"); + std::string product("Pixel"); + std::string serial("UGYJFDjFeRuBEH"); + std::string imei("987080543071019"); + std::string meid("27863510227963"); + std::string manufacturer("Foxconn"); + std::string model("HD1121"); + + AuthorizationSet authSetAttestParams(AuthorizationSetBuilder() + .Authorization(TAG_ATTESTATION_ID_BRAND, brand.data(), brand.size()) + .Authorization(TAG_ATTESTATION_ID_DEVICE, device.data(), device.size()) + .Authorization(TAG_ATTESTATION_ID_PRODUCT, product.data(), product.size()) + .Authorization(TAG_ATTESTATION_ID_SERIAL, serial.data(), serial.size()) + .Authorization(TAG_ATTESTATION_ID_IMEI, imei.data(), imei.size()) + .Authorization(TAG_ATTESTATION_ID_MEID, meid.data(), meid.size()) + .Authorization(TAG_ATTESTATION_ID_MANUFACTURER, manufacturer.data(), manufacturer.size()) + .Authorization(TAG_ATTESTATION_ID_MODEL, model.data(), model.size())); + + hidl_vec attestParams = kmParamSet2Hidl(authSetAttestParams); + + array = cppbor::Array(); + cborConverter.addKeyparameters(array, attestParams); + std::vector cborData = array.encode(); + + if(ErrorCode::OK != (errorCode = sendProvisionData(transport, ins, cborData, response))) { + return errorCode; + } + return errorCode; +} + +static ErrorCode provisionSharedSecret(std::unique_ptr& transport) { + ErrorCode errorCode = ErrorCode::OK; + cppbor::Array array; + Instruction ins = Instruction::INS_PROVISION_SHARED_SECRET_CMD; + std::vector response; + std::vector masterKey(kFakeKeyAgreementKey, kFakeKeyAgreementKey + + sizeof(kFakeKeyAgreementKey)/sizeof(kFakeKeyAgreementKey[0])); + + array = cppbor::Array(); + array.add(masterKey); + std::vector cborData = array.encode(); + + if(ErrorCode::OK != (errorCode = sendProvisionData(transport, ins, cborData, response))) { + return errorCode; + } + return errorCode; +} + +static ErrorCode getProvisionStatus(std::unique_ptr& transport, std::vector& +response) { + ErrorCode errorCode = ErrorCode::OK; + Instruction ins = Instruction::INS_GET_PROVISION_STATUS_CMD; + std::vector cborData; + + if(ErrorCode::OK != (errorCode = sendProvisionData(transport, ins, cborData, response))) { + return errorCode; + } + return errorCode; + +} + +static ErrorCode lockProvision(std::unique_ptr& transport) { + ErrorCode errorCode = ErrorCode::OK; + Instruction ins = Instruction::INS_LOCK_PROVISIONING_CMD; + std::vector cborData; + std::vector response; + + if(ErrorCode::OK != (errorCode = sendProvisionData(transport, ins, cborData, response))) { + return errorCode; + } + return errorCode; +} + +static ErrorCode setBootParameters(std::unique_ptr& transport) { + ErrorCode errorCode = ErrorCode::OK; + std::vector verifiedBootKey(32, 0); + std::vector verifiedBootKeyHash(32, 0); + uint32_t vendorPatchLevel = 0; + uint32_t bootPatchLevel = 0; + cppbor::Array array; + std::vector apdu; + std::vector response; + Instruction ins = Instruction::INS_SET_BOOT_PARAMS_CMD; + keymaster_verified_boot_t kmVerifiedBoot = KM_VERIFIED_BOOT_UNVERIFIED; + + array.add(GetOsVersion()). + add(GetOsPatchlevel()). + add(vendorPatchLevel). + add(bootPatchLevel). + /* Verified Boot Key */ + add(verifiedBootKey). + /* Verified Boot Hash */ + add(verifiedBootKeyHash). + /* boot state */ + add(static_cast(kmVerifiedBoot)). + /* device locked */ + add(0); + + std::vector cborData = array.encode(); + + if(ErrorCode::OK != (errorCode = sendProvisionData(transport, ins, cborData, response))) { + return errorCode; + } + return errorCode; +} + +static bool isSEProvisioned(uint64_t status) { + bool ret = true; + + if(status != (ProvisionStatus::PROVISION_STATUS_ATTESTATION_KEY | ProvisionStatus::PROVISION_STATUS_ATTESTATION_CERT_CHAIN | + ProvisionStatus::PROVISION_STATUS_ATTESTATION_CERT_PARAMS | ProvisionStatus::PROVISION_STATUS_ATTEST_IDS | + ProvisionStatus::PROVISION_STATUS_SHARED_SECRET | ProvisionStatus::PROVISION_STATUS_BOOT_PARAM + |ProvisionStatus::PROVISION_STATUS_PROVISIONING_LOCKED)) { + ret = false; + } + return ret; +} + +ErrorCode provision(std::unique_ptr& transport) { + std::vector response; + std::unique_ptr item; + CborConverter cborConverter; + ErrorCode errorCode = ErrorCode::OK; + + //Get Provision status. + if(ErrorCode::OK != (errorCode = getProvisionStatus(transport, response))) { + return errorCode; + } + + //Check if SE is provisioned. + std::tie(item, errorCode) = cborConverter.decodeData(std::vector(response.begin(), response.end()-2), + true); + if(item != NULL) { + uint64_t status; + + if(!cborConverter.getUint64(item, 1, status)) + return ErrorCode::UNKNOWN_ERROR; + + if(isSEProvisioned(status)) { + return ErrorCode::OK; //SE is Provisioned. + } + + } else { + return ErrorCode::UNKNOWN_ERROR; + } + + //SE not provisioned so Provision the SE. + + //Provision Attestation Key. + if(ErrorCode::OK != (errorCode = provisionAttestationKey(transport))) { + return errorCode; + } + //Provision Attestation certificate chain. + if(ErrorCode::OK != (errorCode = provisionAttestationCertificateChain(transport))) { + return errorCode; + } + //Provision certificate parameters. + if(ErrorCode::OK != (errorCode = provisionAttestationCertificateParams(transport))) { + return errorCode; + } + //Provision Attestation IDs. + if(ErrorCode::OK != (errorCode = provisionAttestationIDs(transport))) { + return errorCode; + } + //Provision Shared secret. + if(ErrorCode::OK != (errorCode = provisionSharedSecret(transport))) { + return errorCode; + } + //Set Boot parameters. + if(ErrorCode::OK != (errorCode = setBootParameters(transport))) { + return errorCode; + } + //Lock the provisioning. + if(ErrorCode::OK != (errorCode = lockProvision(transport))) { + return errorCode; + } + //return OK + return errorCode; +} + +} // namespace javacard +} // namespace V4_1 +} // namespace keymaster diff --git a/HAL/keymaster/Android.bp b/HAL/keymaster/Android.bp index 9f42df54..8b34023d 100644 --- a/HAL/keymaster/Android.bp +++ b/HAL/keymaster/Android.bp @@ -27,6 +27,7 @@ cc_binary { "4.1/JavacardSoftKeymasterContext.cpp", "4.1/JavacardOperationContext.cpp", "4.1/CommonUtils.cpp", + "4.1/Provision.cpp", ], local_include_dirs: [ "include", diff --git a/HAL/keymaster/include/CommonUtils.h b/HAL/keymaster/include/CommonUtils.h index e418fc0c..f08a60c3 100644 --- a/HAL/keymaster/include/CommonUtils.h +++ b/HAL/keymaster/include/CommonUtils.h @@ -86,6 +86,8 @@ pubModulus); ErrorCode ecRawKeyFromPKCS8(const std::vector& pkcs8Blob, std::vector& secret, std::vector& publicKey, EcCurve& eccurve); +ErrorCode getCertificateChain(std::vector& chainBuffer, std::vector>& certChain); + class KmParamSet : public keymaster_key_param_set_t { public: explicit KmParamSet(const hidl_vec& keyParams) diff --git a/HAL/keymaster/include/JavacardKeymaster4Device.h b/HAL/keymaster/include/JavacardKeymaster4Device.h index c7c06ed5..fcfdef0f 100644 --- a/HAL/keymaster/include/JavacardKeymaster4Device.h +++ b/HAL/keymaster/include/JavacardKeymaster4Device.h @@ -85,16 +85,6 @@ class JavacardKeymaster4Device : public IKeymasterDevice { Return deviceLocked(bool passwordOnly, const VerificationToken& verificationToken) override; Return earlyBootEnded() override; - //Set Boot Params - /* This method should be called at the time when HAL is initialized for the first time */ - static ErrorCode setBootParams(uint32_t osVersion, uint32_t osPatchLevel, const std::vector& verifiedBootKey, -std::vector& verifiedBootKeyHash, keymaster_verified_boot_t kmVerifiedBoot, bool deviceLocked); - - //Provision Method - /* Reference for vendor to provision the javacard. This should happen only once at the time of production.*/ - static ErrorCode provision(const hidl_vec& keyParams, KeyFormat keyformat, const hidl_vec& -keyData); - protected: CborConverter cborConverter_; diff --git a/HAL/keymaster/include/Provision.h b/HAL/keymaster/include/Provision.h new file mode 100644 index 00000000..a58c17c6 --- /dev/null +++ b/HAL/keymaster/include/Provision.h @@ -0,0 +1,36 @@ +/* + ** + ** Copyright 2020, The Android Open Source Project + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + + +#ifndef KEYMASTER_V4_1_JAVACARD_PROVISION_H_ +#define KEYMASTER_V4_1_JAVACARD_PROVISION_H_ + +#include "TransportFactory.h" + +namespace keymaster { +namespace V4_1 { +namespace javacard { + +/** + * Provisions the SE. + */ +ErrorCode provision(std::unique_ptr& transport); + +} // namespace javacard +} // namespace V4_1 +} // namespace keymaster +#endif //KEYMASTER_V4_1_JAVACARD_PROVISION_H_