From e4484e9731e4e806bca3984fce219c8afa742ef2 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Mon, 5 Oct 2020 19:36:18 +0100 Subject: [PATCH 01/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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/99] 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_ From fa957d00dcdb398503ba8a43afb7738c8d5af9d6 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Tue, 8 Dec 2020 11:01:05 +0000 Subject: [PATCH 43/99] Added provision_tool source --- HAL/keymaster/4.1/provision_tool.cpp | 449 +++++++++++++++++++++++++++ HAL/keymaster/Android.bp | 26 ++ 2 files changed, 475 insertions(+) create mode 100644 HAL/keymaster/4.1/provision_tool.cpp diff --git a/HAL/keymaster/4.1/provision_tool.cpp b/HAL/keymaster/4.1/provision_tool.cpp new file mode 100644 index 00000000..2c9fb180 --- /dev/null +++ b/HAL/keymaster/4.1/provision_tool.cpp @@ -0,0 +1,449 @@ +/* + ** + ** 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 + +#define BUFFER_MAX_LENGTH 256 +#define SB_KEYMASTER_SERVICE "javacard" +#define INS_BEGIN_KM_CMD 0x00 +#define APDU_CLS 0x80 +#define APDU_P1 0x40 +#define APDU_P2 0x00 +#define APDU_RESP_STATUS_OK 0x9000 + +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, +}; + +using ::android::hardware::keymaster::V4_0::ErrorCode; +using ::android::hardware::keymaster::V4_0::HardwareAuthenticatorType; +using ::android::hardware::keymaster::V4_0::HardwareAuthToken; +using ::android::hardware::keymaster::V4_0::HmacSharingParameters; +using ::android::hardware::keymaster::V4_0::KeyCharacteristics; +using ::android::hardware::keymaster::V4_0::KeyFormat; +using ::android::hardware::keymaster::V4_0::KeyParameter; +using ::android::hardware::keymaster::V4_0::KeyPurpose; +using ::android::hardware::keymaster::V4_0::OperationHandle; +using ::android::hardware::keymaster::V4_0::SecurityLevel; +using ::android::hardware::keymaster::V4_0::VerificationToken; +using ::android::hardware::keymaster::V4_0::Tag; +using ::android::hardware::keymaster::V4_1::IKeymasterDevice; +using ::android::sp; +using se_transport::TransportFactory; + +static sp sbKeymaster; +static TransportFactory *pTransportFactory; + +constexpr char hex_value[256] = {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, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // '0'..'9' + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'A'..'F' + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'a'..'f' + 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, // + 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, // + 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, // + 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, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +std::string hex2str(const uint8_t* a, size_t len) { + std::string b; + size_t num = len / 2; + b.resize(num); + for (size_t i = 0; i < num; i++) { + b[i] = (hex_value[a[i * 2] & 0xFF] << 4) + (hex_value[a[i * 2 + 1] & 0xFF]); + } + return b; +} + +//static function declarations. +static ErrorCode constructApduMessage(Instruction& ins, std::vector& inputData, std::vector& apduOut, bool +extendedOutput); +static ErrorCode sendProvisionData(Instruction ins, std::vector& inData, std::vector& response, bool +extendedOutput); +static Tag mapAttestKeyToAttestTag(const char* key); + + + +static inline 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 inline TransportFactory* getTransportFactoryInstance() { + if(pTransportFactory == nullptr) { + pTransportFactory = new se_transport::TransportFactory( + android::base::GetBoolProperty("ro.kernel.qemu", false)); + pTransportFactory->openConnection(); + } + return pTransportFactory; +} + +static Tag mapAttestKeyToAttestTag(const char* key) { + //keymaster_tag_t tag = KM_TAG_INVALID; + Tag tag = Tag::INVALID; + std::string keyStr(key); + + if (0 == keyStr.compare("brand")) { + tag = Tag::ATTESTATION_ID_BRAND; + } else if(0 == keyStr.compare("device")) { + tag = Tag::ATTESTATION_ID_DEVICE; + } else if(0 == keyStr.compare("product")) { + tag = Tag::ATTESTATION_ID_PRODUCT; + } else if(0 == keyStr.compare("serial")) { + tag = Tag::ATTESTATION_ID_SERIAL; + } else if(0 == keyStr.compare("imei")) { + tag = Tag::ATTESTATION_ID_IMEI; + } else if(0 == keyStr.compare("meid")) { + tag = Tag::ATTESTATION_ID_MEID; + } else if(0 == keyStr.compare("manufacturer")) { + tag = Tag::ATTESTATION_ID_MANUFACTURER; + } else if(0 == keyStr.compare("model")) { + tag = Tag::ATTESTATION_ID_MODEL; + } + return tag; +} + +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(Instruction ins, std::vector& inData, std::vector& response, bool +extendedOutput=false) { + 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(!pTransportFactory->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; +} + +void usage() { + printf("Usage:\n"); + printf("provision --attest_ids --shared_secret <32 bytes secret> --set_boot_params --lock_provision" + "--provision_status\n"); + printf("\n\n"); + printf("Options:\n"); + printf("-h, --help show this help message and exit.\n"); + printf("-a, --attest_ids FILE \n"); + printf("\t Syntax for attest_ids inside the file:\n"); + printf("\t brand=Google\n"); + printf("\t device=Pixel 3A\n"); + printf("\t product=Pixel\n"); + printf("\t serial=UGYJFDjFeRuBEH\n"); + printf("\t imei=987080543071019\n"); + printf("\t meid=27863510227963\n"); + printf("\t manufacturer=Foxconn\n"); + printf("\t model=HD1121\n"); + printf("-s, --shared_secret <32 bytes secret> \n"); + //TODO include set_boot_params + printf("\t The value of shared secret should be a 32 bytes in HEX\n"); + printf("-p, --provision_status Prints the provision status.\n"); + printf("-l, --lock_provision Locks the provision commands.\n"); +} + +bool provisionAttestationIds(const char* filename) { + CborConverter cborConverter; + cppbor::Array array; + Instruction ins = Instruction::INS_PROVISION_ATTEST_IDS_CMD; + ErrorCode errorCode = ErrorCode::OK; + std::vector response; + FILE *fp; + char tempChar; + int tempIndex = 0; + uint8_t buf[BUFFER_MAX_LENGTH]; + bool ret = true; + fp = fopen(filename, "rb"); + + if(fp == NULL) { + std::cout << "Failed to open file: " << filename; + return false; + } + std::vector params; + KeyParameter parameter; + Tag tag; + while((tempChar = fgetc(fp))) { + if (tempChar == '\n' || tempChar == EOF) { + buf[tempIndex] = '\0'; + tempIndex = 0; + if(0 != strlen((const char*)buf)) { + std::vector blob(buf, buf + strlen((const char*)buf)); + parameter.blob = std::move(blob); + params.push_back(parameter); + } + parameter = KeyParameter(); + // Decide to break or continue + if(tempChar == EOF) + break; + else + continue; + + } else if (tempChar == '=') { + buf[tempIndex] = '\0'; + tempIndex = 0; + if(Tag::INVALID == (tag = mapAttestKeyToAttestTag((const char*)buf))) { + ret = false; + printf("\n Invalid TAG \n"); + break; + } + parameter.tag = tag; + printf("Key: %s", buf); + continue; + } + buf[tempIndex++] = tempChar; + } + fclose(fp); + if(!ret) + return ret; + + hidl_vec attestParams(params); + + //Encode input data into CBOR. + cborConverter.addKeyparameters(array, attestParams); + std::vector cborData = array.encode(); + + if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { + ret = false; + printf("\n Failed to provision attestation ids error: %d\n", uint32_t(errorCode)); + } + return ret; +} + +bool lockProvision() { + bool ret = true; + cppbor::Array array; + Instruction ins = Instruction::INS_LOCK_PROVISIONING_CMD; + ErrorCode errorCode = ErrorCode::OK; + std::vector cborData; + std::vector response; + printf("\n lock provision\n"); + + + if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { + ret = false; + printf("\n Failed to lock provisioning error: %d\n", uint32_t(errorCode)); + } + return ret; +} + +bool getProvisionStatus() { + bool ret = true; + CborConverter cborConverter; + cppbor::Array array; + Instruction ins = Instruction::INS_GET_PROVISION_STATUS_CMD; + ErrorCode errorCode = ErrorCode::OK; + std::vector cborData; + std::vector response; + std::unique_ptr item; + printf("\nget provision sttus\n"); + + + if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { + ret = false; + printf("\n Failed to get provision status error: %d\n", uint32_t(errorCode)); + } + 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)) { + ret = false; + printf("\n Failed to get the status value \n"); + } else { + printf("\n Current provision status: %ld", status); + } + } + return ret; +} + +bool provisionSharedSecret(const uint8_t* secret) { + bool ret = true; + cppbor::Array array; + Instruction ins = Instruction::INS_PROVISION_SHARED_SECRET_CMD; + ErrorCode errorCode = ErrorCode::OK; + std::vector response; + std::string str = hex2str(secret, strlen((const char*)secret)); + //Length of the secret should be 32 bytes. + if(32 != str.length()) { + return false; + } + std::vector input(str.data(), str.data() + str.length()); + + //Encode input data into CBOR. + array.add(input); + std::vector cborData = array.encode(); + + if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { + ret = false; + printf("\n Failed to provision shared secret error: %d\n", uint32_t(errorCode)); + } + return ret; +} + +int main(int argc, char* argv[]) +{ + int c; + struct option longOpts[] = { + {"attest_ids", required_argument, NULL, 'a'}, + {"shared_secret", required_argument, NULL, 's'}, + {"set_boot_params", required_argument, NULL, 'b'}, + {"provision_status", no_argument, NULL, 'p'}, + {"lock_provision", no_argument, NULL, 'l'}, + {"help", no_argument, NULL, 'h'}, + {0,0,0,0} + }; + sbKeymaster = IKeymasterDevice::getService(SB_KEYMASTER_SERVICE); + + if(NULL == sbKeymaster) { + printf("\n Failed to get StrongBox Keymaster service\n"); + exit(0); + } + pTransportFactory = getTransportFactoryInstance(); + if(NULL == pTransportFactory) { + printf("\n Failed to create transport factory\n"); + exit(0); + } + + if (argc <= 1) { + printf("\n Invalid command \n"); + usage(); + } + + /* getopt_long stores the option index here. */ + while ((c = getopt_long(argc, argv, ":plha:s:", longOpts, NULL)) != -1) { + switch(c) { + case 'a': + printf("\n attest_ids filename:%s\n", optarg); + provisionAttestationIds(optarg); + break; + case 's': + provisionSharedSecret((const uint8_t*)optarg); + break; + case 'p': + getProvisionStatus(); + break; + case 'l': + lockProvision(); + break; + case 'h': + usage(); + break; + case 0: + printf("\n set 0\n"); + break; + case ':': + printf("\n missing argument\n"); + usage(); + break; + case '?': + default: + printf("\n Invalid option\n"); + usage(); + break; + } + } + if(optind < argc) { + usage(); + } + return 0; +} diff --git a/HAL/keymaster/Android.bp b/HAL/keymaster/Android.bp index 8b34023d..0065f70c 100644 --- a/HAL/keymaster/Android.bp +++ b/HAL/keymaster/Android.bp @@ -14,6 +14,32 @@ // +cc_binary { + name: "provision_tool", + relative_install_path: "hw", + vendor: true, + srcs: [ + "4.1/provision_tool.cpp", + "4.1/CommonUtils.cpp", + "4.1/CborConverter.cpp", + ], + shared_libs: [ + "libdl", + "libcutils", + "libutils", + "libbase", + "libhardware", + "libhidlbase", + "libkeymaster_messages", + "libkeymaster_portable", + "android.hardware.keymaster@4.1", + "android.hardware.keymaster@4.0", + "libcppbor", + "libjc_transport", + "libcrypto", + ], +} + cc_binary { name: "android.hardware.keymaster@4.1-javacard.service", relative_install_path: "hw", From 7e0f20611586022aab2a242211374e663cc9d2f6 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Tue, 8 Dec 2020 21:51:41 +0000 Subject: [PATCH 44/99] Fixed the VTS 4.1 EarlyBootEnded usecase with DeleteKey --- .../javacard/keymaster/KMKeymasterApplet.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 43ada045..c0a55751 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -912,12 +912,16 @@ private void processDeleteKeyCmd(APDU apdu) { tmpVariables[2] = KMKeyCharacteristics.exp(); KMArray.cast(tmpVariables[1]).add(KMKeymasterApplet.KEY_BLOB_KEYCHAR, tmpVariables[2]); KMArray.cast(tmpVariables[1]).add(KMKeymasterApplet.KEY_BLOB_PUB_KEY, KMByteBlob.exp()); - data[KEY_BLOB] = - decoder.decodeArray( - tmpVariables[1], - KMByteBlob.cast(data[KEY_BLOB]).getBuffer(), - KMByteBlob.cast(data[KEY_BLOB]).getStartOff(), - KMByteBlob.cast(data[KEY_BLOB]).length()); + try { + data[KEY_BLOB] = decoder.decodeArray(tmpVariables[1], + KMByteBlob.cast(data[KEY_BLOB]).getBuffer(), + KMByteBlob.cast(data[KEY_BLOB]).getStartOff(), + KMByteBlob.cast(data[KEY_BLOB]).length()); + } catch (ISOException e) { + // As per VTS, deleteKey should return KMError.OK but in case if + // input is empty then VTS accepts UNIMPLEMENTED errorCode as well. + KMException.throwIt(KMError.UNIMPLEMENTED); + } tmpVariables[0] = KMArray.cast(data[KEY_BLOB]).length(); if (tmpVariables[0] < 4) { KMException.throwIt(KMError.INVALID_KEY_BLOB); From e6672fdb1fcb412cb6da4d9639bc06dd5c709ca2 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Wed, 9 Dec 2020 23:00:52 +0000 Subject: [PATCH 45/99] 1. Used libjsoncpp for parsing json file 2. taking input from json file 3. Added all the provisiong flow. --- HAL/keymaster/4.1/provision_tool.cpp | 692 ++++++++++++++++++++++----- HAL/keymaster/Android.bp | 1 + HAL/keymaster/sample_json.txt | 25 + 3 files changed, 593 insertions(+), 125 deletions(-) create mode 100644 HAL/keymaster/sample_json.txt diff --git a/HAL/keymaster/4.1/provision_tool.cpp b/HAL/keymaster/4.1/provision_tool.cpp index 2c9fb180..ce698375 100644 --- a/HAL/keymaster/4.1/provision_tool.cpp +++ b/HAL/keymaster/4.1/provision_tool.cpp @@ -16,17 +16,25 @@ */ #include +#include #include #include #include +#include +#include +#include +#include #include #include #include +#include #include #include #include #include #include +#include +#include #define BUFFER_MAX_LENGTH 256 #define SB_KEYMASTER_SERVICE "javacard" @@ -35,6 +43,8 @@ #define APDU_P1 0x40 #define APDU_P2 0x00 #define APDU_RESP_STATUS_OK 0x9000 +#define MAX_ATTEST_IDS_SIZE 8 +#define SHARED_SECRET_SIZE 32 enum class Instruction { // Provisioning commands @@ -60,6 +70,7 @@ enum ProvisionStatus { }; using ::android::hardware::keymaster::V4_0::ErrorCode; +using ::android::hardware::keymaster::V4_0::EcCurve; using ::android::hardware::keymaster::V4_0::HardwareAuthenticatorType; using ::android::hardware::keymaster::V4_0::HardwareAuthToken; using ::android::hardware::keymaster::V4_0::HmacSharingParameters; @@ -77,6 +88,7 @@ using se_transport::TransportFactory; static sp sbKeymaster; static TransportFactory *pTransportFactory; +Json::Value root; constexpr char hex_value[256] = {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, // @@ -95,9 +107,9 @@ constexpr char hex_value[256] = {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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -std::string hex2str(const uint8_t* a, size_t len) { +std::string hex2str(std::string a) { std::string b; - size_t num = len / 2; + size_t num = a.size() / 2; b.resize(num); for (size_t i = 0; i < num; i++) { b[i] = (hex_value[a[i * 2] & 0xFF] << 4) + (hex_value[a[i * 2 + 1] & 0xFF]); @@ -110,9 +122,103 @@ static ErrorCode constructApduMessage(Instruction& ins, std::vector& in extendedOutput); static ErrorCode sendProvisionData(Instruction ins, std::vector& inData, std::vector& response, bool extendedOutput); -static Tag mapAttestKeyToAttestTag(const char* key); +static Tag mapAttestKeyToAttestTag(std::string key); +bool parseJsonFile(const char* filename); +static bool readDataFromFile(const char *filename, std::vector& data) { + FILE *fp; + bool ret = true; + fp = fopen(filename, "rb"); + if(fp == NULL) { + printf("\nFailed to open file: \n"); + 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)) { + printf("\n No content in the file \n"); + ret = false; + } + if(true == ret) { + data.insert(data.end(), buf.get(), buf.get() + filesize); + } + fclose(fp); + return ret; +} + +static inline X509* parseDerCertificate(std::vector& certData) { + X509 *x509 = 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 inline uint16_t getStatus(std::vector& inputData) { //Last two bytes are the status SW0SW1 @@ -128,10 +234,8 @@ static inline TransportFactory* getTransportFactoryInstance() { return pTransportFactory; } -static Tag mapAttestKeyToAttestTag(const char* key) { - //keymaster_tag_t tag = KM_TAG_INVALID; +static Tag mapAttestKeyToAttestTag(std::string keyStr) { Tag tag = Tag::INVALID; - std::string keyStr(key); if (0 == keyStr.compare("brand")) { tag = Tag::ATTESTATION_ID_BRAND; @@ -218,115 +322,205 @@ extendedOutput=false) { } void usage() { - printf("Usage:\n"); - printf("provision --attest_ids --shared_secret <32 bytes secret> --set_boot_params --lock_provision" - "--provision_status\n"); - printf("\n\n"); - printf("Options:\n"); + printf("Usage: provision_tool [options]\n"); + printf("Valid options are:\n"); printf("-h, --help show this help message and exit.\n"); - printf("-a, --attest_ids FILE \n"); - printf("\t Syntax for attest_ids inside the file:\n"); - printf("\t brand=Google\n"); - printf("\t device=Pixel 3A\n"); - printf("\t product=Pixel\n"); - printf("\t serial=UGYJFDjFeRuBEH\n"); - printf("\t imei=987080543071019\n"); - printf("\t meid=27863510227963\n"); - printf("\t manufacturer=Foxconn\n"); - printf("\t model=HD1121\n"); - printf("-s, --shared_secret <32 bytes secret> \n"); - //TODO include set_boot_params - printf("\t The value of shared secret should be a 32 bytes in HEX\n"); - printf("-p, --provision_status Prints the provision status.\n"); - printf("-l, --lock_provision Locks the provision commands.\n"); + printf("-a, --all jsonFile \t Executes all the provision commands \n"); + printf("-k, --attest_key jsonFile \t Provision attestation key \n"); + printf("-c, --cert_chain jsonFile \t Provision attestation certificate chain \n"); + printf("-p, --cert_params jsonFile \t Provision attestation certificate parameters \n"); + printf("-i, --attest_ids jsonFile \t Provision attestation IDs \n"); + printf("-r, --shared_secret jsonFile \t Provion shared secret \n"); + printf("-b, --set_boot_params jsonFile \t Provion boot parameters \n"); + printf("-s, --provision_status \t Prints the provision status.\n"); + printf("-l, --lock_provision \t Locks the provision commands.\n"); } -bool provisionAttestationIds(const char* filename) { - CborConverter cborConverter; - cppbor::Array array; - Instruction ins = Instruction::INS_PROVISION_ATTEST_IDS_CMD; - ErrorCode errorCode = ErrorCode::OK; - std::vector response; - FILE *fp; - char tempChar; - int tempIndex = 0; - uint8_t buf[BUFFER_MAX_LENGTH]; - bool ret = true; - fp = fopen(filename, "rb"); - - if(fp == NULL) { - std::cout << "Failed to open file: " << filename; - return false; - } - std::vector params; - KeyParameter parameter; - Tag tag; - while((tempChar = fgetc(fp))) { - if (tempChar == '\n' || tempChar == EOF) { - buf[tempIndex] = '\0'; - tempIndex = 0; - if(0 != strlen((const char*)buf)) { - std::vector blob(buf, buf + strlen((const char*)buf)); - parameter.blob = std::move(blob); - params.push_back(parameter); - } - parameter = KeyParameter(); - // Decide to break or continue - if(tempChar == EOF) +bool getBootParameterIntValue(Json::Value& bootParamsObj, const char* key, uint32_t *value) { + bool ret = false; + Json::Value val = bootParamsObj[key]; + if(val.empty()) + return ret; + + if(!val.isInt()) + return ret; + + *value = (uint32_t)val.asInt(); + + return true; +} + +bool getBootParameterBlobValue(Json::Value& bootParamsObj, const char* key, std::vector& blob) { + bool ret = false; + Json::Value val = bootParamsObj[key]; + if(val.empty()) + return ret; + + if(!val.isString()) + return ret; + + std::string blobStr = hex2str(val.asString()); + + for(char ch : blobStr) { + blob.push_back((uint8_t)ch); + } + + return true; +} + +bool setBootParameters(const char* filename) { + Json::Value bootParamsObj; + bool ret = false; + + if(!parseJsonFile(filename)) + return ret; + + bootParamsObj = root.get("set_boot_params", bootParamsObj); + if (!bootParamsObj.isNull()) { + cppbor::Array array; + ErrorCode errorCode = ErrorCode::OK; + std::vector apdu; + std::vector response; + Instruction ins = Instruction::INS_SET_BOOT_PARAMS_CMD; + uint32_t value; + std::vector blob; + + if(!getBootParameterIntValue(bootParamsObj, "os_version", &value)) { + printf("\n Invalid value for os_version or os_version tag missing\n"); + return ret; + } + array.add(value); + if(!getBootParameterIntValue(bootParamsObj, "os_patch_level", &value)) { + printf("\n Invalid value for os_patch_level or os_patch_level tag missing\n"); + return ret; + } + array.add(value); + if(!getBootParameterIntValue(bootParamsObj, "vendor_patch_level", &value)) { + printf("\n Invalid value for vendor_patch_level or vendor_patch_level tag missing\n"); + return ret; + } + array.add(value); + if(!getBootParameterIntValue(bootParamsObj, "boot_patch_level", &value)) { + printf("\n Invalid value for boot_patch_level or boot_patch_level tag missing\n"); + return ret; + } + array.add(value); + if(!getBootParameterBlobValue(bootParamsObj, "verified_boot_key", blob)) { + printf("\n Invalid value for verified_boot_key or verified_boot_key tag missing\n"); + return ret; + } + array.add(blob); + blob.clear(); + if(!getBootParameterBlobValue(bootParamsObj, "verified_boot_key_hash", blob)) { + printf("\n Invalid value for verified_boot_key_hash or verified_boot_key_hash tag missing\n"); + return ret; + } + array.add(blob); + blob.clear(); + if(!getBootParameterIntValue(bootParamsObj, "boot_state", &value)) { + printf("\n Invalid value for boot_state or boot_state tag missing\n"); + return ret; + } + array.add(value); + if(!getBootParameterIntValue(bootParamsObj, "device_locked", &value)) { + printf("\n Invalid value for device_locked or device_locked tag missing\n"); + return ret; + } + array.add(value); + + std::vector cborData = array.encode(); + + if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { + printf("\n Failed to set boot parameters errorCode:%d\n", errorCode); + return ret; + } + + } else { + return ret; + } + printf("\n SE successfully accepted boot paramters \n"); + return true; +} + +bool provisionAttestationIds(const char *filename) { + Json::Value attestIds; + bool ret = false; + + if(!parseJsonFile(filename)) + return ret; + + attestIds = root.get("attest_ids", attestIds); + if (!attestIds.isNull()) { + if (attestIds.size() != MAX_ATTEST_IDS_SIZE) { + return ret; + } + Json::Value value; + std::vector temp; + int i = 0; + std::vector params(attestIds.size()); + Json::Value::Members keys = attestIds.getMemberNames(); + Tag tag; + for(std::string key : keys) { + if(Tag::INVALID == (tag = mapAttestKeyToAttestTag(key))) { break; - else - continue; - - } else if (tempChar == '=') { - buf[tempIndex] = '\0'; - tempIndex = 0; - if(Tag::INVALID == (tag = mapAttestKeyToAttestTag((const char*)buf))) { - ret = false; - printf("\n Invalid TAG \n"); + } + value = attestIds[key]; + if(value.empty()) { break; } - parameter.tag = tag; - printf("Key: %s", buf); - continue; + params[i].tag = tag; + for(char ch : value.asString()) { + temp.push_back((uint8_t)ch); + } + params[i].blob.resize(temp.size()); + params[i].blob = temp; + temp.clear(); + i++; } - buf[tempIndex++] = tempChar; - } - fclose(fp); - if(!ret) - return ret; - hidl_vec attestParams(params); + if(i != MAX_ATTEST_IDS_SIZE) + return ret; - //Encode input data into CBOR. - cborConverter.addKeyparameters(array, attestParams); - std::vector cborData = array.encode(); + CborConverter cborConverter; + cppbor::Array array; + Instruction ins = Instruction::INS_PROVISION_ATTEST_IDS_CMD; + ErrorCode errorCode = ErrorCode::OK; + std::vector response; + hidl_vec attestParams(params); - if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { - ret = false; - printf("\n Failed to provision attestation ids error: %d\n", uint32_t(errorCode)); + //Encode input data into CBOR. + cborConverter.addKeyparameters(array, attestParams); + std::vector cborData = array.encode(); + + if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { + printf("\n Failed to provision attestation ids error: %d\n", uint32_t(errorCode)); + return ret; + } + } else { + return ret; } - return ret; + printf("\n provisioned attestation ids successfully \n"); + return true; } bool lockProvision() { - bool ret = true; + bool ret = false; cppbor::Array array; Instruction ins = Instruction::INS_LOCK_PROVISIONING_CMD; ErrorCode errorCode = ErrorCode::OK; std::vector cborData; std::vector response; - printf("\n lock provision\n"); - if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { - ret = false; printf("\n Failed to lock provisioning error: %d\n", uint32_t(errorCode)); + return ret; } - return ret; + printf("\n Successfully locked provisioning process. Now SE doesn't accept any further provision commands. \n"); + return true; } bool getProvisionStatus() { - bool ret = true; + bool ret = false; CborConverter cborConverter; cppbor::Array array; Instruction ins = Instruction::INS_GET_PROVISION_STATUS_CMD; @@ -334,12 +528,10 @@ bool getProvisionStatus() { std::vector cborData; std::vector response; std::unique_ptr item; - printf("\nget provision sttus\n"); - if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { - ret = false; printf("\n Failed to get provision status error: %d\n", uint32_t(errorCode)); + return ret; } std::tie(item, errorCode) = cborConverter.decodeData(std::vector(response.begin(), response.end()-2), true); @@ -347,53 +539,287 @@ bool getProvisionStatus() { uint64_t status; if(!cborConverter.getUint64(item, 1, status)) { - ret = false; printf("\n Failed to get the status value \n"); + return ret; } else { - printf("\n Current provision status: %ld", status); + printf("\nCurrent provision status: %ld\n", status); } + } else { + return ret; } - return ret; + return true; } -bool provisionSharedSecret(const uint8_t* secret) { - bool ret = true; - cppbor::Array array; - Instruction ins = Instruction::INS_PROVISION_SHARED_SECRET_CMD; - ErrorCode errorCode = ErrorCode::OK; - std::vector response; - std::string str = hex2str(secret, strlen((const char*)secret)); - //Length of the secret should be 32 bytes. - if(32 != str.length()) { +bool provisionSharedSecret(const char* filename) { + Json::Value sharedSecret; + bool ret = false; + + if(!parseJsonFile(filename)) + return ret; + + sharedSecret = root.get("shared_secret", sharedSecret); + if (!sharedSecret.isNull()) { + cppbor::Array array; + Instruction ins = Instruction::INS_PROVISION_SHARED_SECRET_CMD; + ErrorCode errorCode = ErrorCode::OK; + std::vector response; + std::string str = sharedSecret.asString(); + std::string secret = hex2str(str); + + //Length of the secret should be 32 bytes. + if(SHARED_SECRET_SIZE != secret.size()) { + return ret; + } + std::vector input(secret.data(), secret.data() + secret.length()); + + //Encode input data into CBOR. + array.add(input); + std::vector cborData = array.encode(); + + if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { + printf("\n Failed to provision shared secret error: %d\n", uint32_t(errorCode)); + return ret; + } + } else { + return ret; + } + printf("\n Provisioned shared secret successfully \n"); + return true; +} + +static bool provisionAttestationKey(const char* filename) { + Json::Value keyFile; + bool ret = false; + + if(!parseJsonFile(filename)) + return ret; + + keyFile = root.get("attest_key", keyFile); + if (!keyFile.isNull()) { + 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; + + std::string keyFileName = keyFile.asString(); + if(!readDataFromFile(keyFileName.data(), data)) { + printf("\n Failed to read the Root ec key\n"); + return ret; + } + keymaster::AuthorizationSet authSetKeyParams(keymaster::AuthorizationSetBuilder() + .Authorization(keymaster::TAG_ALGORITHM, KM_ALGORITHM_EC) + .Authorization(keymaster::TAG_DIGEST, KM_DIGEST_SHA_2_256) + .Authorization(keymaster::TAG_EC_CURVE, KM_EC_CURVE_P_256) + .Authorization(keymaster::TAG_PURPOSE, static_cast(0x7F))); /* The value 0x7F is not present in types.hal */ + // Read the ECKey from the file. + hidl_vec keyParams = keymaster::V4_1::javacard::kmParamSet2Hidl(authSetKeyParams); + + if(ErrorCode::OK != (errorCode = keymaster::V4_1::javacard::ecRawKeyFromPKCS8(data, privKey, pubKey, curve))) { + printf("\n Failed to convert PKCS8 to RAW key\n"); + return ret; + } + 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(ins, cborData, response))) { + printf("\n Failed to provision attestation key\n"); + return ret; + } + } else { + return ret; + } + printf("\n Provisioned attestation key successfully\n"); + return true; +} + +bool provisionAttestationCertificateChain(const char* filename) { + Json::Value certChainFile; + bool ret = false; + + if(!parseJsonFile(filename)) + return ret; + + certChainFile = root.get("attest_cert_chain", certChainFile); + if (!certChainFile.isNull()) { + ErrorCode errorCode = ErrorCode::OK; + cppbor::Array array; + Instruction ins = Instruction::INS_PROVISION_CERT_CHAIN_CMD; + std::vector response; + + std::vector certData; + std::string strCertChain = certChainFile.asString(); + /* Read the Root certificate */ + if(!readDataFromFile(strCertChain.data(), certData)) { + printf("\n Failed to read the Root certificate\n"); + return ret; + } + cppbor::Bstr certChain(certData.begin(), certData.end()); + std::vector cborData = certChain.encode(); + + if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { + printf("\n Failed to provision cert chain errorCode:%d\n", static_cast(errorCode)); + return ret; + } + } else { + return ret; + } + printf("\n Provisioned attestation certificate chain successfully\n"); + return true; +} + +bool provisionAttestationCertificateParams(const char* filename) { + Json::Value certChainFile; + bool ret = false; + + if(!parseJsonFile(filename)) + return ret; + + certChainFile = root.get("attest_cert_chain", certChainFile); + if (!certChainFile.isNull()) { + 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; + std::vector certData; + std::vector> certChain; + + + std::string strCertChain = certChainFile.asString(); + /* Read the Root certificate */ + if(!readDataFromFile(strCertChain.data(), certData)) { + printf("\n Failed to read the Root certificate\n"); + return ret; + } + + // Get first certificate from chain of certificates. + if(ErrorCode::OK != (errorCode =keymaster::V4_1::javacard::getCertificateChain(certData, certChain))) { + printf("\n Failed to parse the certificate chain \n"); + return ret; + } + + if(certChain.size() == 0) { + printf("\n Length of the certificate chain is 0\n"); + return ret; + } + + + /* 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(certChain[0]))) { + printf("\n Failed to parse the DER certificate \n"); + return ret; + } + + /* Get subject in DER */ + getDerSubjectName(x509, subject); + /* Get AuthorityKeyIdentifier */ + getAuthorityKeyIdentifier(x509, authorityKeyIdentifier); + /* Get Expirty Time */ + getNotAfter(x509, notAfter); + /*Free X509 */ + X509_free(x509); + + array.add(subject); + array.add(notAfter); + array.add(authorityKeyIdentifier); + std::vector cborData = array.encode(); + + if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { + printf("\n Failed to provision cert params errorCode:%d\n", static_cast(errorCode)); + return ret; + } + } else { + return ret; + } + printf("\n Provisioned attestation certificate parameters successfully\n"); + return true; +} + +bool provision(const char* filename) { + + if(!provisionAttestationKey(filename)) { + printf("\n Failed to provision attestation Key\n"); + return false; + } + if(!provisionAttestationCertificateChain(filename)) { + printf("\n Failed to provision certificate chain\n"); + return false; + } + if(!provisionAttestationCertificateParams(filename)) { + printf("\n Failed to provision certificate paramters\n"); return false; } - std::vector input(str.data(), str.data() + str.length()); + if(!provisionSharedSecret(filename)) { + printf("\n Failed to provision shared secret\n"); + return false; + } + if(!provisionAttestationIds(filename)) { + printf("\n Failed to provision attestation ids\n"); + return false; + } + if(!setBootParameters(filename)) { + printf("\n Failed to set boot parameters\n"); + return false; + } + return true; +} - //Encode input data into CBOR. - array.add(input); - std::vector cborData = array.encode(); +bool parseJsonFile(const char* filename) { + std::stringstream buffer; + Json::Reader jsonReader; - if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { - ret = false; - printf("\n Failed to provision shared secret error: %d\n", uint32_t(errorCode)); + if(!root.empty()) { + printf("\n Already parsed \n"); + return true; + } + std::ifstream stream(filename); + buffer << stream.rdbuf(); + if(jsonReader.parse(buffer.str(), root)) { + printf("\n Parsed json file successfully\n"); + return true; + } else { + printf("\n Failed to parse json file\n"); + return false; } - return ret; } int main(int argc, char* argv[]) { int c; struct option longOpts[] = { - {"attest_ids", required_argument, NULL, 'a'}, - {"shared_secret", required_argument, NULL, 's'}, + {"all", required_argument, NULL, 'a'}, + {"attest_key", required_argument, NULL, 'k'}, + {"cert_chain", required_argument, NULL, 'c'}, + {"cert_params", required_argument, NULL,'p'}, + {"attest_ids", required_argument, NULL, 'i'}, + {"shared_secret", required_argument, NULL, 'r'}, {"set_boot_params", required_argument, NULL, 'b'}, - {"provision_status", no_argument, NULL, 'p'}, + {"provision_status", no_argument, NULL, 's'}, {"lock_provision", no_argument, NULL, 'l'}, {"help", no_argument, NULL, 'h'}, {0,0,0,0} }; - sbKeymaster = IKeymasterDevice::getService(SB_KEYMASTER_SERVICE); + sbKeymaster = IKeymasterDevice::getService(SB_KEYMASTER_SERVICE); if(NULL == sbKeymaster) { printf("\n Failed to get StrongBox Keymaster service\n"); exit(0); @@ -410,16 +836,35 @@ int main(int argc, char* argv[]) } /* getopt_long stores the option index here. */ - while ((c = getopt_long(argc, argv, ":plha:s:", longOpts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, ":slha:k:c:p:i:r:b:", longOpts, NULL)) != -1) { switch(c) { - case 'a': - printf("\n attest_ids filename:%s\n", optarg); + case 'a': + //all + provision(optarg); + break; + case 'k': + //attest key + provisionAttestationKey(optarg); + break; + case 'c': + //attest certchain + provisionAttestationCertificateChain(optarg); + break; + case 'p': + //attest cert params + provisionAttestationCertificateParams(optarg); + break; + case 'i': provisionAttestationIds(optarg); break; - case 's': - provisionSharedSecret((const uint8_t*)optarg); + case 'r': + provisionSharedSecret(optarg); break; - case 'p': + case 'b': + //set boot params + setBootParameters(optarg); + break; + case 's': getProvisionStatus(); break; case 'l': @@ -428,9 +873,6 @@ int main(int argc, char* argv[]) case 'h': usage(); break; - case 0: - printf("\n set 0\n"); - break; case ':': printf("\n missing argument\n"); usage(); diff --git a/HAL/keymaster/Android.bp b/HAL/keymaster/Android.bp index 0065f70c..c8ccb497 100644 --- a/HAL/keymaster/Android.bp +++ b/HAL/keymaster/Android.bp @@ -37,6 +37,7 @@ cc_binary { "libcppbor", "libjc_transport", "libcrypto", + "libjsoncpp", ], } diff --git a/HAL/keymaster/sample_json.txt b/HAL/keymaster/sample_json.txt new file mode 100644 index 00000000..b65164aa --- /dev/null +++ b/HAL/keymaster/sample_json.txt @@ -0,0 +1,25 @@ +{ + "attest_ids": { + "brand": "Google", + "device": "Pixel 3A", + "product": "Pixel", + "serial": "UGYJFDjFeRuBEH", + "imei": "987080543071019", + "meid": "27863510227963", + "manufacturer": "Foxconn", + "model": "HD1121" + }, + "shared_secret": "0000000000000000000000000000000000000000000000000000000000000000", + "set_boot_params": { + "os_version": 100, + "os_patch_level": 100, + "vendor_patch_level": 0, + "boot_patch_level": 0, + "verified_boot_key": "0000000000000000000000000000000000000000000000000000000000000000", + "verified_boot_key_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "boot_state": 0, + "device_locked": 0 + }, + "attest_key": "/data/data/ec_key.der", + "attest_cert_chain": "/data/data/ec_cert_chain.der" +} From f678ad2f70807f83a280d7f7ab6b8a7c9adee2ea Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Wed, 9 Dec 2020 23:04:04 +0000 Subject: [PATCH 46/99] Clear the certificate chain persisted in memory whenever provisionCertificateChain command gets called multiple times. --- .../android/javacard/keymaster/KMAndroidSEProvider.java | 7 +++++++ .../com/android/javacard/keymaster/KMJCardSimulator.java | 7 +++++++ .../com/android/javacard/keymaster/KMKeymasterApplet.java | 5 +++++ .../src/com/android/javacard/keymaster/KMSEProvider.java | 5 +++++ 4 files changed, 24 insertions(+) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java index 9d9812c1..aba38934 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java @@ -1137,6 +1137,13 @@ public short cmacKdf(byte[] keyMaterial, short keyMaterialStart, return key.getKey(keyBuf, keyStart); } + @Override + public void clearCertificateChain() { + JCSystem.beginTransaction(); + Util.arrayFillNonAtomic(certificateChain, (short)0, CERT_CHAIN_MAX_SIZE, (byte) 0); + JCSystem.commitTransaction(); + } + //This function supports multi-part request data. @Override public void persistPartialCertificateChain(byte[] buf, short offset, short len, short totalLen) { diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java index 70311e51..9c9e71c6 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java @@ -1252,6 +1252,13 @@ public short ecSign256(byte[] secret, short secretStart, short secretLength, outputDataBuf, outputDataStart); } + @Override + public void clearCertificateChain() { + JCSystem.beginTransaction(); + Util.arrayFillNonAtomic(certificateChain, (short)0, CERT_CHAIN_MAX_SIZE, (byte) 0); + JCSystem.commitTransaction(); + } + @Override public void persistPartialCertificateChain(byte[] buf, short offset, short len, short totalLen) { diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index c0a55751..d9691a1e 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -644,6 +644,11 @@ private void processProvisionAttestationCertParams(APDU apdu) { } private void processProvisionAttestationCertChainCmd(APDU apdu) { + tmpVariables[0] = seProvider.getCertificateChainLength(); + if (tmpVariables[0] != 0) { + //Clear the previous certificate chain. + seProvider.clearCertificateChain(); + } byte[] srcBuffer = apdu.getBuffer(); short recvLen = apdu.setIncomingAndReceive(); short srcOffset = apdu.getOffsetCdata(); diff --git a/Applet/src/com/android/javacard/keymaster/KMSEProvider.java b/Applet/src/com/android/javacard/keymaster/KMSEProvider.java index b3e9c266..81b35db2 100644 --- a/Applet/src/com/android/javacard/keymaster/KMSEProvider.java +++ b/Applet/src/com/android/javacard/keymaster/KMSEProvider.java @@ -441,6 +441,11 @@ KMOperation initAsymmetricOperation( */ public void persistPartialCertificateChain(byte[] buf, short offset, short len, short totalLen); + /** + * This operation clears the certificate chain from persistent memory. + */ + public void clearCertificateChain(); + /** * The operation reads the certificate chain from persistent memory. * From a816c1915bd10ab6907fda0f95c0d4749748d120 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Tue, 12 Jan 2021 22:42:34 +0530 Subject: [PATCH 47/99] HAL fixes shared by NXP team. --- .../4.1/JavacardKeymaster4Device.cpp | 104 +++++++++--------- .../4.1/JavacardOperationContext.cpp | 17 ++- HAL/keymaster/Android.bp | 5 + 3 files changed, 73 insertions(+), 53 deletions(-) diff --git a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp index 23583024..71350e9b 100644 --- a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp +++ b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp @@ -304,14 +304,10 @@ Return JavacardKeymaster4Device::getHardwareInfo(getHardwareInfo_cb _hidl_ hidl_string jcKeymasterAuthor; ErrorCode ret = sendData(Instruction::INS_GET_HW_INFO_CMD, input, resp); - if(ret != ErrorCode::OK) { - //Socket not connected. - _hidl_cb(SecurityLevel::STRONGBOX, JAVACARD_KEYMASTER_NAME, JAVACARD_KEYMASTER_AUTHOR); - return Void(); - } else { + if (ret == ErrorCode::OK) { //Skip last 2 bytes in cborData, it contains status. std::tie(item, ret) = cborConverter_.decodeData(std::vector(resp.begin(), resp.end()-2), - true); + false); if (item != nullptr) { std::vector temp; if(!cborConverter_.getUint64(item, 0, securityLevel) || @@ -324,29 +320,23 @@ Return JavacardKeymaster4Device::getHardwareInfo(getHardwareInfo_cb _hidl_ _hidl_cb(static_cast(securityLevel), jcKeymasterName, jcKeymasterAuthor); return Void(); } +#ifdef TRANSCEIVE_VIA_SOCKET + else { + //TODO Should we throw fatal error here.? + _hidl_cb(SecurityLevel::STRONGBOX, JAVACARD_KEYMASTER_NAME, JAVACARD_KEYMASTER_AUTHOR); + return Void(); + } +#endif } Return JavacardKeymaster4Device::getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) { - /* TODO temporary fix: vold daemon calls performHmacKeyAgreement. At that time when vold calls this API there is no - * network connectivity and socket cannot be connected. So as a hack we are calling softkeymaster to getHmacSharing - * parameters. - */ std::vector cborData; std::vector input; 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::OK) { - auto response = softKm_->GetHmacSharingParameters(); - ::android::hardware::keymaster::V4_0::HmacSharingParameters params; - params.seed.setToExternal(const_cast(response.params.seed.data), - response.params.seed.data_length); - static_assert(sizeof(response.params.nonce) == params.nonce.size(), "Nonce sizes don't match"); - memcpy(params.nonce.data(), response.params.nonce, params.nonce.size()); - _hidl_cb(legacy_enum_conversion(response.error), params); - return Void(); - } else { + if (ErrorCode::OK == errorCode) { //Skip last 2 bytes in cborData, it contains status. std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborData.begin(), cborData.end()-2), true); @@ -355,16 +345,26 @@ Return JavacardKeymaster4Device::getHmacSharingParameters(getHmacSharingPa errorCode = ErrorCode::UNKNOWN_ERROR; } } - _hidl_cb(errorCode, hmacSharingParameters); - return Void(); } +#ifdef TRANSCEIVE_VIA_SOCKET + /* TODO temporary fix: vold daemon calls performHmacKeyAgreement. At that time when vold calls this API there is no + * network connectivity and socket cannot be connected. So as a hack we are calling softkeymaster to getHmacSharing + * parameters. + */ + else { + auto response = softKm_->GetHmacSharingParameters(); + hmacSharingParameters.seed.setToExternal(const_cast(response.params.seed.data), + response.params.seed.data_length); + static_assert(sizeof(response.params.nonce) == hmacSharingParameters.nonce.size(), "Nonce sizes don't match"); + memcpy(hmacSharingParameters.nonce.data(), response.params.nonce, hmacSharingParameters.nonce.size()); + errorCode = legacy_enum_conversion(response.error); + } +#endif + _hidl_cb(errorCode, hmacSharingParameters); + return Void(); } Return JavacardKeymaster4Device::computeSharedHmac(const hidl_vec& params, computeSharedHmac_cb _hidl_cb) { - /* TODO temporary fix: vold daemon calls performHmacKeyAgreement. At that time when vold calls this API there is no - * network connectivity and socket cannot be connected. So as a hack we are calling softkeymaster to - * computeSharedHmac. - */ cppbor::Array array; std::unique_ptr item; std::vector cborOutData; @@ -387,7 +387,25 @@ Return JavacardKeymaster4Device::computeSharedHmac(const hidl_vec cborData = array.encode(); errorCode = sendData(Instruction::INS_COMPUTE_SHARED_HMAC_CMD, cborData, cborOutData); - if(errorCode != ErrorCode::OK) { + if (ErrorCode::OK == errorCode) { + //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; + } + } + } +#ifdef TRANSCEIVE_VIA_SOCKET + /* TODO temporary fix: vold daemon calls performHmacKeyAgreement. At that time when vold calls this API there is no + * network connectivity and socket cannot be connected. So as a hack we are calling softkeymaster to + * computeSharedHmac. + */ + else { ComputeSharedHmacRequest request; request.params_array.params_array = new keymaster::HmacSharingParameters[params.size()]; request.params_array.num_params = params.size(); @@ -401,29 +419,13 @@ Return JavacardKeymaster4Device::computeSharedHmac(const hidl_vecComputeSharedHmac(request); - hidl_vec sharing_check; - if (response.error == KM_ERROR_OK) sharing_check = kmBlob2hidlVec(response.sharing_check); - - _hidl_cb(legacy_enum_conversion(response.error), sharing_check); - return Void(); - - } else { - //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); - return Void(); + if (response.error == KM_ERROR_OK) sharingCheck = kmBlob2hidlVec(response.sharing_check); + errorCode = legacy_enum_conversion(response.error); } - -} +#endif + _hidl_cb(errorCode, sharingCheck); + return Void(); + } Return JavacardKeymaster4Device::verifyAuthorization(uint64_t , const hidl_vec& , const HardwareAuthToken& , verifyAuthorization_cb _hidl_cb) { VerificationToken verificationToken; @@ -1061,8 +1063,10 @@ Return JavacardKeymaster4Device::finish(uint64_t operationHandle, const hi sendDataCallback))) { output = tempOut; } + if (ErrorCode::OK != errorCode) { + abort(operationHandle); + } } - abort(operationHandle); _hidl_cb(errorCode, outParams, output); return Void(); } diff --git a/HAL/keymaster/4.1/JavacardOperationContext.cpp b/HAL/keymaster/4.1/JavacardOperationContext.cpp index 457a6d87..1872f75b 100644 --- a/HAL/keymaster/4.1/JavacardOperationContext.cpp +++ b/HAL/keymaster/4.1/JavacardOperationContext.cpp @@ -183,9 +183,18 @@ ErrorCode OperationContext::finish(uint64_t operHandle, const std::vector newInput(first, end); - if(ErrorCode::OK != (errorCode = handleInternalUpdate(operHandle, newInput.data(), newInput.size(), - Operation::Update, cb))) { - return errorCode; + if(extraData == 0 && (i == noOfChunks - 1)) { + //Last chunk + if(ErrorCode::OK != (errorCode = handleInternalUpdate(operHandle, newInput.data(), newInput.size(), + Operation::Finish, cb, true))) { + return errorCode; + } + + } else { + if(ErrorCode::OK != (errorCode = handleInternalUpdate(operHandle, newInput.data(), newInput.size(), + Operation::Update, cb))) { + return errorCode; + } } } if(extraData > 0) { @@ -217,6 +226,8 @@ ErrorCode OperationContext::getBlockAlignedData(uint64_t operHandle, uint8_t* in blockSize = AES_BLOCK_SIZE; } else if(Algorithm::TRIPLE_DES == operationTable[operHandle].info.alg) { blockSize = DES_BLOCK_SIZE; + } else { + return ErrorCode::INCOMPATIBLE_ALGORITHM; } if(opr == Operation::Finish) { diff --git a/HAL/keymaster/Android.bp b/HAL/keymaster/Android.bp index 8b34023d..eb4fa49c 100644 --- a/HAL/keymaster/Android.bp +++ b/HAL/keymaster/Android.bp @@ -49,6 +49,11 @@ cc_binary { "libjc_transport", "libcrypto", ], + product_variables: { + debuggable: { + cflags: ["-DTRANSCEIVE_VIA_SOCKET"] + } + } } cc_library { From 8a36d0282090084a04006ed62cfe5454d21df03a Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Wed, 13 Jan 2021 23:14:09 +0530 Subject: [PATCH 48/99] Create operation handle map in HAL to differentiate between public and strongbox operations in update, finish and abort operations. --- .../4.1/JavacardKeymaster4Device.cpp | 169 ++++++++++++++---- 1 file changed, 134 insertions(+), 35 deletions(-) diff --git a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp index 71350e9b..ab8ee0ed 100644 --- a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp +++ b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp @@ -49,6 +49,9 @@ #define INS_BEGIN_KM_CMD 0x00 #define INS_END_KM_PROVISION_CMD 0x20 #define INS_END_KM_CMD 0x7F +#define MAX_COUNTER_VALUE 25 +#define SW_KM_OPR 0UL +#define SB_KM_OPR 1UL namespace keymaster { namespace V4_1 { @@ -56,6 +59,7 @@ namespace javacard { static std::unique_ptr pTransportFactory = nullptr; constexpr size_t kOperationTableSize = 4; +std::map operationTable; struct KM_AUTH_LIST_Delete { void operator()(KM_AUTH_LIST* p) { KM_AUTH_LIST_free(p); } @@ -116,6 +120,63 @@ static inline bool getTag(const hidl_vec& params, Tag tag, KeyPara return false; } +static ErrorCode generateOperationHandle(uint64_t& oprHandle) { + std::map::iterator it; + //Check if oprHandleCnt is present in operationTable + uint64_t cnt = 1; + uint64_t mask; + for(; cnt < MAX_COUNTER_VALUE; cnt++) { + mask = cnt | (SB_KM_OPR << 56); + it = operationTable.find(mask); + if (it == operationTable.end()) { + //NO HW Operation found with this operation handle. + //Check for SW. + mask = cnt | (SW_KM_OPR << 56); + it = operationTable.find(mask); + if (it != operationTable.end()) + continue; + else + break; + } else { + continue; + } + } + if (cnt == MAX_COUNTER_VALUE) { + LOG(ERROR) << "generateOperationHandle TOO_MANY_OPERATIONS"; + return ErrorCode::TOO_MANY_OPERATIONS; + } + oprHandle = cnt; + return ErrorCode::OK; +} + +static ErrorCode createOprHandleEntry(uint64_t origOprHandle, uint64_t mask/* SW or HW */, uint64_t& generatedOprHandle) { + ErrorCode errorCode = ErrorCode::OK; + if (ErrorCode::OK != (errorCode = generateOperationHandle(generatedOprHandle))) { + return errorCode; + } + //mask the operationhandle + generatedOprHandle |= (mask << 56); + operationTable[generatedOprHandle] = origOprHandle; + return errorCode; +} + +static ErrorCode getOrigOperationHandle(uint64_t generatedOprHandle, uint64_t& origOprHandle) { + std::map::iterator it = operationTable.find(generatedOprHandle); + if (it == operationTable.end()) { + return ErrorCode::INVALID_OPERATION_HANDLE; + } + origOprHandle = it->second; + return ErrorCode::OK; +} + +static bool isStrongboxOperation(uint64_t generatedOprHandle) { + return (SB_KM_OPR == (generatedOprHandle >> 56)); +} + +static void deleteOprHandleEntry(uint64_t generatedOprHandle) { + operationTable.erase(generatedOprHandle); +} + ErrorCode encodeParametersVerified(const VerificationToken& verificationToken, std::vector& asn1ParamsVerified) { if (verificationToken.parametersVerified.size() > 0) { AuthorizationSet paramSet; @@ -793,12 +854,13 @@ Return JavacardKeymaster4Device::begin(KeyPurpose purpose, const hidl_vec< hidl_vec outParams; uint64_t operationHandle = 0; hidl_vec resultParams; + uint64_t generatedOpHandle = 0; if(keyBlob.size() == 0) { _hidl_cb(ErrorCode::INVALID_ARGUMENT, resultParams, operationHandle); return Void(); } - + /* Asymmetric public key operations are handled by softkeymaster. */ if (KeyPurpose::ENCRYPT == purpose || KeyPurpose::VERIFY == purpose) { BeginOperationRequest request; request.purpose = legacy_enum_conversion(purpose); @@ -806,13 +868,17 @@ Return JavacardKeymaster4Device::begin(KeyPurpose purpose, const hidl_vec< request.additional_params.Reinitialize(KmParamSet(inParams)); BeginOperationResponse response; + /* For Symmetric key operation, the BeginOperation returns KM_ERROR_INCOMPATIBLE_ALGORITHM error. */ softKm_->BeginOperation(request, &response); if (response.error == KM_ERROR_OK) { resultParams = kmParamSet2Hidl(response.output_params); } if (response.error != KM_ERROR_INCOMPATIBLE_ALGORITHM) { /*Incompatible algorithm could be handled by JavaCard*/ - _hidl_cb(legacy_enum_conversion(response.error), resultParams, response.op_handle); + errorCode = legacy_enum_conversion(response.error); + if (errorCode == ErrorCode::OK) + errorCode = createOprHandleEntry(response.op_handle, SW_KM_OPR, generatedOpHandle); + _hidl_cb(errorCode, resultParams, generatedOpHandle); return Void(); } } @@ -871,29 +937,40 @@ Return JavacardKeymaster4Device::begin(KeyPurpose purpose, const hidl_vec< } } } - _hidl_cb(errorCode, outParams, operationHandle); + if (ErrorCode::OK == errorCode) + errorCode = createOprHandleEntry(operationHandle, SB_KM_OPR, generatedOpHandle); + _hidl_cb(errorCode, outParams, generatedOpHandle); return Void(); } -Return JavacardKeymaster4Device::update(uint64_t operationHandle, const hidl_vec& inParams, const hidl_vec& input, const HardwareAuthToken& authToken, const VerificationToken& verificationToken, update_cb _hidl_cb) { +Return JavacardKeymaster4Device::update(uint64_t halGeneratedOprHandle, const hidl_vec& inParams, const hidl_vec& input, const HardwareAuthToken& authToken, const VerificationToken& verificationToken, update_cb _hidl_cb) { ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; - UpdateOperationRequest request; - request.op_handle = operationHandle; - request.input.Reinitialize(input.data(), input.size()); - request.additional_params.Reinitialize(KmParamSet(inParams)); - - UpdateOperationResponse response; - softKm_->UpdateOperation(request, &response); - uint32_t inputConsumed = 0; hidl_vec outParams; hidl_vec output; - errorCode = legacy_enum_conversion(response.error); - if (response.error == KM_ERROR_OK) { - inputConsumed = response.input_consumed; - outParams = kmParamSet2Hidl(response.output_params); - output = kmBuffer2hidlVec(response.output); - } else if(response.error == KM_ERROR_INVALID_OPERATION_HANDLE) { + uint64_t operationHandle; + UpdateOperationResponse response; + if (ErrorCode::OK != (errorCode = getOrigOperationHandle(halGeneratedOprHandle, operationHandle))) { + _hidl_cb(errorCode, inputConsumed, outParams, output); + return Void(); + } + + if (!isStrongboxOperation(halGeneratedOprHandle)) { + /* SW keymaster (Public key operation) */ + UpdateOperationRequest request; + request.op_handle = operationHandle; + request.input.Reinitialize(input.data(), input.size()); + request.additional_params.Reinitialize(KmParamSet(inParams)); + + softKm_->UpdateOperation(request, &response); + errorCode = legacy_enum_conversion(response.error); + if (response.error == KM_ERROR_OK) { + inputConsumed = response.input_consumed; + outParams = kmParamSet2Hidl(response.output_params); + output = kmBuffer2hidlVec(response.output); + } + } else { + /* Strongbox Keymaster operation */ std::vector tempOut; /* OperationContext calls this below sendDataCallback callback function. This callback * may be called multiple times if the input data is larger than MAX_ALLOWED_INPUT_SIZE. @@ -954,32 +1031,48 @@ Return JavacardKeymaster4Device::update(uint64_t operationHandle, const hi inputConsumed = input.size(); output = tempOut; } + if(ErrorCode::OK != errorCode) { + abort(operationHandle); + } } if(ErrorCode::OK != errorCode) { - abort(operationHandle); + deleteOprHandleEntry(halGeneratedOprHandle); } + _hidl_cb(errorCode, inputConsumed, outParams, output); return Void(); } -Return JavacardKeymaster4Device::finish(uint64_t operationHandle, const hidl_vec& inParams, const hidl_vec& input, const hidl_vec& signature, const HardwareAuthToken& authToken, const VerificationToken& verificationToken, finish_cb _hidl_cb) { +Return JavacardKeymaster4Device::finish(uint64_t halGeneratedOprHandle, const hidl_vec& inParams, const hidl_vec& input, const hidl_vec& signature, const HardwareAuthToken& authToken, const VerificationToken& verificationToken, finish_cb _hidl_cb) { ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; - FinishOperationRequest request; - request.op_handle = operationHandle; - request.input.Reinitialize(input.data(), input.size()); - request.signature.Reinitialize(signature.data(), signature.size()); - request.additional_params.Reinitialize(KmParamSet(inParams)); - - FinishOperationResponse response; - softKm_->FinishOperation(request, &response); - + uint64_t operationHandle; hidl_vec outParams; hidl_vec output; - errorCode = legacy_enum_conversion(response.error); - if (response.error == KM_ERROR_OK) { - outParams = kmParamSet2Hidl(response.output_params); - output = kmBuffer2hidlVec(response.output); - } else if (response.error == KM_ERROR_INVALID_OPERATION_HANDLE) { + FinishOperationResponse response; + + if (ErrorCode::OK != (errorCode = getOrigOperationHandle(halGeneratedOprHandle, operationHandle))) { + _hidl_cb(errorCode, outParams, output); + return Void(); + } + + if (!isStrongboxOperation(halGeneratedOprHandle)) { + /* SW keymaster (Public key operation) */ + FinishOperationRequest request; + request.op_handle = operationHandle; + request.input.Reinitialize(input.data(), input.size()); + request.signature.Reinitialize(signature.data(), signature.size()); + request.additional_params.Reinitialize(KmParamSet(inParams)); + + //FinishOperationResponse response; + softKm_->FinishOperation(request, &response); + + errorCode = legacy_enum_conversion(response.error); + if (response.error == KM_ERROR_OK) { + outParams = kmParamSet2Hidl(response.output_params); + output = kmBuffer2hidlVec(response.output); + } + } else { + /* Strongbox Keymaster operation */ std::vector tempOut; bool aadTag = false; /* OperationContext calls this below sendDataCallback callback function. This callback @@ -1067,12 +1160,17 @@ Return JavacardKeymaster4Device::finish(uint64_t operationHandle, const hi abort(operationHandle); } } + deleteOprHandleEntry(halGeneratedOprHandle); _hidl_cb(errorCode, outParams, output); return Void(); } -Return JavacardKeymaster4Device::abort(uint64_t operationHandle) { +Return JavacardKeymaster4Device::abort(uint64_t halGeneratedOprHandle) { ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + uint64_t operationHandle; + if (ErrorCode::OK != (errorCode = getOrigOperationHandle(halGeneratedOprHandle, operationHandle))) { + return errorCode; + } AbortOperationRequest request; request.op_handle = operationHandle; @@ -1099,6 +1197,7 @@ Return JavacardKeymaster4Device::abort(uint64_t operationHandle) { } /* Delete the entry on this operationHandle */ oprCtx_->clearOperationData(operationHandle); + deleteOprHandleEntry(halGeneratedOprHandle); return errorCode; } From 39357b51c3a168e970f3fd62a82d9d157feb3ca8 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Thu, 14 Jan 2021 00:44:08 +0530 Subject: [PATCH 49/99] Pass hal generated operation handle to abort() call from update and finish. --- HAL/keymaster/4.1/JavacardKeymaster4Device.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp index ab8ee0ed..cbcbdfb7 100644 --- a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp +++ b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp @@ -142,7 +142,7 @@ static ErrorCode generateOperationHandle(uint64_t& oprHandle) { } } if (cnt == MAX_COUNTER_VALUE) { - LOG(ERROR) << "generateOperationHandle TOO_MANY_OPERATIONS"; + LOG(ERROR) << "generateOperationHandle TOO_MANY_OPERATIONS error."; return ErrorCode::TOO_MANY_OPERATIONS; } oprHandle = cnt; @@ -1032,7 +1032,7 @@ Return JavacardKeymaster4Device::update(uint64_t halGeneratedOprHandle, co output = tempOut; } if(ErrorCode::OK != errorCode) { - abort(operationHandle); + abort(halGeneratedOprHandle); } } if(ErrorCode::OK != errorCode) { @@ -1129,7 +1129,6 @@ Return JavacardKeymaster4Device::finish(uint64_t halGeneratedOprHandle, co cborConverter_.addHardwareAuthToken(array, authToken); cborConverter_.addVerificationToken(array, verificationToken, asn1ParamsVerified); std::vector cborData = array.encode(); - errorCode = sendData(ins, cborData, cborOutData); if(errorCode == ErrorCode::OK) { @@ -1157,7 +1156,7 @@ Return JavacardKeymaster4Device::finish(uint64_t halGeneratedOprHandle, co output = tempOut; } if (ErrorCode::OK != errorCode) { - abort(operationHandle); + abort(halGeneratedOprHandle); } } deleteOprHandleEntry(halGeneratedOprHandle); From 5c630f2a70d2349754a63bc2f66d30c7213f9f76 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Thu, 14 Jan 2021 12:11:49 +0530 Subject: [PATCH 50/99] Added comments for the newly added code. --- .../4.1/JavacardKeymaster4Device.cpp | 43 +++++++++++++------ 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp index cbcbdfb7..f36fcc67 100644 --- a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp +++ b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp @@ -120,17 +120,18 @@ static inline bool getTag(const hidl_vec& params, Tag tag, KeyPara return false; } +/* Generate new operation handle */ static ErrorCode generateOperationHandle(uint64_t& oprHandle) { std::map::iterator it; - //Check if oprHandleCnt is present in operationTable + //Check if operationHandle is present in operationTable uint64_t cnt = 1; uint64_t mask; for(; cnt < MAX_COUNTER_VALUE; cnt++) { mask = cnt | (SB_KM_OPR << 56); it = operationTable.find(mask); if (it == operationTable.end()) { - //NO HW Operation found with this operation handle. - //Check for SW. + //No Strongbox Operation found with this operation handle. + //Check for Software operation. mask = cnt | (SW_KM_OPR << 56); it = operationTable.find(mask); if (it != operationTable.end()) @@ -142,26 +143,28 @@ static ErrorCode generateOperationHandle(uint64_t& oprHandle) { } } if (cnt == MAX_COUNTER_VALUE) { - LOG(ERROR) << "generateOperationHandle TOO_MANY_OPERATIONS error."; + LOG(ERROR) << "operation handle count reached max operations"; return ErrorCode::TOO_MANY_OPERATIONS; } oprHandle = cnt; return ErrorCode::OK; } -static ErrorCode createOprHandleEntry(uint64_t origOprHandle, uint64_t mask/* SW or HW */, uint64_t& generatedOprHandle) { +/* Create a new operation handle entry in operation table.*/ +static ErrorCode createOprHandleEntry(uint64_t origOprHandle, uint64_t mask/* SW or HW */, uint64_t& newOperationHandle) { ErrorCode errorCode = ErrorCode::OK; - if (ErrorCode::OK != (errorCode = generateOperationHandle(generatedOprHandle))) { + if (ErrorCode::OK != (errorCode = generateOperationHandle(newOperationHandle))) { return errorCode; } //mask the operationhandle - generatedOprHandle |= (mask << 56); - operationTable[generatedOprHandle] = origOprHandle; + newOperationHandle |= (mask << 56); + operationTable[newOperationHandle] = origOprHandle; return errorCode; } -static ErrorCode getOrigOperationHandle(uint64_t generatedOprHandle, uint64_t& origOprHandle) { - std::map::iterator it = operationTable.find(generatedOprHandle); +/* Get original operation handle generated by softkeymaster/strongboxkeymaster. */ +static ErrorCode getOrigOperationHandle(uint64_t halGeneratedOperationHandle, uint64_t& origOprHandle) { + std::map::iterator it = operationTable.find(halGeneratedOperationHandle); if (it == operationTable.end()) { return ErrorCode::INVALID_OPERATION_HANDLE; } @@ -169,12 +172,14 @@ static ErrorCode getOrigOperationHandle(uint64_t generatedOprHandle, uint64_t& o return ErrorCode::OK; } -static bool isStrongboxOperation(uint64_t generatedOprHandle) { - return (SB_KM_OPR == (generatedOprHandle >> 56)); +/* Tells if the operation handle belongs to strongbox keymaster. */ +static bool isStrongboxOperation(uint64_t halGeneratedOperationHandle) { + return (SB_KM_OPR == (halGeneratedOperationHandle >> 56)); } -static void deleteOprHandleEntry(uint64_t generatedOprHandle) { - operationTable.erase(generatedOprHandle); +/* Delete the operation handle entry from operation table. */ +static void deleteOprHandleEntry(uint64_t halGeneratedOperationHandle) { + operationTable.erase(halGeneratedOperationHandle); } ErrorCode encodeParametersVerified(const VerificationToken& verificationToken, std::vector& asn1ParamsVerified) { @@ -876,6 +881,10 @@ Return JavacardKeymaster4Device::begin(KeyPurpose purpose, const hidl_vec< } if (response.error != KM_ERROR_INCOMPATIBLE_ALGORITHM) { /*Incompatible algorithm could be handled by JavaCard*/ errorCode = legacy_enum_conversion(response.error); + /* Create a new operation handle and add a entry inside the operation table map with + * key - new operation handle + * value - hal generated operation handle. + */ if (errorCode == ErrorCode::OK) errorCode = createOprHandleEntry(response.op_handle, SW_KM_OPR, generatedOpHandle); _hidl_cb(errorCode, resultParams, generatedOpHandle); @@ -937,6 +946,10 @@ Return JavacardKeymaster4Device::begin(KeyPurpose purpose, const hidl_vec< } } } + /* Create a new operation handle and add a entry inside the operation table map with + * key - new operation handle + * value - hal generated operation handle. + */ if (ErrorCode::OK == errorCode) errorCode = createOprHandleEntry(operationHandle, SB_KM_OPR, generatedOpHandle); _hidl_cb(errorCode, outParams, generatedOpHandle); @@ -1036,6 +1049,7 @@ Return JavacardKeymaster4Device::update(uint64_t halGeneratedOprHandle, co } } if(ErrorCode::OK != errorCode) { + /* Delete the entry from operation table. */ deleteOprHandleEntry(halGeneratedOprHandle); } @@ -1159,6 +1173,7 @@ Return JavacardKeymaster4Device::finish(uint64_t halGeneratedOprHandle, co abort(halGeneratedOprHandle); } } + /* Delete the entry from operation table. */ deleteOprHandleEntry(halGeneratedOprHandle); _hidl_cb(errorCode, outParams, output); return Void(); From a25e9c0e2e94a6607e7b7b6d24c228f7f9ab169f Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Thu, 14 Jan 2021 19:51:33 +0530 Subject: [PATCH 51/99] updated provisioning tool --- .../4.1/JavacardKeymaster4Device.cpp | 1 - HAL/keymaster/Android.bp | 62 ++++++++++--------- provisioning_tool/Android.bp | 41 ++++++++++++ provisioning_tool/README.md | 1 + .../provision_tool.cpp | 3 +- provisioning_tool/sample_json.txt | 25 ++++++++ 6 files changed, 102 insertions(+), 31 deletions(-) create mode 100644 provisioning_tool/Android.bp create mode 100644 provisioning_tool/README.md rename {HAL/keymaster/4.1 => provisioning_tool}/provision_tool.cpp (99%) create mode 100644 provisioning_tool/sample_json.txt diff --git a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp index 23583024..08c634ca 100644 --- a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp +++ b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp @@ -266,7 +266,6 @@ ErrorCode sendData(Instruction ins, std::vector& inData, std::vector Date: Fri, 15 Jan 2021 20:44:40 +0530 Subject: [PATCH 52/99] Used Rand_bytes for hal generated operation handle. Updated comments --- .../4.1/JavacardKeymaster4Device.cpp | 70 ++++++++----------- .../4.1/JavacardOperationContext.cpp | 3 +- HAL/keymaster/Android.bp | 4 +- 3 files changed, 34 insertions(+), 43 deletions(-) diff --git a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp index f36fcc67..5ac1a431 100644 --- a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp +++ b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -49,7 +50,6 @@ #define INS_BEGIN_KM_CMD 0x00 #define INS_END_KM_PROVISION_CMD 0x20 #define INS_END_KM_CMD 0x7F -#define MAX_COUNTER_VALUE 25 #define SW_KM_OPR 0UL #define SB_KM_OPR 1UL @@ -59,7 +59,10 @@ namespace javacard { static std::unique_ptr pTransportFactory = nullptr; constexpr size_t kOperationTableSize = 4; -std::map operationTable; +/* Key is the newly generated operation handle. Value is a pair with first element having + * original operation handle and second element represents SW or SB operation. + */ +std::map> operationTable; struct KM_AUTH_LIST_Delete { void operator()(KM_AUTH_LIST* p) { KM_AUTH_LIST_free(p); } @@ -122,59 +125,44 @@ static inline bool getTag(const hidl_vec& params, Tag tag, KeyPara /* Generate new operation handle */ static ErrorCode generateOperationHandle(uint64_t& oprHandle) { - std::map::iterator it; - //Check if operationHandle is present in operationTable - uint64_t cnt = 1; - uint64_t mask; - for(; cnt < MAX_COUNTER_VALUE; cnt++) { - mask = cnt | (SB_KM_OPR << 56); - it = operationTable.find(mask); - if (it == operationTable.end()) { - //No Strongbox Operation found with this operation handle. - //Check for Software operation. - mask = cnt | (SW_KM_OPR << 56); - it = operationTable.find(mask); - if (it != operationTable.end()) - continue; - else - break; - } else { - continue; + std::map>::iterator it; + do { + keymaster_error_t err = GenerateRandom(reinterpret_cast(&oprHandle), (size_t)sizeof(oprHandle)); + if (err != KM_ERROR_OK) { + return legacy_enum_conversion(err); } - } - if (cnt == MAX_COUNTER_VALUE) { - LOG(ERROR) << "operation handle count reached max operations"; - return ErrorCode::TOO_MANY_OPERATIONS; - } - oprHandle = cnt; + it = operationTable.find(oprHandle); + } while (it != operationTable.end()); return ErrorCode::OK; } /* Create a new operation handle entry in operation table.*/ -static ErrorCode createOprHandleEntry(uint64_t origOprHandle, uint64_t mask/* SW or HW */, uint64_t& newOperationHandle) { +static ErrorCode createOprHandleEntry(uint64_t origOprHandle, uint64_t keymasterSrc, uint64_t& newOperationHandle) { ErrorCode errorCode = ErrorCode::OK; if (ErrorCode::OK != (errorCode = generateOperationHandle(newOperationHandle))) { return errorCode; } - //mask the operationhandle - newOperationHandle |= (mask << 56); - operationTable[newOperationHandle] = origOprHandle; + operationTable[newOperationHandle] = std::make_pair(origOprHandle, keymasterSrc); return errorCode; } /* Get original operation handle generated by softkeymaster/strongboxkeymaster. */ static ErrorCode getOrigOperationHandle(uint64_t halGeneratedOperationHandle, uint64_t& origOprHandle) { - std::map::iterator it = operationTable.find(halGeneratedOperationHandle); + std::map>::iterator it = operationTable.find(halGeneratedOperationHandle); if (it == operationTable.end()) { return ErrorCode::INVALID_OPERATION_HANDLE; } - origOprHandle = it->second; + origOprHandle = it->second.first; return ErrorCode::OK; } /* Tells if the operation handle belongs to strongbox keymaster. */ static bool isStrongboxOperation(uint64_t halGeneratedOperationHandle) { - return (SB_KM_OPR == (halGeneratedOperationHandle >> 56)); + std::map>::iterator it = operationTable.find(halGeneratedOperationHandle); + if (it == operationTable.end()) { + return false; + } + return (SB_KM_OPR == it->second.second); } /* Delete the operation handle entry from operation table. */ @@ -385,14 +373,12 @@ Return JavacardKeymaster4Device::getHardwareInfo(getHardwareInfo_cb _hidl_ } _hidl_cb(static_cast(securityLevel), jcKeymasterName, jcKeymasterAuthor); return Void(); - } -#ifdef TRANSCEIVE_VIA_SOCKET - else { - //TODO Should we throw fatal error here.? + } else { + // It should not come here, but incase if for any reason SB keymaster fails to getHardwareInfo + // return proper values from HAL. _hidl_cb(SecurityLevel::STRONGBOX, JAVACARD_KEYMASTER_NAME, JAVACARD_KEYMASTER_AUTHOR); return Void(); } -#endif } Return JavacardKeymaster4Device::getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) { @@ -412,7 +398,7 @@ Return JavacardKeymaster4Device::getHmacSharingParameters(getHmacSharingPa } } } -#ifdef TRANSCEIVE_VIA_SOCKET +#ifdef VTS_EMULATOR /* TODO temporary fix: vold daemon calls performHmacKeyAgreement. At that time when vold calls this API there is no * network connectivity and socket cannot be connected. So as a hack we are calling softkeymaster to getHmacSharing * parameters. @@ -466,7 +452,7 @@ Return JavacardKeymaster4Device::computeSharedHmac(const hidl_vec JavacardKeymaster4Device::begin(KeyPurpose purpose, const hidl_vec< _hidl_cb(ErrorCode::INVALID_ARGUMENT, resultParams, operationHandle); return Void(); } - /* Asymmetric public key operations are handled by softkeymaster. */ + /* Asymmetric public key operations like RSA Verify, RSA Encrypt, ECDSA verify + * are handled by softkeymaster. + */ if (KeyPurpose::ENCRYPT == purpose || KeyPurpose::VERIFY == purpose) { BeginOperationRequest request; request.purpose = legacy_enum_conversion(purpose); diff --git a/HAL/keymaster/4.1/JavacardOperationContext.cpp b/HAL/keymaster/4.1/JavacardOperationContext.cpp index 1872f75b..e3f4c800 100644 --- a/HAL/keymaster/4.1/JavacardOperationContext.cpp +++ b/HAL/keymaster/4.1/JavacardOperationContext.cpp @@ -123,6 +123,7 @@ ErrorCode OperationContext::validateInputData(uint64_t operHandle, Operation opr memset(oprData.data.buf, 0x00, sizeof(oprData.data.buf)); oprData.data.buf_len = 0; } + return ErrorCode::OK; } } input = actualInput; @@ -342,7 +343,7 @@ ErrorCode OperationContext::handleInternalUpdate(uint64_t operHandle, uint8_t* d return errorCode; } } else { - //For strongbox keymaster, in NoDigest case the length of the input message for RSA should be more than + //For strongbox keymaster, in NoDigest case the length of the input message for RSA should not be more than //256 and for EC it should not be more than 32. This validation is already happening in //validateInputData function. Just for safety sake we are checking the length to MAX_BUF_SIZE. if(operationTable[operHandle].data.buf_len <= MAX_BUF_SIZE) { diff --git a/HAL/keymaster/Android.bp b/HAL/keymaster/Android.bp index eb4fa49c..d92809e8 100644 --- a/HAL/keymaster/Android.bp +++ b/HAL/keymaster/Android.bp @@ -51,7 +51,9 @@ cc_binary { ], product_variables: { debuggable: { - cflags: ["-DTRANSCEIVE_VIA_SOCKET"] + cflags: [ + "-DVTS_EMULATOR", + ] } } } From 20ca29b22f785b7d3e0488645f3b0e6e5690f4f9 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Fri, 15 Jan 2021 21:53:46 +0530 Subject: [PATCH 53/99] Clearing the operation data inside the operation context --- HAL/keymaster/4.1/JavacardKeymaster4Device.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp index 5ac1a431..445f3737 100644 --- a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp +++ b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp @@ -1163,6 +1163,7 @@ Return JavacardKeymaster4Device::finish(uint64_t halGeneratedOprHandle, co } /* Delete the entry from operation table. */ deleteOprHandleEntry(halGeneratedOprHandle); + oprCtx_->clearOperationData(operationHandle); _hidl_cb(errorCode, outParams, output); return Void(); } From 8e97a450ef51e0311d439d896d48126e0e895e3d Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Sun, 17 Jan 2021 19:50:33 +0530 Subject: [PATCH 54/99] Added comments for getBlockAlignedData function --- .../4.1/JavacardOperationContext.cpp | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/HAL/keymaster/4.1/JavacardOperationContext.cpp b/HAL/keymaster/4.1/JavacardOperationContext.cpp index e3f4c800..7319cb3c 100644 --- a/HAL/keymaster/4.1/JavacardOperationContext.cpp +++ b/HAL/keymaster/4.1/JavacardOperationContext.cpp @@ -23,7 +23,6 @@ #define DES_BLOCK_SIZE 8 #define RSA_INPUT_MSG_LEN 256 #define EC_INPUT_MSG_LEN 32 -#define MAX_RSA_BUFFER_SIZE 256 #define MAX_EC_BUFFER_SIZE 32 namespace keymaster { @@ -104,11 +103,10 @@ ErrorCode OperationContext::validateInputData(uint64_t operHandle, Operation opr } if(KeyPurpose::DECRYPT == oprData.info.purpose && Algorithm::RSA == oprData.info.alg) { - if((oprData.data.buf_len+actualInput.size()) > MAX_RSA_BUFFER_SIZE) { + if((oprData.data.buf_len+actualInput.size()) > RSA_INPUT_MSG_LEN) { return ErrorCode::INVALID_INPUT_LENGTH; } } - if(opr == Operation::Finish) { //If it is observed in finish operation that buffered data + input data exceeds the MAX_ALLOWED_INPUT_SIZE then //combine both the data in a single buffer. This helps in making sure that no data is left out in the buffer after @@ -171,7 +169,6 @@ ErrorCode OperationContext::update(uint64_t operHandle, const std::vector& actualInput, sendDataToSE_cb cb) { ErrorCode errorCode = ErrorCode::OK; std::vector input; - /* Validate the input data */ if(ErrorCode::OK != (errorCode = validateInputData(operHandle, Operation::Finish, actualInput, input))) { return errorCode; @@ -214,15 +211,25 @@ ErrorCode OperationContext::finish(uint64_t operHandle, const std::vector& out) { - size_t dataToSELen = 0; + size_t dataToSELen = 0;/*Length of the data to be send to the Applet.*/ size_t inputConsumed = 0;/*Length of the data consumed from input */ size_t blockSize = 0; BufferedData& data = operationTable[operHandle].data; int bufIndex = data.buf_len; - if(Algorithm::AES == operationTable[operHandle].info.alg) { blockSize = AES_BLOCK_SIZE; } else if(Algorithm::TRIPLE_DES == operationTable[operHandle].info.alg) { @@ -265,6 +272,8 @@ ErrorCode OperationContext::getBlockAlignedData(uint64_t operHandle, uint8_t* in if(dataToSELen > 0) { //If buffer length is greater than the data length to be send to SE, then input data consumed is 0. //That means all the data to be send to SE is consumed from the buffer. + //The buffer length might become greater than dataToSELen in the cases where we are saving the last block of + //data i.e. AES/TDES Decryption with PKC7Padding or AES GCM Decryption operations. inputConsumed = (data.buf_len > dataToSELen) ? 0 : (dataToSELen - data.buf_len); //Copy the buffer to be send to SE. @@ -301,7 +310,6 @@ ErrorCode OperationContext::handleInternalUpdate(uint64_t operHandle, uint8_t* d sendDataToSE_cb cb, bool finish) { ErrorCode errorCode = ErrorCode::OK; std::vector out; - if(Algorithm::AES == operationTable[operHandle].info.alg || Algorithm::TRIPLE_DES == operationTable[operHandle].info.alg) { /*Symmetric */ @@ -345,16 +353,14 @@ ErrorCode OperationContext::handleInternalUpdate(uint64_t operHandle, uint8_t* d } else { //For strongbox keymaster, in NoDigest case the length of the input message for RSA should not be more than //256 and for EC it should not be more than 32. This validation is already happening in - //validateInputData function. Just for safety sake we are checking the length to MAX_BUF_SIZE. - if(operationTable[operHandle].data.buf_len <= MAX_BUF_SIZE) { - size_t bufIndex = operationTable[operHandle].data.buf_len; - size_t pos = 0; - for(; (pos < len) && (pos < (MAX_BUF_SIZE-bufIndex)); pos++) - { - operationTable[operHandle].data.buf[bufIndex+pos] = data[pos]; - } - operationTable[operHandle].data.buf_len += pos; + //validateInputData function. + size_t bufIndex = operationTable[operHandle].data.buf_len; + size_t pos = 0; + for(; pos < len; ++pos) + { + operationTable[operHandle].data.buf[bufIndex+pos] = data[pos]; } + operationTable[operHandle].data.buf_len += pos; } } else { /* With Digest */ for(size_t j=0; j < len; ++j) From 25325b3cda43ae28dafe6724f9788842d4a04cc1 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Tue, 19 Jan 2021 21:22:57 +0530 Subject: [PATCH 55/99] Handle extended errorcodes in HAL --- .../4.1/JavacardKeymaster4Device.cpp | 103 ++++++++++++++---- 1 file changed, 81 insertions(+), 22 deletions(-) diff --git a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp index 445f3737..20e5cd5a 100644 --- a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp +++ b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp @@ -94,6 +94,23 @@ enum class Instruction { INS_GET_CERT_CHAIN_CMD = INS_END_KM_PROVISION_CMD+22 }; +//Extended error codes +enum ExtendedErrors { + SW_CONDITIONS_NOT_SATISFIED = -1001, + UNSUPPORTED_CLA = -1002, + INVALID_P1P2 = -1003, + UNSUPPORTED_INSTRUCTION = -1004, + CMD_NOT_ALLOWED = -1005, + SW_WRONG_LENGTH = -1006, + INVALID_DATA = -1007, + CRYPTO_ILLEGAL_USE = -1008, + CRYPTO_ILLEGAL_VALUE = -1009, + CRYPTO_INVALID_INIT = -1010, + CRYPTO_NO_SUCH_ALGORITHM = -1011, + CRYPTO_UNINITIALIZED_KEY = -1012, + GENERIC_UNKNOWN_ERROR = -1013 +}; + static inline std::unique_ptr& getTransportFactoryInstance() { if(pTransportFactory == nullptr) { pTransportFactory = std::unique_ptr(new se_transport::TransportFactory( @@ -123,6 +140,47 @@ static inline bool getTag(const hidl_vec& params, Tag tag, KeyPara return false; } +template +static T translateExtendedErrorsToHalErrors(T& errorCode) { + T err; + switch(static_cast(errorCode)) { + case SW_CONDITIONS_NOT_SATISFIED: + case UNSUPPORTED_CLA: + case INVALID_P1P2: + case INVALID_DATA: + case CRYPTO_ILLEGAL_USE: + case CRYPTO_ILLEGAL_VALUE: + case CRYPTO_INVALID_INIT: + case CRYPTO_UNINITIALIZED_KEY: + case GENERIC_UNKNOWN_ERROR: + err = T::UNKNOWN_ERROR; + break; + case CRYPTO_NO_SUCH_ALGORITHM: + err = T::UNSUPPORTED_ALGORITHM; + break; + case UNSUPPORTED_INSTRUCTION: + case CMD_NOT_ALLOWED: + case SW_WRONG_LENGTH: + err = T::UNIMPLEMENTED; + break; + default: + err = static_cast(errorCode); + break; + } + return err; +} + +template +static std::tuple, T> decodeData(CborConverter& cb, const std::vector& response, bool + hasErrorCode) { + std::unique_ptr item(nullptr); + T errorCode = T::OK; + std::tie(item, errorCode) = cb.decodeData(response, hasErrorCode); + if (ErrorCode::OK != errorCode) + errorCode = translateExtendedErrorsToHalErrors(errorCode); + return {std::move(item), errorCode}; +} + /* Generate new operation handle */ static ErrorCode generateOperationHandle(uint64_t& oprHandle) { std::map>::iterator it; @@ -390,7 +448,7 @@ Return JavacardKeymaster4Device::getHmacSharingParameters(getHmacSharingPa errorCode = sendData(Instruction::INS_GET_HMAC_SHARING_PARAM_CMD, input, cborData); if (ErrorCode::OK == errorCode) { //Skip last 2 bytes in cborData, it contains status. - std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborData.begin(), cborData.end()-2), + std::tie(item, errorCode) = decodeData(cborConverter_, std::vector(cborData.begin(), cborData.end()-2), true); if (item != nullptr) { if(!cborConverter_.getHmacSharingParameters(item, 1, hmacSharingParameters)) { @@ -441,7 +499,7 @@ Return JavacardKeymaster4Device::computeSharedHmac(const hidl_vec(cborOutData.begin(), cborOutData.end()-2), + std::tie(item, errorCode) = decodeData(cborConverter_, std::vector(cborOutData.begin(), cborOutData.end()-2), true); if (item != nullptr) { std::vector bstr; @@ -498,7 +556,7 @@ Return JavacardKeymaster4Device::addRngEntropy(const hidl_vec(cborOutData.begin(), cborOutData.end()-2), + std::tie(item, errorCode) = decodeData(cborConverter_, std::vector(cborOutData.begin(), cborOutData.end()-2), true); } return errorCode; @@ -530,7 +588,7 @@ Return JavacardKeymaster4Device::generateKey(const hidl_vec& 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), + std::tie(item, errorCode) = decodeData(cborConverter_, std::vector(cborOutData.begin(), cborOutData.end()-2), true); if (item != nullptr) { if(!cborConverter_.getBinaryArray(item, 1, keyBlob) || @@ -576,7 +634,7 @@ Return JavacardKeymaster4Device::importKey(const hidl_vec& k 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), + std::tie(item, errorCode) = decodeData(cborConverter_, std::vector(cborOutData.begin(), cborOutData.end()-2), true); if (item != nullptr) { if(!cborConverter_.getBinaryArray(item, 1, keyBlob) || @@ -631,7 +689,7 @@ Return JavacardKeymaster4Device::importWrappedKey(const hidl_vec& 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), + std::tie(item, errorCode) = decodeData(cborConverter_, std::vector(cborOutData.begin(), cborOutData.end()-2), true); if (item != nullptr) { if(!cborConverter_.getBinaryArray(item, 1, keyBlob) || @@ -664,7 +722,7 @@ Return JavacardKeymaster4Device::getKeyCharacteristics(const hidl_vec(cborOutData.begin(), cborOutData.end()-2), + std::tie(item, errorCode) = decodeData(cborConverter_, std::vector(cborOutData.begin(), cborOutData.end()-2), true); if (item != nullptr) { if(!cborConverter_.getKeyCharacteristics(item, 1, keyCharacteristics)) { @@ -730,7 +788,7 @@ Return JavacardKeymaster4Device::attestKey(const hidl_vec& keyToA std::vector> temp; std::vector rootCert; //Skip last 2 bytes in cborData, it contains status. - std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), + std::tie(item, errorCode) = decodeData(cborConverter_, std::vector(cborOutData.begin(), cborOutData.end()-2), true); if (item != nullptr) { if(!cborConverter_.getMultiBinaryArray(item, 1, temp)) { @@ -741,7 +799,8 @@ Return JavacardKeymaster4Device::attestKey(const hidl_vec& keyToA errorCode = sendData(Instruction::INS_GET_CERT_CHAIN_CMD, cborData, cborOutData, true); 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), + std::tie(item, errorCode) = decodeData(cborConverter_, std::vector(cborOutData.begin(), + cborOutData.end()-2), true); if (item != nullptr) { std::vector chain; @@ -779,7 +838,7 @@ Return JavacardKeymaster4Device::upgradeKey(const hidl_vec& keyBl 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), + std::tie(item, errorCode) = decodeData(cborConverter_, std::vector(cborOutData.begin(), cborOutData.end()-2), true); if (item != nullptr) { if(!cborConverter_.getBinaryArray(item, 1, upgradedKeyBlob)) @@ -802,7 +861,7 @@ Return JavacardKeymaster4Device::deleteKey(const hidl_vec& k 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), + std::tie(item, errorCode) = decodeData(cborConverter_, std::vector(cborOutData.begin(), cborOutData.end()-2), true); } return errorCode; @@ -818,7 +877,7 @@ Return JavacardKeymaster4Device::deleteAllKeys() { 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), + std::tie(item, errorCode) = decodeData(cborConverter_, std::vector(cborOutData.begin(), cborOutData.end()-2), true); } return errorCode; @@ -834,7 +893,7 @@ Return JavacardKeymaster4Device::destroyAttestationIds() { 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), + std::tie(item, errorCode) = decodeData(cborConverter_, std::vector(cborOutData.begin(), cborOutData.end()-2), true); } return errorCode; @@ -918,7 +977,7 @@ Return JavacardKeymaster4Device::begin(KeyPurpose purpose, const hidl_vec< errorCode = sendData(Instruction::INS_BEGIN_OPERATION_CMD, cborData, cborOutData); 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), + std::tie(item, errorCode) = decodeData(cborConverter_, std::vector(cborOutData.begin(), cborOutData.end()-2), true); if (item != nullptr) { if(!cborConverter_.getKeyParameters(item, 1, outParams) || @@ -1007,7 +1066,7 @@ Return JavacardKeymaster4Device::update(uint64_t halGeneratedOprHandle, co 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), + std::tie(item, errorCode) = decodeData(cborConverter_, std::vector(cborOutData.begin(), cborOutData.end()-2), true); if (item != nullptr) { /*Ignore inputConsumed from javacard SE since HAL consumes all the input */ @@ -1065,10 +1124,10 @@ Return JavacardKeymaster4Device::finish(uint64_t halGeneratedOprHandle, co request.signature.Reinitialize(signature.data(), signature.size()); request.additional_params.Reinitialize(KmParamSet(inParams)); - //FinishOperationResponse response; softKm_->FinishOperation(request, &response); errorCode = legacy_enum_conversion(response.error); + if (response.error == KM_ERROR_OK) { outParams = kmParamSet2Hidl(response.output_params); output = kmBuffer2hidlVec(response.output); @@ -1135,7 +1194,7 @@ Return JavacardKeymaster4Device::finish(uint64_t halGeneratedOprHandle, co 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), + std::tie(item, errorCode) = decodeData(cborConverter_, std::vector(cborOutData.begin(), cborOutData.end()-2), true); if (item != nullptr) { //There is a change that this finish callback may gets called multiple times if the input data size @@ -1194,7 +1253,7 @@ Return JavacardKeymaster4Device::abort(uint64_t halGeneratedOprHandle 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), + std::tie(item, errorCode) = decodeData(cborConverter_, std::vector(cborOutData.begin(), cborOutData.end()-2), true); } } @@ -1226,8 +1285,8 @@ Return<::android::hardware::keymaster::V4_1::ErrorCode> JavacardKeymaster4Device 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); + std::tie(item, errorCode) = cborConverter_.decodeData<::android::hardware::keymaster::V4_1::ErrorCode>( + std::vector(cborOutData.begin(), cborOutData.end()-2), true); } return errorCode; } @@ -1243,8 +1302,8 @@ Return<::android::hardware::keymaster::V4_1::ErrorCode> JavacardKeymaster4Device 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); + std::tie(item, errorCode) = cborConverter_.decodeData<::android::hardware::keymaster::V4_1::ErrorCode>( + std::vector(cborOutData.begin(), cborOutData.end()-2), true); } return errorCode; } From 407a8b7db1807655f2459b2bed148c8218238b0b Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Tue, 19 Jan 2021 20:49:17 +0530 Subject: [PATCH 56/99] 1. Exception handling for CryptoException and Generic exceptions 2. PKCS7 padding decrypt fix for AES/DES 3. Few tags were not supported. --- .../keymaster/KMAndroidSEProvider.java | 16 +-- .../javacard/keymaster/KMOperationImpl.java | 6 + .../javacard/keymaster/KMCipherImpl.java | 6 + .../javacard/keymaster/KMJCardSimulator.java | 28 +---- .../android/javacard/keymaster/KMUtils.java | 1 + .../android/javacard/keymaster/KMError.java | 9 ++ .../javacard/keymaster/KMKeyParameters.java | 32 +++++ .../javacard/keymaster/KMKeymasterApplet.java | 118 ++++++------------ .../javacard/keymaster/KMRepository.java | 2 +- .../javacard/keymaster/KMSEProvider.java | 72 +++++------ 10 files changed, 125 insertions(+), 165 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java index aba38934..e18ae600 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java @@ -100,7 +100,7 @@ public class KMAndroidSEProvider implements KMSEProvider { (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_TAG_LENGTH = 16; 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; @@ -608,7 +608,7 @@ public short aesGCMEncrypt(byte[] aesKey, short aesKeyStart, short aesKeyLen, short authTagStart, short authTagLen) { if (authTagLen != AES_GCM_TAG_LENGTH) { - KMException.throwIt(KMError.UNKNOWN_ERROR); + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } if (nonceLen != AES_GCM_NONCE_LENGTH) { CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); @@ -1115,18 +1115,6 @@ 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 short cmacKdf(byte[] keyMaterial, short keyMaterialStart, short keyMaterialLen, byte[] label, short labelStart, short labelLen, diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMOperationImpl.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMOperationImpl.java index b1f48827..1c7ab32d 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMOperationImpl.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMOperationImpl.java @@ -161,6 +161,12 @@ public short finish(byte[] inputDataBuf, short inputDataStart, // padding byte always should be <= block size if ((short) paddingByte > blkSize || (short) paddingByte <= 0) KMException.throwIt(KMError.INVALID_ARGUMENT); + + for(short j = 1; j <= paddingByte; ++j) { + if (outputDataBuf[(short) (outputDataStart + len - j)] != paddingByte) { + KMException.throwIt(KMError.INVALID_ARGUMENT); + } + } len = (short) (len - (short) paddingByte);// remove the padding bytes } } else if (cipherAlg == KMType.AES && blockMode == KMType.GCM) { diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipherImpl.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipherImpl.java index ea65a94c..264b74e5 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipherImpl.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipherImpl.java @@ -121,6 +121,12 @@ public short doFinal(byte[] buffer, short startOff, short length, byte[] scratch //padding byte always should be <= block size if((short)paddingByte > blkSize || (short)paddingByte <= 0) KMException.throwIt(KMError.INVALID_ARGUMENT); + + for(short j = 1; j <= paddingByte; ++j) { + if (scratchPad[i+len -j] != paddingByte) { + KMException.throwIt(KMError.INVALID_ARGUMENT); + } + } len = (short)(len - (short)paddingByte);// remove the padding bytes } } diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java index 9c9e71c6..eb50fd6d 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java @@ -66,7 +66,7 @@ * creates its own RNG using PRNG. */ public class KMJCardSimulator implements KMSEProvider { - public static final short AES_GCM_TAG_LENGTH = 12; + public static final short AES_GCM_TAG_LENGTH = 16; 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 @@ -483,31 +483,7 @@ public boolean aesGCMDecrypt( public void getTrueRandomNumber(byte[] buf, short start, short length) { Util.arrayCopy(entropyPool,(short)0,buf,start,length); } - - @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; - } - AESKey key = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false); - key.setKey(masterKeySecret, masterKeyStart); - byte[] in = new byte[buffInLength]; - Util.arrayCopyNonAtomic(bufIn, bufInStart,in,(short)0,buffInLength); - kdf.init(key, Signature.MODE_SIGN); - short len = kdf.sign(bufIn, bufInStart, buffInLength, bufOut, bufStart); - byte[] out = new byte[len]; - Util.arrayCopyNonAtomic(bufOut, bufStart,out,(short)0,len); - return len; - } - + 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. diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java index d9dce03b..756c3150 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java @@ -102,6 +102,7 @@ public static short convertToDate(short time, byte[] scratchPad, Util.arrayCopyNonAtomic(oneMonthMsec, (short) 0, scratchPad, (short) 8, (short) 8); monthCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); + monthCount =+ 1; Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, (short) 8); } diff --git a/Applet/src/com/android/javacard/keymaster/KMError.java b/Applet/src/com/android/javacard/keymaster/KMError.java index e70dc8c2..abb0e6df 100644 --- a/Applet/src/com/android/javacard/keymaster/KMError.java +++ b/Applet/src/com/android/javacard/keymaster/KMError.java @@ -92,4 +92,13 @@ public class KMError { public static short CMD_NOT_ALLOWED = 1005; public static short SW_WRONG_LENGTH = 1006; public static short INVALID_DATA = 1007; + //Crypto errors + public static short CRYPTO_ILLEGAL_USE = 1008; + public static short CRYPTO_ILLEGAL_VALUE = 1009; + public static short CRYPTO_INVALID_INIT = 1010; + public static short CRYPTO_NO_SUCH_ALGORITHM = 1011; + public static short CRYPTO_UNINITIALIZED_KEY = 1012; + //Generic Unknown error. + public static short GENERIC_UNKNOWN_ERROR = 1013; + } diff --git a/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java b/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java index ae759ffc..8c8475ac 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java @@ -100,6 +100,38 @@ public short findTag(short tagType, short tagKey){ } return ret; } + + public static boolean hasUnsupportedTags(short keyParamsPtr) { + final short[] tagArr = { + // Unsupported tags. + KMType.BOOL_TAG, KMType.TRUSTED_CONFIRMATION_REQUIRED, + KMType.BOOL_TAG, KMType.TRUSTED_USER_PRESENCE_REQUIRED, + KMType.BOOL_TAG, KMType.ALLOW_WHILE_ON_BODY, + KMType.UINT_TAG, KMType.MIN_SEC_BETWEEN_OPS, + }; + byte index = 0; + short tagInd; + short tagPtr; + short tagKey; + short tagType; + short arrPtr = KMKeyParameters.cast(keyParamsPtr).getVals(); + short len = KMArray.cast(arrPtr).length(); + while (index < len) { + tagInd = 0; + tagPtr = KMArray.cast(arrPtr).get(index); + tagKey = KMTag.getKey(tagPtr); + tagType = KMTag.getTagType(tagPtr); + while (tagInd < (short) tagArr.length) { + if ((tagArr[tagInd] == tagType) + && (tagArr[(short) (tagInd + 1)] == tagKey)) { + return true; + } + tagInd += 2; + } + index++; + } + return false; + } // KDF, ECIES_SINGLE_HASH_MODE missing from types.hal public static short makeHwEnforced(short keyParamsPtr, byte origin, diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index d9691a1e..febc7ec7 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -160,7 +160,7 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe public static final byte KEY_BLOB_KEYCHAR = 3; public static final byte KEY_BLOB_PUB_KEY = 4; // AES GCM constants - private static final byte AES_GCM_AUTH_TAG_LENGTH = 12; + private static final byte AES_GCM_AUTH_TAG_LENGTH = 16; private static final byte AES_GCM_NONCE_LENGTH = 12; // ComputeHMAC constants private static final short HMAC_SHARED_PARAM_MAX_SIZE = 64; @@ -245,6 +245,23 @@ private short mapISOErrorToKMError(short reason) { return KMError.UNKNOWN_ERROR; } } + + private short mapCryptoErrorToKMError(short reason) { + switch (reason) { + case CryptoException.ILLEGAL_USE: + return KMError.CRYPTO_ILLEGAL_USE; + case CryptoException.ILLEGAL_VALUE: + return KMError.CRYPTO_ILLEGAL_VALUE; + case CryptoException.INVALID_INIT: + return KMError.CRYPTO_INVALID_INIT; + case CryptoException.NO_SUCH_ALGORITHM: + return KMError.CRYPTO_NO_SUCH_ALGORITHM; + case CryptoException.UNINITIALIZED_KEY: + return KMError.CRYPTO_UNINITIALIZED_KEY; + default: + return KMError.UNKNOWN_ERROR; + } + } protected void validateApduHeader(APDU apdu) { // Read the apdu header and buffer. @@ -443,6 +460,12 @@ && isProvisioningComplete())) { } catch (ISOException exp) { sendError(apdu, mapISOErrorToKMError(exp.getReason())); freeOperations(); + } catch (CryptoException e) { + freeOperations(); + sendError(apdu, mapCryptoErrorToKMError(e.getReason())); + } catch (Exception e) { + freeOperations(); + sendError(apdu, KMError.GENERIC_UNKNOWN_ERROR); } finally { resetData(); repository.clean(); @@ -578,7 +601,6 @@ private void processAddRngEntropyCmd(APDU apdu) { //reclaim memory repository.reclaimMemory(bufferLength); - // Process KMByteBlob blob = KMByteBlob.cast(KMArray.cast(args).get((short) 0)); // Maximum 2KiB of seed is allowed. @@ -606,7 +628,6 @@ private void processGetCertChainCmd(APDU apdu) { sendOutgoing(apdu); } - private void processProvisionAttestationCertParams(APDU apdu) { receiveIncoming(apdu); // Arguments @@ -620,7 +641,6 @@ private void processProvisionAttestationCertParams(APDU apdu) { //reclaim memory repository.reclaimMemory(bufferLength); - // save issuer - DER Encoded tmpVariables[0] = KMArray.cast(args).get((short) 0); repository.setIssuer( @@ -1607,7 +1627,6 @@ private void processFinishOperationCmd(APDU apdu) { // Finish trusted Confirmation operation switch (op.getPurpose()) { case KMType.SIGN: - finishTrustedConfirmationOperation(op); case KMType.VERIFY: finishSigningVerifyingOperation(op, scratchPad); break; @@ -1631,7 +1650,6 @@ 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); @@ -1905,31 +1923,6 @@ private void finishSigningVerifyingOperation(KMOperationState op, byte[] scratch } } - private void finishTrustedConfirmationOperation(KMOperationState op) { - // Perform trusted confirmation if required - if (op.isTrustedConfirmationRequired()) { - tmpVariables[0] = - KMKeyParameters.findTag( - KMType.BYTES_TAG, KMType.CONFIRMATION_TOKEN, data[KEY_PARAMETERS]); - if (tmpVariables[0] == KMType.INVALID_VALUE) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - tmpVariables[0] = KMByteTag.cast(tmpVariables[0]).getValue(); - boolean verified = - op.getTrustedConfirmationSigner() - .verify( - KMByteBlob.cast(data[INPUT_DATA]).getBuffer(), - KMByteBlob.cast(data[INPUT_DATA]).getStartOff(), - KMByteBlob.cast(data[INPUT_DATA]).length(), - KMByteBlob.cast(tmpVariables[0]).getBuffer(), - KMByteBlob.cast(tmpVariables[0]).getStartOff(), - KMByteBlob.cast(tmpVariables[0]).length()); - if (!verified) { - KMException.throwIt(KMError.VERIFICATION_FAILED); - } - } - } - private void authorizeUpdateFinishOperation(KMOperationState op, byte[] scratchPad) { // If one time user Authentication is required if (op.isSecureUserIdReqd() && !op.isAuthTimeoutValidated()) { @@ -2111,8 +2104,6 @@ private void processUpdateOperationCmd(APDU apdu) { KMByteBlob.cast(data[INPUT_DATA]).getBuffer(), KMByteBlob.cast(data[INPUT_DATA]).getStartOff(), KMByteBlob.cast(data[INPUT_DATA]).length()); - // update trusted confirmation operation - updateTrustedConfirmationOperation(op); data[OUTPUT_DATA] = KMType.INVALID_VALUE; } else if (op.getPurpose() == KMType.ENCRYPT || op.getPurpose() == KMType.DECRYPT) { // Update for encrypt/decrypt using RSA will not be supported because to do this op state @@ -2200,16 +2191,6 @@ private void processUpdateOperationCmd(APDU apdu) { sendOutgoing(apdu); } - private void updateTrustedConfirmationOperation(KMOperationState op) { - if (op.isTrustedConfirmationRequired()) { - op.getTrustedConfirmationSigner() - .update( - KMByteBlob.cast(data[INPUT_DATA]).getBuffer(), - KMByteBlob.cast(data[INPUT_DATA]).getStartOff(), - KMByteBlob.cast(data[INPUT_DATA]).length()); - } - } - private void processBeginOperationCmd(APDU apdu) { // Receive the incoming request fully from the master into buffer. receiveIncoming(apdu); @@ -2257,7 +2238,6 @@ private void processBeginOperationCmd(APDU apdu) { authorizeAndBeginOperation(op, scratchPad); switch (op.getPurpose()) { case KMType.SIGN: - beginTrustedConfirmationOperation(op); case KMType.VERIFY: beginSignVerifyOperation(op); break; @@ -2304,42 +2284,6 @@ private void processBeginOperationCmd(APDU apdu) { sendOutgoing(apdu); } - private void beginTrustedConfirmationOperation(KMOperationState op) { - // Check for trusted confirmation - if required then set the signer in op state. - if (KMKeyParameters.findTag( - KMType.BOOL_TAG, KMType.TRUSTED_CONFIRMATION_REQUIRED, data[HW_PARAMETERS]) - != KMType.INVALID_VALUE) { - // get operation - // get the hmac key - short key = repository.getComputedHmacKey(); - if (key == 0) { - KMException.throwIt(KMError.OPERATION_CANCELLED); - } - /* - op.setTrustedConfirmationSigner(seProvider.initSymmetricOperation( - KMType.VERIFY,KMType.HMAC,KMType.SHA2_256,(byte)0,(byte)0,repository.getComputedHmacKey(), - (short) 0, (short) repository.getComputedHmacKey().length,null,(short)0,(short)0,(short)0)); - */ - op.setTrustedConfirmationSigner( - seProvider.initSymmetricOperation( - KMType.VERIFY, - KMType.HMAC, - KMType.SHA2_256, - (byte) 0, - (byte) 0, - KMByteBlob.cast(key).getBuffer(), - KMByteBlob.cast(key).getStartOff(), - KMByteBlob.cast(key).length(), - null, - (short) 0, - (short) 0, - (short) 0)); - - op.getTrustedConfirmationSigner() - .update(confirmationToken, (short) 0, (short) confirmationToken.length); - } - } - private void authorizeAlgorithm(KMOperationState op) { short alg = KMEnumTag.getValue(KMType.ALGORITHM, data[HW_PARAMETERS]); if (alg == KMType.INVALID_VALUE) { @@ -3435,6 +3379,20 @@ private static void processGenerateKey(APDU apdu) { KMException.throwIt(KMError.UNSUPPORTED_KEY_SIZE); } } + // Only STANDALONE is supported for BLOB_USAGE_REQ tag. + tmpVariables[0] = + KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.BLOB_USAGE_REQ, data[KEY_PARAMETERS]); + if (tmpVariables[0] != KMType.INVALID_VALUE) { + tmpVariables[0] = KMEnumTag.getValue(KMType.BLOB_USAGE_REQ, data[KEY_PARAMETERS]); + if (tmpVariables[0] != KMType.STANDALONE) { + KMException.throwIt(KMError.UNSUPPORTED_TAG); + } + } + //Check if the tags are supported. + if(KMKeyParameters.hasUnsupportedTags(data[KEY_PARAMETERS])) { + KMException.throwIt(KMError.UNSUPPORTED_TAG); + } + // Check algorithm and dispatch to appropriate handler. switch (tmpVariables[3]) { case KMType.RSA: diff --git a/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/src/com/android/javacard/keymaster/KMRepository.java index b8dc8b8d..062e31b5 100644 --- a/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/Applet/src/com/android/javacard/keymaster/KMRepository.java @@ -84,7 +84,7 @@ public class KMRepository implements KMUpgradable { public static final short DEVICE_LOCK_FLAG_SIZE = 1; 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_LENGTH = 16; 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; diff --git a/Applet/src/com/android/javacard/keymaster/KMSEProvider.java b/Applet/src/com/android/javacard/keymaster/KMSEProvider.java index 81b35db2..3e981c9a 100644 --- a/Applet/src/com/android/javacard/keymaster/KMSEProvider.java +++ b/Applet/src/com/android/javacard/keymaster/KMSEProvider.java @@ -49,11 +49,12 @@ void createAsymmetricKey( short[] lengths); /** - * Verify that the imported key is valid. + * Verify that the imported key is valid. If the algorithm and/or keysize are not supported then it + * should throw a CryptoException. * * @param alg will be KMType.AES, KMType.DES or KMType.HMAC. * @param keysize will be 128 or 256 for AES or DES. It can be 64 to 512 (multiple of 8) for HMAC. - * @param buf is the buffer in which key has to be returned + * @param buf is the buffer that contains the symmetric key. * @param startOff is the start offset. * @param length of the data in the buf. This should match the keysize (in bytes). * @return true if the symmetric key is supported and valid. @@ -63,14 +64,15 @@ void createAsymmetricKey( /** * Validate that the imported asymmetric key pair is valid. For RSA the public key exponent must * always be 0x010001. The key size of RSA key pair must be 2048 bits and key size of EC key pair - * must be for p256 curve. + * must be for p256 curve. If the algorithms are not supported then it should throw a + * CryptoException. * * @param alg will be KMType.RSA or KMType.EC. - * @param privKeyBuf is the buffer to return the private key exponent in case of RSA or private + * @param privKeyBuf is the buffer that contains the private key exponent in case of RSA or private * key in case of EC. * @param privKeyStart is the start offset. * @param privKeyLength is the length of this private key buffer. - * @param pubModBuf is the buffer to return the modulus in case of RSA or public key in case of + * @param pubModBuf is the buffer that contains the modulus in case of RSA or public key in case of * EC. * @param pubModStart is the start of offset. * @param pubModLength is the length of this public key buffer. @@ -88,14 +90,14 @@ boolean importAsymmetricKey( /** * This is a oneshot operation that generates random number of desired length. * - * @param num is the buffer in which random number is returned to applet. + * @param num is the buffer in which random number is returned to the applet. * @param offset is start of the buffer. * @param length indicates the size of buffer and desired length of random number in bytes. */ void newRandomNumber(byte[] num, short offset, short length); /** - * This is a oneshot operation that adds the entropy to the entroy pool. This operation + * This is a oneshot operation that adds the entropy to the entropy pool. This operation * corresponds to addRndEntropy command. This method may ignore the added entropy value if the SE * provider does not support it. * @@ -108,14 +110,16 @@ boolean importAsymmetricKey( /** * This is a oneshot operation that generates and returns back a true random number. * - * @param num is the buffer in which entropy value is given. + * @param num is the buffer in which entropy value is returned. * @param offset is start of the buffer. * @param length length of the buffer. */ void getTrueRandomNumber(byte[] num, short offset, short length); /** - * This is a oneshot operation that performs encryption operation using AES GCM algorithm. + * This is a oneshot operation that performs encryption operation using AES GCM algorithm. It throws + * CryptoException if algorithm is not supported or if tag length is not equal to 16 or + * nonce length is not equal to 12. * * @param aesKey is the buffer that contains 128 bit or 256 bit aes key used to encrypt. * @param aesKeyStart is the start in aes key buffer. @@ -156,7 +160,8 @@ short aesGCMEncrypt( short authTagLen); /** - * This is a oneshot operation that performs decryption operation using AES GCM algorithm. + * This is a oneshot operation that performs decryption operation using AES GCM algorithm. It throws + * CryptoException if algorithm is not supported. * * @param aesKey is the buffer that contains 128 bit or 256 bit aes key used to encrypt. * @param aesKeyStart is the start in aes key buffer. @@ -164,7 +169,7 @@ short aesGCMEncrypt( * @param encData is the buffer of the input encrypted data. * @param encDataStart is the start of the encrypted data buffer. * @param encDataLen is the length of the data buffer. - * @param data is the buffer that contains output data to encrypt. + * @param data is the buffer that contains output decrypted data. * @param dataStart is the start of the data buffer. * @param nonce is the buffer of nonce. * @param nonceStart is the start of the nonce buffer. @@ -196,30 +201,7 @@ boolean aesGCMDecrypt( short authTagStart, short authTagLen); - /** - * This is a oneshot operation that performs signing using AES CCM algorithm. - * - * @param data is the input data buffer. - * @param dataStart is the start of the buffer. - * @param dataLen is the length of the input data - * @param aesKey is the aesKey buffer either 128 bit or 256 bit aes key. - * @param aesKeyStart is the start of the aes key. - * @param aesKeyLen is the length of the aes key buffer in bytes. - * @param signature is the output signature buffer. - * @param signatureStart is the start of the signature buffer. - * @return length of the signature buffer. - */ - short aesCCMSign( - byte[] data, - short dataStart, - short dataLen, - byte[] aesKey, - short aesKeyStart, - short aesKeyLen, - byte[] signature, - short signatureStart); - - /** + /** * This is a oneshot operation that performs key derivation function using cmac kdf (CKDF) as * defined in android keymaster hal definition. * @@ -299,7 +281,8 @@ boolean hmacVerify( /** * This is a oneshot operation that decrypts the data using RSA algorithm with oaep256 padding. - * The public exponent is always 0x010001. + * The public exponent is always 0x010001. It throws CryptoException if OAEP encoding validation + * fails. * * @param privExp is the private exponent (2048 bit) buffer. * @param privExpStart is the start of the private exponent buffer. @@ -309,8 +292,8 @@ boolean hmacVerify( * @param modLength is the length of the modulus 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. - * @param outputDataBuf is the buffer of the decrypted data buffer. + * @param inputDataLength is the length of the input data buffer in bytes. + * @param outputDataBuf is the output buffer that contains the decrypted data. * @param outputDataStart is the start of the output data buffer. * @return length of the decrypted data. */ @@ -336,11 +319,11 @@ short rsaDecipherOAEP256( * @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. - * @param outputDataBuf is the buffer of the decrypted data buffer. + * @param outputDataBuf is the output buffer that contains the signature. * @param outputDataStart is the start of the output data buffer. * @return length of the decrypted data. */ - public short ecSign256( + short ecSign256( byte[] secret, short secretStart, short secretLength, @@ -354,7 +337,7 @@ public short ecSign256( * This creates a persistent operation for signing, verify, encryption and decryption using HMAC, * AES and DES algorithms when keymaster hal's beginOperation function is executed. The * KMOperation instance can be reclaimed by the seProvider when KMOperation is finished or - * aborted. + * aborted. It throws CryptoException if algorithm is not supported. * * @param purpose is KMType.ENCRYPT or KMType.DECRYPT for AES and DES algorithm. It will be * KMType.SIGN and KMType.VERIFY for HMAC algorithm @@ -391,7 +374,8 @@ KMOperation initSymmetricOperation( * This creates a persistent operation for signing, verify, encryption and decryption using RSA * and EC algorithms when keymaster hal's beginOperation function is executed. For RSA the public * exponent is always 0x0100101. For EC the curve is always p256. The KMOperation instance can be - * reclaimed by the seProvider when KMOperation is finished or aborted. + * reclaimed by the seProvider when KMOperation is finished or aborted. It throws CryptoException + * if algorithm is not supported. * * @param purpose is KMType.ENCRYPT or KMType.DECRYPT for RSA. It will be * KMType.SIGN and * KMType.VERIFY for RSA and EC algorithms. @@ -439,12 +423,12 @@ KMOperation initAsymmetricOperation( * @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); + void persistPartialCertificateChain(byte[] buf, short offset, short len, short totalLen); /** * This operation clears the certificate chain from persistent memory. */ - public void clearCertificateChain(); + void clearCertificateChain(); /** * The operation reads the certificate chain from persistent memory. From f297133d7d5519212f453aba7ce7895d41ddaf09 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Wed, 20 Jan 2021 20:41:07 +0530 Subject: [PATCH 57/99] Remove trusted confirmation related code --- .../android/javacard/keymaster/KMUtils.java | 13 +++++----- .../android/javacard/keymaster/KMUtils.java | 14 +++++----- .../android/javacard/keymaster/KMError.java | 26 +++++++++---------- .../javacard/keymaster/KMKeymasterApplet.java | 1 - .../javacard/keymaster/KMOperationState.java | 22 ++-------------- .../javacard/keymaster/KMRepository.java | 4 +-- 6 files changed, 30 insertions(+), 50 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java index d9dce03b..08309f86 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java @@ -13,23 +13,23 @@ public class KMUtils { 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 + 0, 0, 0, 0, (byte) 0x9C,(byte) 0xBE, (byte) 0xBD, 0x50}; // 2629746000 msec public static final byte[] oneYearMsec = { - 0, 0, 0, 0x07, 0x57, (byte) 0xB1, 0x2C, 0x00 }; // 31536000000 msec + 0, 0, 0, 0x75, (byte) 0x8F, 0x0D, (byte) 0xFC, 0x00 }; // 31556952000 msec // Leap year + 3 yrs public static final byte[] fourYrsMsec = { - 0, 0, 0, 0x1D, 0x63, (byte) 0xEB, 0x0C, 0x00 }; // 126230400000 msec + 0, 0, 0, 0x1D, 0x63, (byte) 0xC3, 0x7F, 0x00 }; // 126227808000 msec public static final byte[] firstJan2020 = { - 0, 0, 0x01, 0x6F, 0x60, 0x1E, 0x5C, 0x00 }; // 1577865600000 msec + 0, 0, 0x01, 0x76, (byte) 0xBB, 0x3E, (byte) 0x70, 0x40 }; // 1609459200000 msec public static final byte[] firstJan2051 = { - 0, 0, 0x02, 0x53, 0x27, (byte) 0xC5, (byte) 0x90, 0x00 }; // 2556172800000 + 0, 0, 0x02, 0x53, 0x26, (byte) 0x0E, (byte) 0x1C, 0x00 }; // 2556144000000 // msec // -------------------------------------- public static short convertToDate(short time, byte[] scratchPad, boolean utcFlag) { short yrsCount = 0; - short monthCount = 0; + short monthCount = 1; short dayCount = 0; short hhCount = 0; short mmCount = 0; @@ -102,6 +102,7 @@ public static short convertToDate(short time, byte[] scratchPad, Util.arrayCopyNonAtomic(oneMonthMsec, (short) 0, scratchPad, (short) 8, (short) 8); monthCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); + monthCount++; Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, (short) 8); } diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java index 756c3150..08309f86 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java @@ -13,23 +13,23 @@ public class KMUtils { 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 + 0, 0, 0, 0, (byte) 0x9C,(byte) 0xBE, (byte) 0xBD, 0x50}; // 2629746000 msec public static final byte[] oneYearMsec = { - 0, 0, 0, 0x07, 0x57, (byte) 0xB1, 0x2C, 0x00 }; // 31536000000 msec + 0, 0, 0, 0x75, (byte) 0x8F, 0x0D, (byte) 0xFC, 0x00 }; // 31556952000 msec // Leap year + 3 yrs public static final byte[] fourYrsMsec = { - 0, 0, 0, 0x1D, 0x63, (byte) 0xEB, 0x0C, 0x00 }; // 126230400000 msec + 0, 0, 0, 0x1D, 0x63, (byte) 0xC3, 0x7F, 0x00 }; // 126227808000 msec public static final byte[] firstJan2020 = { - 0, 0, 0x01, 0x6F, 0x60, 0x1E, 0x5C, 0x00 }; // 1577865600000 msec + 0, 0, 0x01, 0x76, (byte) 0xBB, 0x3E, (byte) 0x70, 0x40 }; // 1609459200000 msec public static final byte[] firstJan2051 = { - 0, 0, 0x02, 0x53, 0x27, (byte) 0xC5, (byte) 0x90, 0x00 }; // 2556172800000 + 0, 0, 0x02, 0x53, 0x26, (byte) 0x0E, (byte) 0x1C, 0x00 }; // 2556144000000 // msec // -------------------------------------- public static short convertToDate(short time, byte[] scratchPad, boolean utcFlag) { short yrsCount = 0; - short monthCount = 0; + short monthCount = 1; short dayCount = 0; short hhCount = 0; short mmCount = 0; @@ -102,7 +102,7 @@ public static short convertToDate(short time, byte[] scratchPad, Util.arrayCopyNonAtomic(oneMonthMsec, (short) 0, scratchPad, (short) 8, (short) 8); monthCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); - monthCount =+ 1; + monthCount++; Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, (short) 8); } diff --git a/Applet/src/com/android/javacard/keymaster/KMError.java b/Applet/src/com/android/javacard/keymaster/KMError.java index abb0e6df..85c71654 100644 --- a/Applet/src/com/android/javacard/keymaster/KMError.java +++ b/Applet/src/com/android/javacard/keymaster/KMError.java @@ -85,20 +85,20 @@ public class KMError { 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 = 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; + public static short SW_CONDITIONS_NOT_SATISFIED = 10001; + public static short UNSUPPORTED_CLA = 10002; + public static short INVALID_P1P2 = 10003; + public static short UNSUPPORTED_INSTRUCTION = 10004; + public static short CMD_NOT_ALLOWED = 10005; + public static short SW_WRONG_LENGTH = 10006; + public static short INVALID_DATA = 10007; //Crypto errors - public static short CRYPTO_ILLEGAL_USE = 1008; - public static short CRYPTO_ILLEGAL_VALUE = 1009; - public static short CRYPTO_INVALID_INIT = 1010; - public static short CRYPTO_NO_SUCH_ALGORITHM = 1011; - public static short CRYPTO_UNINITIALIZED_KEY = 1012; + public static short CRYPTO_ILLEGAL_USE = 10008; + public static short CRYPTO_ILLEGAL_VALUE = 10009; + public static short CRYPTO_INVALID_INIT = 10010; + public static short CRYPTO_NO_SUCH_ALGORITHM = 10011; + public static short CRYPTO_UNINITIALIZED_KEY = 10012; //Generic Unknown error. - public static short GENERIC_UNKNOWN_ERROR = 1013; + public static short GENERIC_UNKNOWN_ERROR = 10013; } diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index febc7ec7..a37e6aa8 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -1624,7 +1624,6 @@ private void processFinishOperationCmd(APDU apdu) { } // Authorize the finish operation authorizeUpdateFinishOperation(op, scratchPad); - // Finish trusted Confirmation operation switch (op.getPurpose()) { case KMType.SIGN: case KMType.VERIFY: diff --git a/Applet/src/com/android/javacard/keymaster/KMOperationState.java b/Applet/src/com/android/javacard/keymaster/KMOperationState.java index 6647a6a8..347c9920 100644 --- a/Applet/src/com/android/javacard/keymaster/KMOperationState.java +++ b/Applet/src/com/android/javacard/keymaster/KMOperationState.java @@ -28,7 +28,7 @@ public class KMOperationState { public static final byte MAX_DATA = 20; - public static final byte MAX_REFS = 2; + public static final byte MAX_REFS = 1; private static final byte DATA = 0; private static final byte REFS = 1; // byte type @@ -53,9 +53,6 @@ public class KMOperationState { // Object References private static final byte OPERATION = 0; - private static final byte HMAC_SIGNER = 1; - - private static KMOperation hmacSigner; // used for trusted confirmation. private static KMOperation op; private static byte[] data; private static Object[] slot; @@ -85,14 +82,13 @@ public static KMOperationState read(Object[] slot) { Util.arrayCopy((byte[]) slot[DATA], (short) 0, data, (short) 0, (short) data.length); Object[] ops = ((Object[]) slot[REFS]); op = (KMOperation) ops[OPERATION]; - hmacSigner = (KMOperation) ops[HMAC_SIGNER]; KMOperationState.slot = slot; return opState; } public void persist() { if (!dFlag) return; - KMRepository.instance().persistOperation(data, Util.getShort(data, OP_HANDLE), op, hmacSigner); + KMRepository.instance().persistOperation(data, Util.getShort(data, OP_HANDLE), op); dFlag = false; } @@ -104,21 +100,8 @@ public short getKeySize() { return Util.getShort(data, KEY_SIZE); } - public void setTrustedConfirmationSigner(KMOperation hmacSigner) { - KMOperationState.hmacSigner = hmacSigner; - } - - public KMOperation getTrustedConfirmationSigner() { - return KMOperationState.hmacSigner; - } - - public boolean isTrustedConfirmationRequired() { - return KMOperationState.hmacSigner != null; - } - public void reset() { dFlag = false; - hmacSigner = null; op = null; slot = null; Util.arrayFillNonAtomic( @@ -135,7 +118,6 @@ public void release() { Util.arrayFillNonAtomic( (byte[]) slot[0], (short) 0, (short) ((byte[]) slot[0]).length, (byte) 0); ops[OPERATION] = null; - ops[HMAC_SIGNER] = null; JCSystem.commitTransaction(); reset(); } diff --git a/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/src/com/android/javacard/keymaster/KMRepository.java index 062e31b5..c2809c08 100644 --- a/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/Applet/src/com/android/javacard/keymaster/KMRepository.java @@ -148,7 +148,7 @@ public KMOperationState reserveOperation(){ } //TODO refactor following method - public void persistOperation(byte[] data, short opHandle, KMOperation op, KMOperation hmacSigner) { + public void persistOperation(byte[] data, short opHandle, KMOperation op) { short index = 0; byte[] opId; //Update an existing operation state. @@ -160,7 +160,6 @@ public void persistOperation(byte[] data, short opHandle, KMOperation op, KMOper Util.arrayCopy(data, (short) 0, (byte[]) slot[0], (short) 0, (short) ((byte[]) slot[0]).length); Object[] ops = ((Object[]) slot[1]); ops[0] = op; - ops[1] = hmacSigner; JCSystem.commitTransaction(); return; } @@ -178,7 +177,6 @@ public void persistOperation(byte[] data, short opHandle, KMOperation op, KMOper Util.arrayCopy(data, (short) 0, (byte[]) slot[0], (short) 0, (short) ((byte[]) slot[0]).length); Object[] ops = ((Object[]) slot[1]); ops[0] = op; - ops[1] = hmacSigner; JCSystem.commitTransaction(); break; } From 6c97a2578328a06d0c35378f58c8eac1e1f5ac89 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Wed, 20 Jan 2021 20:47:01 +0530 Subject: [PATCH 58/99] Corrected the extended error code values. --- .../4.1/JavacardKeymaster4Device.cpp | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp index 20e5cd5a..f422bc26 100644 --- a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp +++ b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp @@ -96,19 +96,19 @@ enum class Instruction { //Extended error codes enum ExtendedErrors { - SW_CONDITIONS_NOT_SATISFIED = -1001, - UNSUPPORTED_CLA = -1002, - INVALID_P1P2 = -1003, - UNSUPPORTED_INSTRUCTION = -1004, - CMD_NOT_ALLOWED = -1005, - SW_WRONG_LENGTH = -1006, - INVALID_DATA = -1007, - CRYPTO_ILLEGAL_USE = -1008, - CRYPTO_ILLEGAL_VALUE = -1009, - CRYPTO_INVALID_INIT = -1010, - CRYPTO_NO_SUCH_ALGORITHM = -1011, - CRYPTO_UNINITIALIZED_KEY = -1012, - GENERIC_UNKNOWN_ERROR = -1013 + SW_CONDITIONS_NOT_SATISFIED = -10001, + UNSUPPORTED_CLA = -10002, + INVALID_P1P2 = -10003, + UNSUPPORTED_INSTRUCTION = -10004, + CMD_NOT_ALLOWED = -10005, + SW_WRONG_LENGTH = -10006, + INVALID_DATA = -10007, + CRYPTO_ILLEGAL_USE = -10008, + CRYPTO_ILLEGAL_VALUE = -10009, + CRYPTO_INVALID_INIT = -10010, + CRYPTO_NO_SUCH_ALGORITHM = -10011, + CRYPTO_UNINITIALIZED_KEY = -10012, + GENERIC_UNKNOWN_ERROR = -10013 }; static inline std::unique_ptr& getTransportFactoryInstance() { @@ -176,7 +176,8 @@ static std::tuple, T> decodeData(CborConverter& cb, const std::unique_ptr item(nullptr); T errorCode = T::OK; std::tie(item, errorCode) = cb.decodeData(response, hasErrorCode); - if (ErrorCode::OK != errorCode) + + if (T::OK != errorCode) errorCode = translateExtendedErrorsToHalErrors(errorCode); return {std::move(item), errorCode}; } @@ -1285,8 +1286,8 @@ Return<::android::hardware::keymaster::V4_1::ErrorCode> JavacardKeymaster4Device 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); + std::tie(item, errorCode) = decodeData<::android::hardware::keymaster::V4_1::ErrorCode>( + cborConverter_, std::vector(cborOutData.begin(), cborOutData.end()-2), true); } return errorCode; } @@ -1302,8 +1303,8 @@ Return<::android::hardware::keymaster::V4_1::ErrorCode> JavacardKeymaster4Device 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); + std::tie(item, errorCode) = decodeData<::android::hardware::keymaster::V4_1::ErrorCode>( + cborConverter_, std::vector(cborOutData.begin(), cborOutData.end()-2), true); } return errorCode; } From 489e175a4ef80bd03e90f2ae8753b718d5c9cb17 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Wed, 20 Jan 2021 22:17:20 +0530 Subject: [PATCH 59/99] certificate chain input validation --- .../com/android/javacard/keymaster/KMAndroidSEProvider.java | 3 +++ .../src/com/android/javacard/keymaster/KMJCardSimulator.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java index e18ae600..b2833e8b 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java @@ -1143,6 +1143,9 @@ public void persistPartialCertificateChain(byte[] buf, short offset, short len, // 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. + if (totalLen > CERT_CHAIN_MAX_SIZE) { + KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + } short persistedLen = Util.getShort(certificateChain, (short) 0); if (persistedLen > totalLen) { KMException.throwIt(KMError.INVALID_INPUT_LENGTH); diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java index eb50fd6d..a9a6a937 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java @@ -1246,6 +1246,9 @@ public void persistPartialCertificateChain(byte[] buf, short offset, // 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. + if (totalLen > CERT_CHAIN_MAX_SIZE) { + KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + } short persistedLen = Util.getShort(certificateChain, (short) 0); if (persistedLen > totalLen) { KMException.throwIt(KMError.INVALID_INPUT_LENGTH); From 7d34a133433ab6de1fedfb692f976b9ad678c148 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Thu, 21 Jan 2021 12:18:38 +0530 Subject: [PATCH 60/99] 1. Renamed INS_SHARED_SECRET to INS_PRESHARED_SECRET. 2. Removed AuthorityKeyIdentifier. --- .../keymaster/KMAttestationCertImpl.java | 93 +------------------ .../keymaster/KMAttestationCertImpl.java | 81 ---------------- .../javacard/keymaster/KMAttestationCert.java | 8 -- .../javacard/keymaster/KMKeymasterApplet.java | 26 ++---- .../javacard/keymaster/KMRepository.java | 48 ++++------ 5 files changed, 32 insertions(+), 224 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java index 40bd751b..5a36e3c3 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -30,8 +30,6 @@ public class KMAttestationCertImpl implements KMAttestationCert { 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}; private static final short ECDSA_MAX_SIG_LEN = 72; //Signature algorithm identifier - always ecdsaWithSha256 - 1.2.840.10045.4.3.2 @@ -95,7 +93,6 @@ public class KMAttestationCertImpl implements KMAttestationCert { private static short verifiedBootKey; private static byte verifiedState; private static short verifiedHash; - private static short authKey; private static short issuer; private static short signPriv; @@ -138,7 +135,6 @@ private static void init() { verifiedState = 0; rsaCert = true; deviceLocked = 0; - authKey = 0; signPriv = 0; } @@ -148,12 +144,6 @@ public KMAttestationCert verifiedBootHash(short obj) { return this; } - @Override - public KMAttestationCert authKey(short obj) { - authKey = obj; - return this; - } - @Override public KMAttestationCert verifiedBootKey(short obj) { verifiedBootKey = obj; @@ -259,46 +249,6 @@ private void createKeyUsage(short tag) { } } - 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(); @@ -335,7 +285,6 @@ 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); @@ -480,19 +429,13 @@ private static void pushKeyDescription() { 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 = { 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 { - /* - if(tagIds[index] == KMType.ATTESTATION_APPLICATION_ID) { - pushAttIds(tagIds[index]); - continue; - } - */ pushParams(swParams, swParamsIndex, tagIds[index]); } while (++index < tagIds.length); pushSequenceHeader((short) (last - stackPtr)); @@ -500,7 +443,7 @@ private static void pushSWParams() { private static void pushHWParams() { short last = stackPtr; - // Attestation ids are not included. As per VTS attestation ids are not supported currenlty. + // Below are the allowed hardwareEnforced Authorization tags inside the attestation certificate's extension. short[] tagIds = { KMType.BOOT_PATCH_LEVEL, KMType.VENDOR_PATCH_LEVEL, KMType.OS_PATCH_LEVEL, KMType.OS_VERSION, KMType.ROOT_OF_TRUST, @@ -511,9 +454,9 @@ private static void pushHWParams() { 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; if (tagIds[index] == KMType.ROOT_OF_TRUST) { pushRoT(); continue; @@ -600,7 +543,6 @@ private static void pushTag(short tag) { // } private static void pushRoT() { short last = stackPtr; - byte val = 0x00; // verified boot hash // pushOctetString(repo.verifiedBootHash, (short) 0, (short) repo.verifiedBootHash.length); pushOctetString( @@ -764,39 +706,10 @@ private static void pushKeyUsage(byte keyUsage, byte unusedBits) { 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( - 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); diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java index 136ec4ba..cd9567d3 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -30,8 +30,6 @@ public class KMAttestationCertImpl implements KMAttestationCert { 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}; private static final short ECDSA_MAX_SIG_LEN = 72; //Signature algorithm identifier - always ecdsaWithSha256 - 1.2.840.10045.4.3.2 @@ -95,7 +93,6 @@ public class KMAttestationCertImpl implements KMAttestationCert { private static short verifiedBootKey; private static byte verifiedState; private static short verifiedHash; - private static short authKey; private static short issuer; private static short signPriv; @@ -138,7 +135,6 @@ private static void init() { verifiedState = 0; rsaCert = true; deviceLocked = 0; - authKey = 0; signPriv = 0; } @@ -148,12 +144,6 @@ public KMAttestationCert verifiedBootHash(short obj) { return this; } - @Override - public KMAttestationCert authKey(short obj) { - authKey = obj; - return this; - } - @Override public KMAttestationCert verifiedBootKey(short obj) { verifiedBootKey = obj; @@ -259,46 +249,6 @@ private void createKeyUsage(short tag) { } } - 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(); @@ -335,7 +285,6 @@ 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); @@ -594,7 +543,6 @@ private static void pushTag(short tag) { // } private static void pushRoT() { short last = stackPtr; - byte val = 0x00; // verified boot hash // pushOctetString(repo.verifiedBootHash, (short) 0, (short) repo.verifiedBootHash.length); pushOctetString( @@ -758,39 +706,10 @@ private static void pushKeyUsage(byte keyUsage, byte unusedBits) { 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( - 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); diff --git a/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java b/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java index f15fbfcb..d27f015a 100644 --- a/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java +++ b/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java @@ -32,14 +32,6 @@ public interface KMAttestationCert { */ KMAttestationCert verifiedBootState(byte val); - /** - * Set authentication key Id from CA Certificate set during provisioning. - * - * @param obj This is a KMByteBlob containing authentication Key Id. - * @return instance of KMAttestationCert - */ - KMAttestationCert authKey(short obj); - /** * Set uniqueId received from CA certificate during provisioning. * diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index a37e6aa8..a1157f34 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -75,7 +75,7 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe 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_PROVISION_PRESHARED_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 @@ -113,7 +113,7 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe 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_PRESHARED_SECRET = 0x10; private static final byte PROVISION_STATUS_BOOT_PARAM = 0x20; private static final byte PROVISION_STATUS_PROVISIONING_LOCKED = 0x40; @@ -339,9 +339,9 @@ public void process(APDU apdu) { sendError(apdu, KMError.OK); return; - case INS_PROVISION_SHARED_SECRET_CMD: + case INS_PROVISION_PRESHARED_SECRET_CMD: processProvisionSharedSecretCmd(apdu); - provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_SHARED_SECRET; + provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_PRESHARED_SECRET; sendError(apdu, KMError.OK); return; @@ -461,9 +461,11 @@ && isProvisioningComplete())) { sendError(apdu, mapISOErrorToKMError(exp.getReason())); freeOperations(); } catch (CryptoException e) { + e.printStackTrace(); freeOperations(); sendError(apdu, mapCryptoErrorToKMError(e.getReason())); } catch (Exception e) { + e.printStackTrace(); freeOperations(); sendError(apdu, KMError.GENERIC_UNKNOWN_ERROR); } finally { @@ -476,7 +478,7 @@ 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_PRESHARED_SECRET)) && (0 != (provisionStatus & PROVISION_STATUS_BOOT_PARAM))) { return true; } else { @@ -632,10 +634,9 @@ private void processProvisionAttestationCertParams(APDU apdu) { receiveIncoming(apdu); // Arguments short blob = KMByteBlob.exp(); - short argsProto = KMArray.instance((short) 3); + short argsProto = KMArray.instance((short) 2); 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); //reclaim memory @@ -654,13 +655,6 @@ private void processProvisionAttestationCertParams(APDU apdu) { 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) 2); - repository.setAuthKeyId( - KMByteBlob.cast(tmpVariables[0]).getBuffer(), - KMByteBlob.cast(tmpVariables[0]).getStartOff(), - KMByteBlob.cast(tmpVariables[0]).length()); } private void processProvisionAttestationCertChainCmd(APDU apdu) { @@ -1438,9 +1432,7 @@ private void processAttestKeyCmd(APDU apdu) { addTags(KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getHardwareEnforced(), true, cert); addTags( KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getSoftwareEnforced(), false, cert); - if (repository.getAuthKeyId() != 0) { - cert.authKey(repository.getAuthKeyId()); - } + cert.deviceLocked(repository.getDeviceLock()); cert.issuer(repository.getIssuer()); cert.publicKey(data[PUB_KEY]); diff --git a/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/src/com/android/javacard/keymaster/KMRepository.java index c2809c08..4bcdf28b 100644 --- a/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/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 = 33; + public static final short DATA_INDEX_SIZE = 32; public static final short DATA_INDEX_ENTRY_SIZE = 4; public static final short DATA_MEM_SIZE = 2048; public static final short HEAP_SIZE = 10000; @@ -50,26 +50,25 @@ public class KMRepository implements KMUpgradable { public static final byte ATT_ID_MANUFACTURER = 6; public static final byte ATT_ID_MODEL = 7; 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 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; + public static final byte CERT_ISSUER = 13; + public static final byte CERT_EXPIRY_TIME = 14; + public static final byte BOOT_OS_VERSION = 15; + public static final byte BOOT_OS_PATCH = 16; + public static final byte VENDOR_PATCH_LEVEL = 17; + public static final byte BOOT_PATCH_LEVEL = 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; // Data Item sizes public static final short MASTER_KEY_SIZE = 16; @@ -567,13 +566,6 @@ public void setCertExpiryTime(byte[] buf, short start, short len) { writeDataEntry(CERT_EXPIRY_TIME, buf,start,len); } - public short getAuthKeyId() { - return readData(CERT_AUTH_KEY_ID); - } - - public void setAuthKeyId(byte[] buf, short start, short len) { - writeDataEntry(CERT_AUTH_KEY_ID,buf,start,len); - } private static final byte[] zero = {0,0,0,0,0,0,0,0}; public short getOsVersion(){ From 606138149106d4dee78adc51eb2b589e73a445d4 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Thu, 21 Jan 2021 14:19:13 +0530 Subject: [PATCH 61/99] Fixed the issue with KMFunctionalTest --- .../src/com/android/javacard/keymaster/KMUtils.java | 2 +- .../src/com/android/javacard/keymaster/KMUtils.java | 2 +- .../com/android/javacard/test/KMFunctionalTest.java | 13 +++++-------- .../javacard/keymaster/KMKeymasterApplet.java | 2 -- 4 files changed, 7 insertions(+), 12 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java index 08309f86..2e0f8d99 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java @@ -20,7 +20,7 @@ public class KMUtils { public static final byte[] fourYrsMsec = { 0, 0, 0, 0x1D, 0x63, (byte) 0xC3, 0x7F, 0x00 }; // 126227808000 msec public static final byte[] firstJan2020 = { - 0, 0, 0x01, 0x76, (byte) 0xBB, 0x3E, (byte) 0x70, 0x40 }; // 1609459200000 msec + 0, 0, 0x01, 0x6F, 0x5E, 0x66, (byte)0xE8, 0x00 }; // 1577836800000 msec public static final byte[] firstJan2051 = { 0, 0, 0x02, 0x53, 0x26, (byte) 0x0E, (byte) 0x1C, 0x00 }; // 2556144000000 // msec diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java index 08309f86..4569fb15 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java @@ -20,7 +20,7 @@ public class KMUtils { public static final byte[] fourYrsMsec = { 0, 0, 0, 0x1D, 0x63, (byte) 0xC3, 0x7F, 0x00 }; // 126227808000 msec public static final byte[] firstJan2020 = { - 0, 0, 0x01, 0x76, (byte) 0xBB, 0x3E, (byte) 0x70, 0x40 }; // 1609459200000 msec + 0, 0, 0x01, 0x6F, 0x5E, 0x66, (byte)0xE8, 0x00 }; // 1577836800000 msec public static final byte[] firstJan2051 = { 0, 0, 0x02, 0x53, 0x26, (byte) 0x0E, (byte) 0x1C, 0x00 }; // 2556144000000 // msec diff --git a/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java b/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java index fb248f2d..0e6408d2 100644 --- a/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java +++ b/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java @@ -59,7 +59,7 @@ public class KMFunctionalTest { 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_PROVISION_PRESHARED_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 @@ -538,16 +538,13 @@ private void provisionSigningKey(CardSimulator simulator) { private void provisionCertificateParams(CardSimulator simulator) { - short arrPtr = KMArray.instance((short) 3); + short arrPtr = KMArray.instance((short) 2); 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); @@ -565,7 +562,7 @@ private void provisionSharedSecret(CardSimulator simulator) { (short) sharedKeySecret.length); KMArray.cast(arrPtr).add((short) 0, byteBlob); - CommandAPDU apdu = encodeApdu((byte) INS_PROVISION_SHARED_SECRET_CMD, + CommandAPDU apdu = encodeApdu((byte) INS_PROVISION_PRESHARED_SECRET_CMD, arrPtr); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); @@ -1622,11 +1619,11 @@ public void testImportWrappedKey(){ byte[] nonce = new byte[12]; cryptoProvider.newRandomNumber(nonce,(short)0,(short)12); byte[] authData = "Auth Data".getBytes(); - byte[] authTag = new byte[12]; + byte[] authTag = new byte[16]; 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); + authTag, (short)0, (short)16); 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++){ diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index a1157f34..b9ae5ce4 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -461,11 +461,9 @@ && isProvisioningComplete())) { sendError(apdu, mapISOErrorToKMError(exp.getReason())); freeOperations(); } catch (CryptoException e) { - e.printStackTrace(); freeOperations(); sendError(apdu, mapCryptoErrorToKMError(e.getReason())); } catch (Exception e) { - e.printStackTrace(); freeOperations(); sendError(apdu, KMError.GENERIC_UNKNOWN_ERROR); } finally { From 2023d6da399ffc2b377b6e3c7b605a8d85af0873 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Thu, 21 Jan 2021 14:23:56 +0530 Subject: [PATCH 62/99] Renamed SHARED_SECRET to PRESHARED_SECRET --- HAL/keymaster/4.1/Provision.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/HAL/keymaster/4.1/Provision.cpp b/HAL/keymaster/4.1/Provision.cpp index 34b6420d..e90cd7ef 100644 --- a/HAL/keymaster/4.1/Provision.cpp +++ b/HAL/keymaster/4.1/Provision.cpp @@ -49,7 +49,7 @@ enum class Instruction { 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_PROVISION_PRESHARED_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, @@ -61,7 +61,7 @@ enum ProvisionStatus { PROVISION_STATUS_ATTESTATION_CERT_CHAIN = 0x02, PROVISION_STATUS_ATTESTATION_CERT_PARAMS = 0x04, PROVISION_STATUS_ATTEST_IDS = 0x08, - PROVISION_STATUS_SHARED_SECRET = 0x10, + PROVISION_STATUS_PRESHARED_SECRET = 0x10, PROVISION_STATUS_BOOT_PARAM = 0x20, PROVISION_STATUS_PROVISIONING_LOCKED = 0x40, }; @@ -406,7 +406,7 @@ static ErrorCode provisionAttestationIDs(std::unique_ptr& transport) { ErrorCode errorCode = ErrorCode::OK; cppbor::Array array; - Instruction ins = Instruction::INS_PROVISION_SHARED_SECRET_CMD; + Instruction ins = Instruction::INS_PROVISION_PRESHARED_SECRET_CMD; std::vector response; std::vector masterKey(kFakeKeyAgreementKey, kFakeKeyAgreementKey + sizeof(kFakeKeyAgreementKey)/sizeof(kFakeKeyAgreementKey[0])); @@ -484,7 +484,7 @@ static bool isSEProvisioned(uint64_t status) { 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_PRESHARED_SECRET | ProvisionStatus::PROVISION_STATUS_BOOT_PARAM |ProvisionStatus::PROVISION_STATUS_PROVISIONING_LOCKED)) { ret = false; } From 5aae09d3dcc008e3d855ebf5f36f77337c4e01c4 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Thu, 21 Jan 2021 17:18:47 +0530 Subject: [PATCH 63/99] Corrected the month milliseconds hex value --- .../src/com/android/javacard/keymaster/KMUtils.java | 2 +- .../src/com/android/javacard/keymaster/KMUtils.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java index 2e0f8d99..d9d7e111 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java @@ -15,7 +15,7 @@ public class KMUtils { public static final byte[] oneMonthMsec = { 0, 0, 0, 0, (byte) 0x9C,(byte) 0xBE, (byte) 0xBD, 0x50}; // 2629746000 msec public static final byte[] oneYearMsec = { - 0, 0, 0, 0x75, (byte) 0x8F, 0x0D, (byte) 0xFC, 0x00 }; // 31556952000 msec + 0, 0, 0, 0x07, 0x58, (byte) 0xF0, (byte) 0xDF, (byte) 0xC0 }; // 31556952000 msec // Leap year + 3 yrs public static final byte[] fourYrsMsec = { 0, 0, 0, 0x1D, 0x63, (byte) 0xC3, 0x7F, 0x00 }; // 126227808000 msec diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java index 4569fb15..41bbe1ff 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java @@ -15,7 +15,7 @@ public class KMUtils { public static final byte[] oneMonthMsec = { 0, 0, 0, 0, (byte) 0x9C,(byte) 0xBE, (byte) 0xBD, 0x50}; // 2629746000 msec public static final byte[] oneYearMsec = { - 0, 0, 0, 0x75, (byte) 0x8F, 0x0D, (byte) 0xFC, 0x00 }; // 31556952000 msec + 0, 0, 0, 0x07, 0x58, (byte) 0xF0, (byte) 0xDF, (byte) 0xC0 }; // 31556952000 msec // Leap year + 3 yrs public static final byte[] fourYrsMsec = { 0, 0, 0, 0x1D, 0x63, (byte) 0xC3, 0x7F, 0x00 }; // 126227808000 msec From 3dadaad1d7e0d51ed674780d612d0368d5a17412 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Thu, 21 Jan 2021 17:25:31 +0530 Subject: [PATCH 64/99] Removed authenticationIdentifier from cert params --- HAL/keymaster/4.1/Provision.cpp | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/HAL/keymaster/4.1/Provision.cpp b/HAL/keymaster/4.1/Provision.cpp index e90cd7ef..6249e34d 100644 --- a/HAL/keymaster/4.1/Provision.cpp +++ b/HAL/keymaster/4.1/Provision.cpp @@ -125,28 +125,6 @@ static inline void getDerSubjectName(X509* x509, std::vector& subject) 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) { @@ -334,7 +312,6 @@ static ErrorCode provisionAttestationCertificateParams(std::unique_ptr 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. */ @@ -345,8 +322,6 @@ static ErrorCode provisionAttestationCertificateParams(std::unique_ptr cborData = array.encode(); if(ErrorCode::OK != (errorCode = sendProvisionData(transport, ins, cborData, response))) { From ee1228fc070a8e927e6d19eec934a34b66905b77 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Thu, 21 Jan 2021 20:37:58 +0530 Subject: [PATCH 65/99] Fixed the issue with keyblob decryption with AndroidSEProvider --- .../com/android/javacard/keymaster/KMAndroidSEProvider.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java index b2833e8b..4b0994f4 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java @@ -643,8 +643,8 @@ public boolean aesGCMDecrypt(byte[] aesKey, short aesKeyStart, // encrypt the secret aesGcmCipher.doFinal(encSecret, encSecretStart, encSecretLen, secret, secretStart); - verification = aesGcmCipher.verifyTag(authTag, authTagStart, (short) 12, - (short) 12); + verification = aesGcmCipher.verifyTag(authTag, authTagStart, (short) authTagLen, + (short) AES_GCM_TAG_LENGTH); return verification; } From f21600112c2211c3fe5d7da485890dbe77f67208 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Fri, 22 Jan 2021 16:34:29 +0530 Subject: [PATCH 66/99] Remove MAX_USES_PER_BOOT related code as it is not supported by strongbox --- .../javacard/keymaster/KMKeyParameters.java | 4 +- .../javacard/keymaster/KMKeymasterApplet.java | 59 +------- .../javacard/keymaster/KMRepository.java | 137 +----------------- 3 files changed, 7 insertions(+), 193 deletions(-) diff --git a/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java b/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java index 8c8475ac..f08ee388 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java @@ -108,6 +108,7 @@ public static boolean hasUnsupportedTags(short keyParamsPtr) { KMType.BOOL_TAG, KMType.TRUSTED_USER_PRESENCE_REQUIRED, KMType.BOOL_TAG, KMType.ALLOW_WHILE_ON_BODY, KMType.UINT_TAG, KMType.MIN_SEC_BETWEEN_OPS, + KMType.UINT_TAG, KMType.MAX_USES_PER_BOOT }; byte index = 0; short tagInd; @@ -148,15 +149,12 @@ public static short makeHwEnforced(short keyParamsPtr, byte origin, KMType.ENUM_ARRAY_TAG, KMType.DIGEST, KMType.ENUM_ARRAY_TAG, KMType.PADDING, KMType.ENUM_ARRAY_TAG, KMType.BLOCK_MODE, - KMType.UINT_TAG, KMType.MIN_SEC_BETWEEN_OPS, - KMType.UINT_TAG, KMType.MAX_USES_PER_BOOT, KMType.ULONG_ARRAY_TAG, KMType.USER_SECURE_ID, KMType.BOOL_TAG, KMType.NO_AUTH_REQUIRED, KMType.UINT_TAG, KMType.AUTH_TIMEOUT, KMType.BOOL_TAG, KMType.CALLER_NONCE, KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, KMType.ENUM_TAG, KMType.ECCURVE, - KMType.BOOL_TAG, KMType.TRUSTED_CONFIRMATION_REQUIRED, KMType.BOOL_TAG, KMType.INCLUDE_UNIQUE_ID, KMType.BOOL_TAG, KMType.ROLLBACK_RESISTANCE, KMType.ENUM_TAG, KMType.USER_AUTH_TYPE, diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index b9ae5ce4..467fe81a 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -901,7 +901,6 @@ private void processGetHmacSharingParamCmd(APDU apdu) { private void processDeleteAllKeysCmd(APDU apdu) { // No arguments - repository.removeAllAuthTags(); // Send ok sendError(apdu, KMError.OK); } @@ -943,12 +942,6 @@ private void processDeleteKeyCmd(APDU apdu) { if (tmpVariables[0] < 4) { KMException.throwIt(KMError.INVALID_KEY_BLOB); } - // Validate Auth Tag - data[AUTH_TAG] = KMArray.cast(data[KEY_BLOB]).get(KEY_BLOB_AUTH_TAG); - if (repository.validateAuthTag(data[AUTH_TAG])) { - // delete the auth tag - repository.removeAuthTag(data[AUTH_TAG]); - } // Send ok sendError(apdu, KMError.OK); } @@ -1156,19 +1149,11 @@ private void processUpgradeKeyCmd(APDU apdu) { } } - boolean blobPersisted = false; if (tmpVariables[5] != KMError.INVALID_ARGUMENT) { - if (repository.validateAuthTag(data[AUTH_TAG])) { - repository.removeAuthTag(data[AUTH_TAG]); - blobPersisted = true; - } // copy origin data[ORIGIN] = KMEnumTag.getValue(KMType.ORIGIN, data[HW_PARAMETERS]); // create new key blob with current os version etc. createEncryptedKeyBlob(scratchPad); - if (blobPersisted) { - repository.persistAuthTag(data[AUTH_TAG]); - } } else { data[KEY_BLOB] = KMByteBlob.instance((short) 0); } @@ -2452,7 +2437,6 @@ private void authorizeAndBeginOperation(KMOperationState op, byte[] scratchPad) authorizeDigest(op); authorizePadding(op); authorizeBlockModeAndMacLength(op); - authorizeKeyUsageForCount(); if (!validateHwToken(data[HW_TOKEN], scratchPad)) { data[HW_TOKEN] = KMType.INVALID_VALUE; } @@ -2798,25 +2782,6 @@ private boolean validateHwToken(short hwToken, byte[] scratchPad) { KMByteBlob.cast(ptr).length()); } - private void authorizeKeyUsageForCount() { - // TODO currently only short usageLimit supported - max count 32K. - short usageLimit = - KMIntegerTag.getShortValue(KMType.UINT_TAG, KMType.MAX_USES_PER_BOOT, data[HW_PARAMETERS]); - if (usageLimit == KMType.INVALID_VALUE) return; - // get current counter - short usage = repository.getRateLimitedKeyCount(data[AUTH_TAG]); - if (usage != KMType.INVALID_VALUE) { - if (usage < usageLimit) { - KMException.throwIt(KMError.KEY_MAX_OPS_EXCEEDED); - } - // increment the counter and store it back. - usage++; - repository.setRateLimitedKeyCount(data[AUTH_TAG], usage); - } else { - KMException.throwIt(KMError.UNKNOWN_ERROR); - } - } - private void processImportKeyCmd(APDU apdu) { // Receive the incoming request fully from the master into buffer. receiveIncoming(apdu); @@ -2863,6 +2828,11 @@ private void importKey(APDU apdu, byte[] scratchPad) { if (tmpVariables[3] == KMType.INVALID_VALUE) { KMException.throwIt(KMError.INVALID_ARGUMENT); } + + //Check if the tags are supported. + if(KMKeyParameters.hasUnsupportedTags(data[KEY_PARAMETERS])) { + KMException.throwIt(KMError.UNSUPPORTED_TAG); + } // Check algorithm and dispatch to appropriate handler. switch (tmpVariables[3]) { case KMType.RSA: @@ -2886,15 +2856,6 @@ private void importKey(APDU apdu, byte[] scratchPad) { } // create key blob createEncryptedKeyBlob(scratchPad); - tmpVariables[0] = - KMIntegerTag.getShortValue(KMType.UINT_TAG, KMType.MAX_USES_PER_BOOT, data[KEY_PARAMETERS]); - if (tmpVariables[0] != KMType.INVALID_VALUE) { - // before generating key, check whether max count reached - if (repository.getKeyBlobCount() > KMRepository.MAX_BLOB_STORAGE) { - KMException.throwIt(KMError.UNKNOWN_ERROR); - } - repository.persistAuthTag(data[AUTH_TAG]); - } // prepare the response tmpVariables[0] = KMArray.instance((short) 3); @@ -3407,16 +3368,6 @@ private static void processGenerateKey(APDU apdu) { data[ORIGIN] = KMType.GENERATED; createEncryptedKeyBlob(scratchPad); - tmpVariables[0] = - KMIntegerTag.getShortValue(KMType.UINT_TAG, KMType.MAX_USES_PER_BOOT, data[KEY_PARAMETERS]); - if (tmpVariables[0] != KMType.INVALID_VALUE) { - // before generating key, check whether max count reached - if (repository.getKeyBlobCount() > KMRepository.MAX_BLOB_STORAGE) { - KMException.throwIt(KMError.UNKNOWN_ERROR); - } - repository.persistAuthTag(data[AUTH_TAG]); - } - // prepare the response tmpVariables[0] = KMArray.instance((short) 3); KMArray.cast(tmpVariables[0]).add((short) 0, KMInteger.uint_16(KMError.OK)); diff --git a/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/src/com/android/javacard/keymaster/KMRepository.java index 4bcdf28b..2b95697a 100644 --- a/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/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 = 32; + public static final short DATA_INDEX_SIZE = 24; public static final short DATA_INDEX_ENTRY_SIZE = 4; public static final short DATA_MEM_SIZE = 2048; public static final short HEAP_SIZE = 10000; @@ -61,14 +61,6 @@ public class KMRepository implements KMUpgradable { 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; // Data Item sizes public static final short MASTER_KEY_SIZE = 16; @@ -82,9 +74,6 @@ public class KMRepository implements KMUpgradable { 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; - public static final short MAX_BLOB_STORAGE = 8; - public static final short AUTH_TAG_LENGTH = 16; - 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; @@ -398,120 +387,6 @@ 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); - 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 +1), - (short) 0); - short index = 0; - while (index < MAX_BLOB_STORAGE) { - 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++; - } - } - - public boolean validateAuthTag(short authTag) { - short tag = findTag(authTag); - return tag !=KMType.INVALID_VALUE; - } - - public void removeAuthTag(short authTag) { - short tag = findTag(authTag); - if(tag ==KMType.INVALID_VALUE) KMException.throwIt(KMError.UNKNOWN_ERROR); - clearDataEntry(tag); - } - - public void removeAllAuthTags() { - short index = 0; - while (index < MAX_BLOB_STORAGE) { - clearDataEntry((short)(index+AUTH_TAG_1)); - index++; - } - } - - private short findTag(short authTag) { - if(KMByteBlob.cast(authTag).length() != AUTH_TAG_LENGTH)KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - short index = 0; - short found; - short offset = alloc(AUTH_TAG_ENTRY_SIZE); - while (index < MAX_BLOB_STORAGE) { - if (dataLength((short)(index+AUTH_TAG_1)) != 0) { - readDataEntry((short)(index+AUTH_TAG_1), - getHeap(), offset); - found = - Util.arrayCompare( - getHeap(), - (short)(offset+1), - KMByteBlob.cast(authTag).getBuffer(), - KMByteBlob.cast(authTag).getStartOff(), - AUTH_TAG_LENGTH); - if(found == 0)return (short)(index+AUTH_TAG_1); - } - index++; - } - return KMType.INVALID_VALUE; - } - - public short getRateLimitedKeyCount(short authTag) { - short tag = findTag(authTag); - short blob; - if (tag != KMType.INVALID_VALUE) { - blob = readData(tag); - return Util.getShort(KMByteBlob.cast(blob).getBuffer(), - (short)(KMByteBlob.cast(blob).getStartOff()+AUTH_TAG_LENGTH+1)); - } - return KMType.INVALID_VALUE; - } - - public void setRateLimitedKeyCount(short authTag, short val) { - short tag = findTag(authTag); - if (tag != KMType.INVALID_VALUE) { - 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()); - } - } - - public void persistAttestationKey(short secret) { writeDataEntry(ATT_EC_KEY, KMByteBlob.cast(secret).getBuffer(), @@ -703,16 +578,6 @@ public void setBootState(byte state){ writeDataEntry(BOOT_VERIFIED_BOOT_STATE,getHeap(),start,BOOT_STATE_SIZE); } - public short getKeyBlobCount(){ - byte index = 0; - byte count = 0; - while(index < MAX_BLOB_STORAGE){ - if(dataLength((short)(index+AUTH_TAG_1)) != 0) count++; - index++; - } - return count; - } - @Override public void onSave(Element ele) { ele.write(dataIndex); From fe1f2fc5a710a58bc4bf1b188ddfc14b88d21463 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Sat, 23 Jan 2021 00:34:50 +0530 Subject: [PATCH 67/99] generate random number for operation handle --- .../javacard/test/KMFunctionalTest.java | 20 ++- .../javacard/keymaster/KMKeymasterApplet.java | 30 +++-- .../javacard/keymaster/KMOperationState.java | 11 +- .../javacard/keymaster/KMRepository.java | 127 ++++++++++++------ 4 files changed, 126 insertions(+), 62 deletions(-) diff --git a/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java b/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java index 0e6408d2..74892031 100644 --- a/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java +++ b/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java @@ -2241,10 +2241,13 @@ public void testAbortOperation(){ 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)); + byte[] opHandleBuf = new byte[KMRepository.OPERATION_HANDLE_SIZE]; + KMInteger.cast(opHandle).getValue(opHandleBuf, (short) 0, (short) opHandleBuf.length); + opHandle = KMInteger.uint_64(opHandleBuf, (short) 0); + abort(opHandle); short dataPtr = KMByteBlob.instance(plainData, (short) 0, (short) plainData.length); - ret = update(KMInteger.uint_16(opHandle), dataPtr, (short) 0, (short) 0, (short) 0); + opHandle = KMInteger.uint_64(opHandleBuf, (short) 0); + ret = update(opHandle, dataPtr, (short) 0, (short) 0, (short) 0); Assert.assertEquals(KMError.INVALID_OPERATION_HANDLE,ret); cleanUp(); } @@ -2513,7 +2516,8 @@ public short processMessage( boolean aesGcmFlag) { short beginResp = begin(keyPurpose, keyBlob, inParams, hwToken); short opHandle = KMArray.cast(beginResp).get((short) 2); - opHandle = KMInteger.cast(opHandle).getShort(); + byte[] opHandleBuf = new byte[KMRepository.OPERATION_HANDLE_SIZE]; + KMInteger.cast(opHandle).getValue(opHandleBuf, (short) 0, (short) opHandleBuf.length); short dataPtr = KMByteBlob.instance(data, (short) 0, (short) data.length); short ret = KMType.INVALID_VALUE; byte[] outputData = new byte[128]; @@ -2537,7 +2541,8 @@ public short processMessage( KMArray.cast(inParams).add((short)0, associatedData); inParams = KMKeyParameters.instance(inParams); } - ret = update(KMInteger.uint_16(opHandle), dataPtr, inParams, (short) 0, (short) 0); + opHandle = KMInteger.uint_64(opHandleBuf, (short) 0); + ret = update(opHandle, dataPtr, inParams, (short) 0, (short) 0); dataPtr = KMArray.cast(ret).get((short) 3); if (KMByteBlob.cast(dataPtr).length() > 0) { Util.arrayCopyNonAtomic( @@ -2553,10 +2558,11 @@ public short processMessage( } } + opHandle = KMInteger.uint_64(opHandleBuf, (short) 0); if (keyPurpose == KMType.VERIFY) { - ret = finish(KMInteger.uint_16(opHandle), dataPtr, signature, (short) 0, (short) 0, (short) 0); + ret = finish(opHandle, dataPtr, signature, (short) 0, (short) 0, (short) 0); } else { - ret = finish(KMInteger.uint_16(opHandle), dataPtr, null, (short) 0, (short) 0, (short) 0); + ret = finish(opHandle, dataPtr, null, (short) 0, (short) 0, (short) 0); } if(len >0){ dataPtr = KMArray.cast(ret).get((short)2); diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 467fe81a..a85a7243 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -472,6 +472,12 @@ && isProvisioningComplete())) { } } + private void generateUniqueOperationHandle(byte[] buf, short offset, short len) { + do { + seProvider.newRandomNumber(buf, offset, len); + } while (null != repository.findOperation(buf, offset, len)); + } + private boolean isProvisioningComplete() { if((0 != (provisionStatus & PROVISION_STATUS_ATTESTATION_KEY)) && (0 != (provisionStatus & PROVISION_STATUS_ATTESTATION_CERT_CHAIN)) @@ -486,7 +492,7 @@ private boolean isProvisioningComplete() { private void freeOperations() { if (data[OP_HANDLE] != KMType.INVALID_VALUE) { - KMOperationState op = repository.findOperation(KMInteger.cast(data[OP_HANDLE]).getShort()); + KMOperationState op = repository.findOperation(data[OP_HANDLE]); if (op != null) { repository.releaseOperation(op); } @@ -1557,8 +1563,7 @@ private void processAbortOperationCmd(APDU apdu) { 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]); + KMOperationState op = repository.findOperation(data[OP_HANDLE]); if (op == null) { KMException.throwIt(KMError.INVALID_OPERATION_HANDLE); } @@ -1592,8 +1597,7 @@ private void processFinishOperationCmd(APDU apdu) { data[HW_TOKEN] = KMArray.cast(tmpVariables[2]).get((short) 4); data[VERIFICATION_TOKEN] = KMArray.cast(tmpVariables[2]).get((short) 5); // Check Operation Handle - tmpVariables[1] = KMInteger.cast(data[OP_HANDLE]).getShort(); - KMOperationState op = repository.findOperation(tmpVariables[1]); + KMOperationState op = repository.findOperation(data[OP_HANDLE]); if (op == null) { KMException.throwIt(KMError.INVALID_OPERATION_HANDLE); } @@ -2064,8 +2068,7 @@ private void processUpdateOperationCmd(APDU apdu) { } // Check Operation Handle and get op state // Check Operation Handle - tmpVariables[1] = KMInteger.cast(data[OP_HANDLE]).getShort(); - KMOperationState op = repository.findOperation(tmpVariables[1]); + KMOperationState op = repository.findOperation(data[OP_HANDLE]); if (op == null) KMException.throwIt(KMError.INVALID_OPERATION_HANDLE); // authorize the update operation authorizeUpdateFinishOperation(op, scratchPad); @@ -2203,7 +2206,18 @@ private void processBeginOperationCmd(APDU apdu) { tmpVariables[0] = KMArray.cast(args).get((short) 0); tmpVariables[0] = KMEnum.cast(tmpVariables[0]).getVal(); data[HW_TOKEN] = KMArray.cast(args).get((short) 3); - KMOperationState op = repository.reserveOperation(); + /*Generate a random number for operation handle */ + short buf = KMByteBlob.instance(KMRepository.OPERATION_HANDLE_SIZE); + generateUniqueOperationHandle( + KMByteBlob.cast(buf).getBuffer(), + KMByteBlob.cast(buf).getStartOff(), + KMByteBlob.cast(buf).length()); + /* opHandle is a KMInteger and is encoded as KMInteger when it is returned back. */ + short opHandle = KMInteger.instance( + KMByteBlob.cast(buf).getBuffer(), + KMByteBlob.cast(buf).getStartOff(), + KMByteBlob.cast(buf).length()); + KMOperationState op = repository.reserveOperation(opHandle); if (op == null) KMException.throwIt(KMError.TOO_MANY_OPERATIONS); data[OP_HANDLE] = op.getHandle(); diff --git a/Applet/src/com/android/javacard/keymaster/KMOperationState.java b/Applet/src/com/android/javacard/keymaster/KMOperationState.java index 347c9920..6ea96941 100644 --- a/Applet/src/com/android/javacard/keymaster/KMOperationState.java +++ b/Applet/src/com/android/javacard/keymaster/KMOperationState.java @@ -68,20 +68,21 @@ private static KMOperationState proto() { return prototype; } - public static KMOperationState instance(short opId, Object[] slot) { + public static KMOperationState instance(short opHandle, Object[] slot) { KMOperationState opState = proto(); opState.reset(); - Util.setShort(data, OP_HANDLE, opId); + Util.setShort(data, OP_HANDLE, opHandle); KMOperationState.slot = slot; return opState; } - public static KMOperationState read(Object[] slot) { + public static KMOperationState read(byte[] oprHandle, short off, Object[] slot) { KMOperationState opState = proto(); opState.reset(); Util.arrayCopy((byte[]) slot[DATA], (short) 0, data, (short) 0, (short) data.length); Object[] ops = ((Object[]) slot[REFS]); op = (KMOperation) ops[OPERATION]; + Util.setShort(data, OP_HANDLE, KMInteger.uint_64(oprHandle, off)); KMOperationState.slot = slot; return opState; } @@ -123,10 +124,6 @@ public void release() { } public short getHandle() { - return KMInteger.uint_16(Util.getShort(KMOperationState.data, OP_HANDLE)); - } - - public short handle() { return Util.getShort(KMOperationState.data, OP_HANDLE); } diff --git a/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/src/com/android/javacard/keymaster/KMRepository.java index 2b95697a..4c30a613 100644 --- a/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/Applet/src/com/android/javacard/keymaster/KMRepository.java @@ -35,6 +35,11 @@ public class KMRepository implements KMUpgradable { public static final short HEAP_SIZE = 10000; public static final short DATA_INDEX_ENTRY_LENGTH = 0; public static final short DATA_INDEX_ENTRY_OFFSET = 2; + public static final short OPERATION_HANDLE_SIZE = 8; /* 8 bytes */ + private static final short OPERATION_HANDLE_STATUS_OFFSET = 0; + private static final short OPERATION_HANDLE_STATUS_SIZE = 1; + private static final short OPERATION_HANDLE_OFFSET = 1; + private static final short OPERATION_HANDLE_ENTRY_SIZE = OPERATION_HANDLE_SIZE + OPERATION_HANDLE_STATUS_SIZE; // Data table offsets public static final byte MASTER_KEY = 8; @@ -80,7 +85,6 @@ public class KMRepository implements KMUpgradable { // Class Attributes private Object[] operationStateTable; - private static short opIdCounter; private byte[] heap; private short heapIndex; private byte[] dataTable; @@ -101,9 +105,11 @@ public KMRepository(boolean isUpgrading) { reclaimIndex = HEAP_SIZE; operationStateTable = new Object[MAX_OPS]; // create and initialize operation state table. + //First byte in the operation handle buffer denotes whether the operation is + //reserved or unreserved. byte index = 0; while(index < MAX_OPS){ - operationStateTable[index] = new Object[]{new byte[2], + operationStateTable[index] = new Object[]{new byte[OPERATION_HANDLE_ENTRY_SIZE], new Object[] {new byte[KMOperationState.MAX_DATA], new Object[KMOperationState.MAX_REFS]}}; index++; @@ -111,24 +117,51 @@ public KMRepository(boolean isUpgrading) { repository = this; } - public KMOperationState findOperation(short opHandle) { + public void getOperationHandle(short oprHandle, byte[] buf, short off, short len) { + if (KMInteger.cast(oprHandle).length() != OPERATION_HANDLE_SIZE) { + KMException.throwIt(KMError.INVALID_OPERATION_HANDLE); + } + KMInteger.cast(oprHandle).getValue(buf, off, len); + } + + public KMOperationState findOperation(byte[] buf, short off, short len) { short index = 0; byte[] opId; - while(index < MAX_OPS){ - opId = ((byte[])((Object[])operationStateTable[index])[0]); - if(Util.getShort(opId,(short)0) == opHandle)return KMOperationState.read((Object[])((Object[])operationStateTable[index])[1]); + while (index < MAX_OPS) { + opId = ((byte[]) ((Object[]) operationStateTable[index])[0]); + if (0 == Util.arrayCompare(buf, off, opId, OPERATION_HANDLE_OFFSET, len)) { + return KMOperationState + .read(opId, OPERATION_HANDLE_OFFSET, (Object[]) ((Object[]) operationStateTable[index])[1]); + } index++; } + return null; } - public KMOperationState reserveOperation(){ + /* operationHandle is a KMInteger */ + public KMOperationState findOperation(short operationHandle) { + short buf = KMByteBlob.instance(OPERATION_HANDLE_SIZE); + getOperationHandle( + operationHandle, + KMByteBlob.cast(buf).getBuffer(), + KMByteBlob.cast(buf).getStartOff(), + KMByteBlob.cast(buf).length()); + return findOperation( + KMByteBlob.cast(buf).getBuffer(), + KMByteBlob.cast(buf).getStartOff(), + KMByteBlob.cast(buf).length()); + } + + /* opHandle is a KMInteger */ + public KMOperationState reserveOperation(short opHandle){ short index = 0; byte[] opId; while(index < MAX_OPS){ opId = (byte[])((Object[])operationStateTable[index])[0]; - if(Util.getShort(opId,(short)0) == 0){ - return KMOperationState.instance(/*Util.getShort(opId,(short)0)*/getOpId(),(Object[])((Object[])operationStateTable[index])[1]); + /* Check for unreserved operation state */ + if (opId[OPERATION_HANDLE_STATUS_OFFSET] == 0) { + return KMOperationState.instance(opHandle, (Object[])((Object[])operationStateTable[index])[1]); } index++; } @@ -139,29 +172,48 @@ public KMOperationState reserveOperation(){ public void persistOperation(byte[] data, short opHandle, KMOperation op) { short index = 0; byte[] opId; + short buf = KMByteBlob.instance(OPERATION_HANDLE_SIZE); + getOperationHandle( + opHandle, + KMByteBlob.cast(buf).getBuffer(), + KMByteBlob.cast(buf).getStartOff(), + KMByteBlob.cast(buf).length()); //Update an existing operation state. - while(index < MAX_OPS){ - opId = (byte[])((Object[])operationStateTable[index])[0]; - if(Util.getShort(opId,(short)0) == opHandle){ - Object[] slot = (Object[])((Object[])operationStateTable[index])[1]; - JCSystem.beginTransaction(); - Util.arrayCopy(data, (short) 0, (byte[]) slot[0], (short) 0, (short) ((byte[]) slot[0]).length); + while (index < MAX_OPS) { + opId = (byte[]) ((Object[]) operationStateTable[index])[0]; + if ((1 == opId[OPERATION_HANDLE_STATUS_OFFSET]) + && (0 == Util.arrayCompare( + opId, + OPERATION_HANDLE_OFFSET, + KMByteBlob.cast(buf).getBuffer(), + KMByteBlob.cast(buf).getStartOff(), + KMByteBlob.cast(buf).length()))) { + Object[] slot = (Object[]) ((Object[]) operationStateTable[index])[1]; + JCSystem.beginTransaction(); + Util.arrayCopy(data, (short) 0, (byte[]) slot[0], (short) 0, + (short) ((byte[]) slot[0]).length); Object[] ops = ((Object[]) slot[1]); ops[0] = op; JCSystem.commitTransaction(); return; - } - index++; + } + index++; } index = 0; //Persist a new operation. while(index < MAX_OPS){ opId = (byte[])((Object[])operationStateTable[index])[0]; - if(Util.getShort(opId,(short)0) == 0){ - Util.setShort(opId, (short)0, opHandle); + if(0 == opId[OPERATION_HANDLE_STATUS_OFFSET]){ Object[] slot = (Object[])((Object[])operationStateTable[index])[1]; JCSystem.beginTransaction(); + opId[OPERATION_HANDLE_STATUS_OFFSET] = 1;/*reserved */ + Util.arrayCopy( + KMByteBlob.cast(buf).getBuffer(), + KMByteBlob.cast(buf).getStartOff(), + opId, + OPERATION_HANDLE_OFFSET, + OPERATION_HANDLE_SIZE); Util.arrayCopy(data, (short) 0, (byte[]) slot[0], (short) 0, (short) ((byte[]) slot[0]).length); Object[] ops = ((Object[]) slot[1]); ops[0] = op; @@ -172,28 +224,24 @@ public void persistOperation(byte[] data, short opHandle, KMOperation op) { } } - private short getOpId() { - byte index = 0; - opIdCounter++; - while (index < MAX_OPS) { - if (Util.getShort((byte[]) ((Object[]) operationStateTable[index])[0], (short) 0) - == opIdCounter) { - opIdCounter++; - index = 0; - continue; - } - index++; - } - return opIdCounter; - } - - public void releaseOperation(KMOperationState op){ + public void releaseOperation(KMOperationState op) { short index = 0; byte[] var; - while(index < MAX_OPS){ - var = ((byte[])((Object[])operationStateTable[index])[0]); - if(Util.getShort(var,(short)0) == op.handle()){ - Util.arrayFillNonAtomic(var,(short)0,(short)var.length,(byte)0); + short buf = KMByteBlob.instance(OPERATION_HANDLE_SIZE); + getOperationHandle( + op.getHandle(), + KMByteBlob.cast(buf).getBuffer(), + KMByteBlob.cast(buf).getStartOff(), + KMByteBlob.cast(buf).length()); + while (index < MAX_OPS) { + var = ((byte[]) ((Object[]) operationStateTable[index])[0]); + if ((var[OPERATION_HANDLE_STATUS_OFFSET] == 1) && + (0 == Util.arrayCompare(var, + OPERATION_HANDLE_OFFSET, + KMByteBlob.cast(buf).getBuffer(), + KMByteBlob.cast(buf).getStartOff(), + KMByteBlob.cast(buf).length()))) { + Util.arrayFillNonAtomic(var, (short) 0, (short) var.length, (byte) 0); op.release(); break; } @@ -211,7 +259,6 @@ public void initHmacSharedSecretKey(byte[] key, short start, short len) { writeDataEntry(SHARED_KEY,key,start,len); } - public void initComputedHmac(byte[] key, short start, short len) { if(len != COMPUTED_HMAC_KEY_SIZE) KMException.throwIt(KMError.INVALID_INPUT_LENGTH); writeDataEntry(COMPUTED_HMAC_KEY,key,start,len); From f80df71c308003cb6be3b3c48318294f2fbd5723 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Sat, 23 Jan 2021 00:47:05 +0530 Subject: [PATCH 68/99] Corrected the condition for SE provisioned status --- HAL/keymaster/4.1/Provision.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/HAL/keymaster/4.1/Provision.cpp b/HAL/keymaster/4.1/Provision.cpp index 6249e34d..ebcf7e37 100644 --- a/HAL/keymaster/4.1/Provision.cpp +++ b/HAL/keymaster/4.1/Provision.cpp @@ -458,8 +458,7 @@ static bool isSEProvisioned(uint64_t status) { 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_PRESHARED_SECRET | ProvisionStatus::PROVISION_STATUS_BOOT_PARAM - |ProvisionStatus::PROVISION_STATUS_PROVISIONING_LOCKED)) { + ProvisionStatus::PROVISION_STATUS_PRESHARED_SECRET | ProvisionStatus::PROVISION_STATUS_BOOT_PARAM)) { ret = false; } return ret; From 89cbcc44454510cf3374debf56a1998b229a6ecc Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Sat, 23 Jan 2021 01:45:42 +0530 Subject: [PATCH 69/99] Corrected the condition for SE provisioned status --- HAL/keymaster/4.1/Provision.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/HAL/keymaster/4.1/Provision.cpp b/HAL/keymaster/4.1/Provision.cpp index ebcf7e37..24f65667 100644 --- a/HAL/keymaster/4.1/Provision.cpp +++ b/HAL/keymaster/4.1/Provision.cpp @@ -454,12 +454,13 @@ static ErrorCode setBootParameters(std::unique_ptr Date: Mon, 25 Jan 2021 13:59:38 +0530 Subject: [PATCH 70/99] make provision as separate library --- .../4.1/JavacardKeymaster4Device.cpp | 65 +- HAL/keymaster/4.1/Provision.cpp | 264 ++------ HAL/keymaster/Android.bp | 7 +- HAL/keymaster/include/Provision.h | 41 +- provisioning_tool/Android.bp | 2 +- provisioning_tool/provision_tool.cpp | 634 +++++------------- provisioning_tool/sample_json.txt | 7 +- 7 files changed, 339 insertions(+), 681 deletions(-) diff --git a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp index 27f32150..3086e287 100644 --- a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp +++ b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -91,7 +90,19 @@ enum class Instruction { 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 + INS_GET_CERT_CHAIN_CMD = INS_END_KM_PROVISION_CMD+22, + 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_PRESHARED_SECRET = 0x10, + PROVISION_STATUS_BOOT_PARAM = 0x20, + PROVISION_STATUS_PROVISIONING_LOCKED = 0x40, }; //Extended error codes @@ -368,15 +379,57 @@ uint16_t getStatus(std::vector& inputData) { return (inputData.at(inputData.size()-2) << 8) | (inputData.at(inputData.size()-1)); } +static bool isSEProvisioned() { + ErrorCode errorCode = ErrorCode::OK; + Instruction ins = Instruction::INS_GET_PROVISION_STATUS_CMD; + std::vector cborData; + std::vector response; + std::unique_ptr item; + CborConverter cborConverter; + std::vector apdu; + bool ret = false; + + errorCode = constructApduMessage(ins, cborData, apdu); + if(errorCode != ErrorCode::OK) return ret; + + if(!getTransportFactoryInstance()->sendData(apdu.data(), apdu.size(), response)) { + LOG(ERROR) << " Failed to send GET_PROVISION_STATUS_CMD "; + return ret; + } + + if((response.size() <= 2) || (getStatus(response) != APDU_RESP_STATUS_OK)) { + return ret; + } + //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)) { + LOG(ERROR) << "Failed to parse the status from cbor data"; + return ret; + } + + if ( (0 != (status & ProvisionStatus::PROVISION_STATUS_ATTESTATION_KEY)) && + (0 != (status & ProvisionStatus::PROVISION_STATUS_ATTESTATION_CERT_CHAIN)) && + (0 != (status & ProvisionStatus::PROVISION_STATUS_ATTESTATION_CERT_PARAMS)) && + (0 != (status & ProvisionStatus::PROVISION_STATUS_PRESHARED_SECRET)) && + (0 != (status & ProvisionStatus::PROVISION_STATUS_BOOT_PARAM))) { + ret = true; + } + } + return ret; +} + + ErrorCode sendData(Instruction ins, std::vector& inData, std::vector& response, bool extendedOutput=false) { ErrorCode ret = ErrorCode::UNKNOWN_ERROR; std::vector apdu; - // 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"; + if (!isSEProvisioned()) { + LOG(ERROR) << "Javacard applet is not provisioned."; return ret; } ret = constructApduMessage(ins, inData, apdu, extendedOutput); diff --git a/HAL/keymaster/4.1/Provision.cpp b/HAL/keymaster/4.1/Provision.cpp index 24f65667..a896db88 100644 --- a/HAL/keymaster/4.1/Provision.cpp +++ b/HAL/keymaster/4.1/Provision.cpp @@ -28,10 +28,8 @@ #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 @@ -42,7 +40,6 @@ 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, @@ -67,32 +64,15 @@ enum ProvisionStatus { }; // 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) { +static inline X509* parseDerCertificate(std::vector& certData) { 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) { @@ -145,30 +125,6 @@ static uint16_t getStatus(std::vector& inputData) { 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 @@ -235,77 +191,73 @@ extendedOutput) { return ret; } -static ErrorCode provisionAttestationKey(std::unique_ptr& transport) { +// Class Provision Start + +ErrorCode Provision::initProvision() { + if(pTransportFactory == nullptr) { + pTransportFactory = std::unique_ptr(new se_transport::TransportFactory( + android::base::GetBoolProperty("ro.kernel.qemu", false))); + pTransportFactory->openConnection(); + } + return ErrorCode::OK; +} + +ErrorCode Provision::provisionAttestationKey(std::vector& batchKey) { 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; + CborConverter cborConverter; + cppbor::Array array; + cppbor::Array subArray; std::vector response; + Instruction ins = Instruction::INS_PROVISION_ATTESTATION_KEY_CMD; 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))) { + if(ErrorCode::OK != (errorCode = ecRawKeyFromPKCS8(batchKey, 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))) { + if(ErrorCode::OK != (errorCode = sendProvisionData(pTransportFactory, ins, cborData, response))) { return errorCode; } return errorCode; } -static ErrorCode provisionAttestationCertificateChain(std::unique_ptr& transport) { +ErrorCode Provision::provisionAtestationCertificateChain(std::vector>& certChain) { 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); + for (auto data : certChain) { + certData.insert(certData.end(), data.begin(), data.end()); } - 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(); + cppbor::Bstr bstrCertChain(certData.begin(), certData.end()); + std::vector cborData = bstrCertChain.encode(); - if(ErrorCode::OK != (errorCode = sendProvisionData(transport, ins, cborData, response))) { + if(ErrorCode::OK != (errorCode = sendProvisionData(pTransportFactory, ins, cborData, response))) { return errorCode; } return errorCode; } -static ErrorCode provisionAttestationCertificateParams(std::unique_ptr& transport) { +ErrorCode Provision::provisionAttestationCertificateParams(std::vector& batchCertificate) { ErrorCode errorCode = ErrorCode::OK; cppbor::Array array; Instruction ins = Instruction::INS_PROVISION_CERT_PARAMS_CMD; @@ -316,7 +268,7 @@ static ErrorCode provisionAttestationCertificateParams(std::unique_ptr cborData = array.encode(); - if(ErrorCode::OK != (errorCode = sendProvisionData(transport, ins, cborData, response))) { + if(ErrorCode::OK != (errorCode = sendProvisionData(pTransportFactory, ins, cborData, response))) { return errorCode; } return errorCode; } - -static ErrorCode provisionAttestationIDs(std::unique_ptr& transport) { +ErrorCode Provision::provisionAttestationID(AttestIDParams& attestParams) { 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())); + .Authorization(TAG_ATTESTATION_ID_BRAND, attestParams.brand.data(), attestParams.brand.size()) + .Authorization(TAG_ATTESTATION_ID_DEVICE, attestParams.device.data(), attestParams.device.size()) + .Authorization(TAG_ATTESTATION_ID_PRODUCT, attestParams.product.data(), attestParams.product.size()) + .Authorization(TAG_ATTESTATION_ID_SERIAL, attestParams.serial.data(), attestParams.serial.size()) + .Authorization(TAG_ATTESTATION_ID_IMEI, attestParams.imei.data(), attestParams.imei.size()) + .Authorization(TAG_ATTESTATION_ID_MEID, attestParams.meid.data(), attestParams.meid.size()) + .Authorization(TAG_ATTESTATION_ID_MANUFACTURER, attestParams.manufacturer.data(), attestParams.manufacturer.size()) + .Authorization(TAG_ATTESTATION_ID_MODEL, attestParams.model.data(), attestParams.model.size())); - hidl_vec attestParams = kmParamSet2Hidl(authSetAttestParams); + hidl_vec attestKeyParams = kmParamSet2Hidl(authSetAttestParams); array = cppbor::Array(); - cborConverter.addKeyparameters(array, attestParams); + cborConverter.addKeyparameters(array, attestKeyParams); std::vector cborData = array.encode(); - if(ErrorCode::OK != (errorCode = sendProvisionData(transport, ins, cborData, response))) { + if(ErrorCode::OK != (errorCode = sendProvisionData(pTransportFactory, ins, cborData, response))) { return errorCode; } return errorCode; } -static ErrorCode provisionSharedSecret(std::unique_ptr& transport) { +ErrorCode Provision::provisionPreSharedSecret(std::vector& preSharedSecret) { ErrorCode errorCode = ErrorCode::OK; cppbor::Array array; Instruction ins = Instruction::INS_PROVISION_PRESHARED_SECRET_CMD; std::vector response; - std::vector masterKey(kFakeKeyAgreementKey, kFakeKeyAgreementKey + - sizeof(kFakeKeyAgreementKey)/sizeof(kFakeKeyAgreementKey[0])); array = cppbor::Array(); - array.add(masterKey); + array.add(preSharedSecret); 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))) { + if(ErrorCode::OK != (errorCode = sendProvisionData(pTransportFactory, ins, cborData, response))) { return errorCode; } return errorCode; - } -static ErrorCode lockProvision(std::unique_ptr& transport) { +ErrorCode Provision::provisionBootParameters(BootParams& bootParams) { 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). + add(bootParams.vendorPatchLevel). + add(bootParams.bootPatchLevel). /* Verified Boot Key */ - add(verifiedBootKey). + add(bootParams.verifiedBootKey). /* Verified Boot Hash */ - add(verifiedBootKeyHash). + add(bootParams.verifiedBootKeyHash). /* boot state */ - add(static_cast(kmVerifiedBoot)). + add(bootParams.verifiedBootState). /* device locked */ - add(0); + add(bootParams.deviceLocked); std::vector cborData = array.encode(); - if(ErrorCode::OK != (errorCode = sendProvisionData(transport, ins, cborData, response))) { + if(ErrorCode::OK != (errorCode = sendProvisionData(pTransportFactory, ins, cborData, response))) { return errorCode; } return errorCode; } -static bool isSEProvisioned(uint64_t status) { - bool ret = false; - if ( (0 != (status & ProvisionStatus::PROVISION_STATUS_ATTESTATION_KEY)) && - (0 != (status & ProvisionStatus::PROVISION_STATUS_ATTESTATION_CERT_CHAIN)) && - (0 != (status & ProvisionStatus::PROVISION_STATUS_ATTESTATION_CERT_PARAMS)) && - (0 != (status & ProvisionStatus::PROVISION_STATUS_PRESHARED_SECRET)) && - (0 != (status & ProvisionStatus::PROVISION_STATUS_BOOT_PARAM))) { - ret = true; - } - return ret; -} - -ErrorCode provision(std::unique_ptr& transport) { +ErrorCode Provision::getProvisionStatus(uint64_t& status) { + ErrorCode errorCode = ErrorCode::OK; + Instruction ins = Instruction::INS_GET_PROVISION_STATUS_CMD; + std::vector cborData; std::vector response; std::unique_ptr item; CborConverter cborConverter; - ErrorCode errorCode = ErrorCode::OK; - //Get Provision status. - if(ErrorCode::OK != (errorCode = getProvisionStatus(transport, response))) { + if(ErrorCode::OK != (errorCode = sendProvisionData(pTransportFactory, ins, cborData, response))) { + LOG(ERROR) << "Failed to get provision status err: " << static_cast(errorCode); 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)) + if(!cborConverter.getUint64(item, 1, status)) { + LOG(ERROR) << "Failed to parse the status from cbor data"; return ErrorCode::UNKNOWN_ERROR; - - if(isSEProvisioned(status)) { - return ErrorCode::OK; //SE is Provisioned. } - - } else { - return ErrorCode::UNKNOWN_ERROR; } + return errorCode; +} - //SE not provisioned so Provision the SE. +ErrorCode Provision::lockProvision() { + ErrorCode errorCode = ErrorCode::OK; + Instruction ins = Instruction::INS_LOCK_PROVISIONING_CMD; + std::vector cborData; + std::vector response; - //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))) { + if(ErrorCode::OK != (errorCode = sendProvisionData(pTransportFactory, ins, cborData, response))) { return errorCode; } - //return OK return errorCode; } +// Provision End } // namespace javacard } // namespace V4_1 diff --git a/HAL/keymaster/Android.bp b/HAL/keymaster/Android.bp index fdeaf9ce..9db148da 100644 --- a/HAL/keymaster/Android.bp +++ b/HAL/keymaster/Android.bp @@ -25,7 +25,8 @@ cc_binary { "4.1/JavacardKeymaster4Device.cpp", "4.1/JavacardSoftKeymasterContext.cpp", "4.1/JavacardOperationContext.cpp", - "4.1/Provision.cpp", + "4.1/CommonUtils.cpp", + "4.1/CborConverter.cpp", ], local_include_dirs: [ "include", @@ -46,7 +47,6 @@ cc_binary { "android.hardware.keymaster@4.0", "libjc_transport", "libcrypto", - "libjc_common", ], product_variables: { debuggable: { @@ -111,11 +111,12 @@ cc_library { } cc_library { - name: "libjc_common", + name: "libjc_provision", vendor_available: true, srcs: [ "4.1/CommonUtils.cpp", "4.1/CborConverter.cpp", + "4.1/Provision.cpp", ], local_include_dirs: [ "include", diff --git a/HAL/keymaster/include/Provision.h b/HAL/keymaster/include/Provision.h index a58c17c6..e6b670f2 100644 --- a/HAL/keymaster/include/Provision.h +++ b/HAL/keymaster/include/Provision.h @@ -25,10 +25,43 @@ namespace keymaster { namespace V4_1 { namespace javacard { -/** - * Provisions the SE. - */ -ErrorCode provision(std::unique_ptr& transport); +typedef struct BootParams_ { + uint32_t osVersion; + uint32_t osPatchLevel; + uint32_t vendorPatchLevel; + uint32_t bootPatchLevel; + std::vector verifiedBootKey; + std::vector verifiedBootKeyHash; + uint32_t verifiedBootState; + uint32_t deviceLocked; +} BootParams; + +typedef struct AttestIDParams_ { + std::string brand; + std::string device; + std::string product; + std::string serial; + std::string imei; + std::string meid; + std::string manufacturer; + std::string model; +} AttestIDParams; + +class Provision { +public: + ErrorCode initProvision(); + ErrorCode provisionAttestationKey(std::vector& batchKey); + ErrorCode provisionAtestationCertificateChain(std::vector>& CertChain); + ErrorCode provisionAttestationCertificateParams(std::vector& batchCertificate); + ErrorCode provisionAttestationID(AttestIDParams& attestParams); + ErrorCode provisionPreSharedSecret(std::vector& preSharedSecret); + ErrorCode provisionBootParameters(BootParams& bootParams ); + ErrorCode lockProvision(); + ErrorCode getProvisionStatus(uint64_t&); + +private: + std::unique_ptr pTransportFactory; +}; } // namespace javacard } // namespace V4_1 diff --git a/provisioning_tool/Android.bp b/provisioning_tool/Android.bp index 2f66b105..b9b39808 100644 --- a/provisioning_tool/Android.bp +++ b/provisioning_tool/Android.bp @@ -36,6 +36,6 @@ cc_binary { "libjc_transport", "libcrypto", "libjsoncpp", - "libjc_common", + "libjc_provision", ], } diff --git a/provisioning_tool/provision_tool.cpp b/provisioning_tool/provision_tool.cpp index 1cead86a..820384b1 100644 --- a/provisioning_tool/provision_tool.cpp +++ b/provisioning_tool/provision_tool.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #define BUFFER_MAX_LENGTH 256 #define SB_KEYMASTER_SERVICE "javacard" @@ -64,30 +65,14 @@ enum ProvisionStatus { PROVISION_STATUS_ATTESTATION_CERT_CHAIN = 0x02, PROVISION_STATUS_ATTESTATION_CERT_PARAMS = 0x04, PROVISION_STATUS_ATTEST_IDS = 0x08, - PROVISION_STATUS_SHARED_SECRET = 0x10, + PROVISION_STATUS_PRESHARED_SECRET = 0x10, PROVISION_STATUS_BOOT_PARAM = 0x20, PROVISION_STATUS_PROVISIONING_LOCKED = 0x40, }; using ::android::hardware::keymaster::V4_0::ErrorCode; -using ::android::hardware::keymaster::V4_0::EcCurve; -using ::android::hardware::keymaster::V4_0::HardwareAuthenticatorType; -using ::android::hardware::keymaster::V4_0::HardwareAuthToken; -using ::android::hardware::keymaster::V4_0::HmacSharingParameters; -using ::android::hardware::keymaster::V4_0::KeyCharacteristics; -using ::android::hardware::keymaster::V4_0::KeyFormat; -using ::android::hardware::keymaster::V4_0::KeyParameter; -using ::android::hardware::keymaster::V4_0::KeyPurpose; -using ::android::hardware::keymaster::V4_0::OperationHandle; -using ::android::hardware::keymaster::V4_0::SecurityLevel; -using ::android::hardware::keymaster::V4_0::VerificationToken; -using ::android::hardware::keymaster::V4_0::Tag; -using ::android::hardware::keymaster::V4_1::IKeymasterDevice; -using ::android::sp; -using se_transport::TransportFactory; - -static sp sbKeymaster; -static TransportFactory *pTransportFactory; + +static keymaster::V4_1::javacard::Provision mProvision; Json::Value root; constexpr char hex_value[256] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // @@ -117,12 +102,6 @@ std::string hex2str(std::string a) { return b; } -//static function declarations. -static ErrorCode constructApduMessage(Instruction& ins, std::vector& inputData, std::vector& apduOut, bool -extendedOutput); -static ErrorCode sendProvisionData(Instruction ins, std::vector& inData, std::vector& response, bool -extendedOutput); -static Tag mapAttestKeyToAttestTag(std::string key); bool parseJsonFile(const char* filename); static bool readDataFromFile(const char *filename, std::vector& data) { @@ -148,179 +127,6 @@ static bool readDataFromFile(const char *filename, std::vector& data) { return ret; } -static inline X509* parseDerCertificate(std::vector& certData) { - X509 *x509 = 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 inline 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 inline TransportFactory* getTransportFactoryInstance() { - if(pTransportFactory == nullptr) { - pTransportFactory = new se_transport::TransportFactory( - android::base::GetBoolProperty("ro.kernel.qemu", false)); - pTransportFactory->openConnection(); - } - return pTransportFactory; -} - -static Tag mapAttestKeyToAttestTag(std::string keyStr) { - Tag tag = Tag::INVALID; - - if (0 == keyStr.compare("brand")) { - tag = Tag::ATTESTATION_ID_BRAND; - } else if(0 == keyStr.compare("device")) { - tag = Tag::ATTESTATION_ID_DEVICE; - } else if(0 == keyStr.compare("product")) { - tag = Tag::ATTESTATION_ID_PRODUCT; - } else if(0 == keyStr.compare("serial")) { - tag = Tag::ATTESTATION_ID_SERIAL; - } else if(0 == keyStr.compare("imei")) { - tag = Tag::ATTESTATION_ID_IMEI; - } else if(0 == keyStr.compare("meid")) { - tag = Tag::ATTESTATION_ID_MEID; - } else if(0 == keyStr.compare("manufacturer")) { - tag = Tag::ATTESTATION_ID_MANUFACTURER; - } else if(0 == keyStr.compare("model")) { - tag = Tag::ATTESTATION_ID_MODEL; - } - return tag; -} - -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(Instruction ins, std::vector& inData, std::vector& response, bool -extendedOutput=false) { - 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(!pTransportFactory->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; -} - void usage() { printf("Usage: provision_tool [options]\n"); printf("Valid options are:\n"); @@ -371,73 +177,55 @@ bool getBootParameterBlobValue(Json::Value& bootParamsObj, const char* key, std: bool setBootParameters(const char* filename) { Json::Value bootParamsObj; bool ret = false; + keymaster::V4_1::javacard::BootParams bootParams; if(!parseJsonFile(filename)) return ret; bootParamsObj = root.get("set_boot_params", bootParamsObj); if (!bootParamsObj.isNull()) { - cppbor::Array array; - ErrorCode errorCode = ErrorCode::OK; - std::vector apdu; - std::vector response; - Instruction ins = Instruction::INS_SET_BOOT_PARAMS_CMD; - uint32_t value; - std::vector blob; - - if(!getBootParameterIntValue(bootParamsObj, "os_version", &value)) { + + if(!getBootParameterIntValue(bootParamsObj, "os_version", &bootParams.osVersion)) { printf("\n Invalid value for os_version or os_version tag missing\n"); return ret; } - array.add(value); - if(!getBootParameterIntValue(bootParamsObj, "os_patch_level", &value)) { + if(!getBootParameterIntValue(bootParamsObj, "os_patch_level", &bootParams.osPatchLevel)) { printf("\n Invalid value for os_patch_level or os_patch_level tag missing\n"); return ret; } - array.add(value); - if(!getBootParameterIntValue(bootParamsObj, "vendor_patch_level", &value)) { + if(!getBootParameterIntValue(bootParamsObj, "vendor_patch_level", &bootParams.vendorPatchLevel)) { printf("\n Invalid value for vendor_patch_level or vendor_patch_level tag missing\n"); return ret; } - array.add(value); - if(!getBootParameterIntValue(bootParamsObj, "boot_patch_level", &value)) { + if(!getBootParameterIntValue(bootParamsObj, "boot_patch_level", &bootParams.bootPatchLevel)) { printf("\n Invalid value for boot_patch_level or boot_patch_level tag missing\n"); return ret; } - array.add(value); - if(!getBootParameterBlobValue(bootParamsObj, "verified_boot_key", blob)) { + if(!getBootParameterBlobValue(bootParamsObj, "verified_boot_key", bootParams.verifiedBootKey)) { printf("\n Invalid value for verified_boot_key or verified_boot_key tag missing\n"); return ret; } - array.add(blob); - blob.clear(); - if(!getBootParameterBlobValue(bootParamsObj, "verified_boot_key_hash", blob)) { + if(!getBootParameterBlobValue(bootParamsObj, "verified_boot_key_hash", bootParams.verifiedBootKeyHash)) { printf("\n Invalid value for verified_boot_key_hash or verified_boot_key_hash tag missing\n"); return ret; } - array.add(blob); - blob.clear(); - if(!getBootParameterIntValue(bootParamsObj, "boot_state", &value)) { + if(!getBootParameterIntValue(bootParamsObj, "boot_state", &bootParams.verifiedBootState)) { printf("\n Invalid value for boot_state or boot_state tag missing\n"); return ret; } - array.add(value); - if(!getBootParameterIntValue(bootParamsObj, "device_locked", &value)) { + if(!getBootParameterIntValue(bootParamsObj, "device_locked", &bootParams.deviceLocked)) { printf("\n Invalid value for device_locked or device_locked tag missing\n"); return ret; } - array.add(value); - - std::vector cborData = array.encode(); - - if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { - printf("\n Failed to set boot parameters errorCode:%d\n", errorCode); - return ret; - } } else { return ret; } + + if (ErrorCode::OK != mProvision.provisionBootParameters(bootParams)) { + return ret; + } + printf("\n SE successfully accepted boot paramters \n"); return true; } @@ -445,55 +233,47 @@ bool setBootParameters(const char* filename) { bool provisionAttestationIds(const char *filename) { Json::Value attestIds; bool ret = false; + keymaster::V4_1::javacard::AttestIDParams params; if(!parseJsonFile(filename)) return ret; attestIds = root.get("attest_ids", attestIds); if (!attestIds.isNull()) { - if (attestIds.size() != MAX_ATTEST_IDS_SIZE) { - return ret; - } Json::Value value; - std::vector temp; - int i = 0; - std::vector params(attestIds.size()); Json::Value::Members keys = attestIds.getMemberNames(); - Tag tag; for(std::string key : keys) { - if(Tag::INVALID == (tag = mapAttestKeyToAttestTag(key))) { - break; - } value = attestIds[key]; if(value.empty()) { - break; + continue; } - params[i].tag = tag; - for(char ch : value.asString()) { - temp.push_back((uint8_t)ch); + if (!value.isString()) { + return ret; } - params[i].blob.resize(temp.size()); - params[i].blob = temp; - temp.clear(); - i++; - } - - if(i != MAX_ATTEST_IDS_SIZE) - return ret; - - CborConverter cborConverter; - cppbor::Array array; - Instruction ins = Instruction::INS_PROVISION_ATTEST_IDS_CMD; - ErrorCode errorCode = ErrorCode::OK; - std::vector response; - hidl_vec attestParams(params); - //Encode input data into CBOR. - cborConverter.addKeyparameters(array, attestParams); - std::vector cborData = array.encode(); + if (0 == key.compare("brand")) { + params.brand = value.asString(); + } else if(0 == key.compare("device")) { + params.device = value.asString(); + } else if(0 == key.compare("product")) { + params.product = value.asString(); + } else if(0 == key.compare("serial")) { + params.serial = value.asString(); + } else if(0 == key.compare("imei")) { + params.imei = value.asString(); + } else if(0 == key.compare("meid")) { + params.meid = value.asString(); + } else if(0 == key.compare("manufacturer")) { + params.manufacturer = value.asString(); + } else if(0 == key.compare("model")) { + params.model = value.asString(); + } else { + printf("\n unknown attestation id key:%s \n", key.c_str()); + return ret; + } + } - if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { - printf("\n Failed to provision attestation ids error: %d\n", uint32_t(errorCode)); + if (ErrorCode::OK != mProvision.provisionAttestationID(params)) { return ret; } } else { @@ -504,14 +284,10 @@ bool provisionAttestationIds(const char *filename) { } bool lockProvision() { - bool ret = false; - cppbor::Array array; - Instruction ins = Instruction::INS_LOCK_PROVISIONING_CMD; - ErrorCode errorCode = ErrorCode::OK; - std::vector cborData; - std::vector response; + ErrorCode errorCode; + bool ret = false; - if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { + if(ErrorCode::OK != (errorCode = mProvision.lockProvision())) { printf("\n Failed to lock provisioning error: %d\n", uint32_t(errorCode)); return ret; } @@ -521,31 +297,32 @@ bool lockProvision() { bool getProvisionStatus() { bool ret = false; - CborConverter cborConverter; - cppbor::Array array; - Instruction ins = Instruction::INS_GET_PROVISION_STATUS_CMD; - ErrorCode errorCode = ErrorCode::OK; - std::vector cborData; - std::vector response; - std::unique_ptr item; - - if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { - printf("\n Failed to get provision status error: %d\n", uint32_t(errorCode)); + uint64_t status; + if (ErrorCode::OK != mProvision.getProvisionStatus(status)) { return ret; } - 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)) { - printf("\n Failed to get the status value \n"); - return ret; - } else { - printf("\nCurrent provision status: %ld\n", status); + if ( (0 != (status & ProvisionStatus::PROVISION_STATUS_ATTESTATION_KEY)) && + (0 != (status & ProvisionStatus::PROVISION_STATUS_ATTESTATION_CERT_CHAIN)) && + (0 != (status & ProvisionStatus::PROVISION_STATUS_ATTESTATION_CERT_PARAMS)) && + (0 != (status & ProvisionStatus::PROVISION_STATUS_PRESHARED_SECRET)) && + (0 != (status & ProvisionStatus::PROVISION_STATUS_BOOT_PARAM))) { + printf("\n SE is provisioned \n"); + } else { + if (0 == (status & ProvisionStatus::PROVISION_STATUS_ATTESTATION_KEY)) { + printf("\n Attestation key is not provisioned \n"); + } + if (0 == (status & ProvisionStatus::PROVISION_STATUS_ATTESTATION_CERT_CHAIN)) { + printf("\n Attestation certificate chain is not provisioned \n"); + } + if (0 == (status & ProvisionStatus::PROVISION_STATUS_ATTESTATION_CERT_PARAMS)) { + printf("\n Attestation certificate params are not provisioned \n"); + } + if (0 == (status & ProvisionStatus::PROVISION_STATUS_PRESHARED_SECRET)) { + printf("\n Shared secret is not provisioned \n"); + } + if (0 == (status & ProvisionStatus::PROVISION_STATUS_BOOT_PARAM)) { + printf("\n Boot params are not provisioned \n"); } - } else { - return ret; } return true; } @@ -559,25 +336,13 @@ bool provisionSharedSecret(const char* filename) { sharedSecret = root.get("shared_secret", sharedSecret); if (!sharedSecret.isNull()) { - cppbor::Array array; - Instruction ins = Instruction::INS_PROVISION_SHARED_SECRET_CMD; - ErrorCode errorCode = ErrorCode::OK; - std::vector response; - std::string str = sharedSecret.asString(); - std::string secret = hex2str(str); - - //Length of the secret should be 32 bytes. - if(SHARED_SECRET_SIZE != secret.size()) { + + if (!sharedSecret.isString()) { return ret; } - std::vector input(secret.data(), secret.data() + secret.length()); - - //Encode input data into CBOR. - array.add(input); - std::vector cborData = array.encode(); - - if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { - printf("\n Failed to provision shared secret error: %d\n", uint32_t(errorCode)); + std::string secret = hex2str(sharedSecret.asString()); + std::vector data(secret.begin(), secret.end()); + if(ErrorCode::OK != mProvision.provisionPreSharedSecret(data)) { return ret; } } else { @@ -596,48 +361,14 @@ static bool provisionAttestationKey(const char* filename) { keyFile = root.get("attest_key", keyFile); if (!keyFile.isNull()) { - 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; std::string keyFileName = keyFile.asString(); if(!readDataFromFile(keyFileName.data(), data)) { printf("\n Failed to read the Root ec key\n"); return ret; } - keymaster::AuthorizationSet authSetKeyParams(keymaster::AuthorizationSetBuilder() - .Authorization(keymaster::TAG_ALGORITHM, KM_ALGORITHM_EC) - .Authorization(keymaster::TAG_DIGEST, KM_DIGEST_SHA_2_256) - .Authorization(keymaster::TAG_EC_CURVE, KM_EC_CURVE_P_256) - .Authorization(keymaster::TAG_PURPOSE, static_cast(0x7F))); /* The value 0x7F is not present in types.hal */ - // Read the ECKey from the file. - hidl_vec keyParams = keymaster::V4_1::javacard::kmParamSet2Hidl(authSetKeyParams); - - if(ErrorCode::OK != (errorCode = keymaster::V4_1::javacard::ecRawKeyFromPKCS8(data, privKey, pubKey, curve))) { - printf("\n Failed to convert PKCS8 to RAW key\n"); - return ret; - } - 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(ins, cborData, response))) { - printf("\n Failed to provision attestation key\n"); + if(ErrorCode::OK != mProvision.provisionAttestationKey(data)) { return ret; } } else { @@ -656,23 +387,26 @@ bool provisionAttestationCertificateChain(const char* filename) { certChainFile = root.get("attest_cert_chain", certChainFile); if (!certChainFile.isNull()) { - ErrorCode errorCode = ErrorCode::OK; - cppbor::Array array; - Instruction ins = Instruction::INS_PROVISION_CERT_CHAIN_CMD; - std::vector response; - - std::vector certData; - std::string strCertChain = certChainFile.asString(); - /* Read the Root certificate */ - if(!readDataFromFile(strCertChain.data(), certData)) { - printf("\n Failed to read the Root certificate\n"); + std::vector> certData; + + if(certChainFile.isArray()) { + for (int i = 0; i < certChainFile.size(); i++) { + std::vector tmp; + if(certChainFile[i].isString()) { + /* Read the certificates. */ + if(!readDataFromFile(certChainFile[i].asString().data(), tmp)) { + printf("\n Failed to read the Root certificate\n"); + return ret; + } + certData.push_back(std::move(tmp)); + } else { + return ret; + } + } + } else { return ret; } - cppbor::Bstr certChain(certData.begin(), certData.end()); - std::vector cborData = certChain.encode(); - - if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { - printf("\n Failed to provision cert chain errorCode:%d\n", static_cast(errorCode)); + if (ErrorCode::OK != mProvision.provisionAtestationCertificateChain(certData)) { return ret; } } else { @@ -691,60 +425,21 @@ bool provisionAttestationCertificateParams(const char* filename) { certChainFile = root.get("attest_cert_chain", certChainFile); if (!certChainFile.isNull()) { - 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; - std::vector certData; - std::vector> certChain; - - - std::string strCertChain = certChainFile.asString(); - /* Read the Root certificate */ - if(!readDataFromFile(strCertChain.data(), certData)) { - printf("\n Failed to read the Root certificate\n"); - return ret; - } - - // Get first certificate from chain of certificates. - if(ErrorCode::OK != (errorCode =keymaster::V4_1::javacard::getCertificateChain(certData, certChain))) { - printf("\n Failed to parse the certificate chain \n"); - return ret; - } - - if(certChain.size() == 0) { - printf("\n Length of the certificate chain is 0\n"); - return ret; - } + std::vector> certData; - - /* 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(certChain[0]))) { - printf("\n Failed to parse the DER certificate \n"); - return ret; - } - - /* Get subject in DER */ - getDerSubjectName(x509, subject); - /* Get AuthorityKeyIdentifier */ - getAuthorityKeyIdentifier(x509, authorityKeyIdentifier); - /* Get Expirty Time */ - getNotAfter(x509, notAfter); - /*Free X509 */ - X509_free(x509); - - array.add(subject); - array.add(notAfter); - array.add(authorityKeyIdentifier); - std::vector cborData = array.encode(); - - if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { - printf("\n Failed to provision cert params errorCode:%d\n", static_cast(errorCode)); + if(certChainFile.isArray()) { + if (certChainFile.size() == 0) { + return ret; + } + std::vector tmp; + if(!readDataFromFile(certChainFile[0].asString().data(), tmp)) { + printf("\n Failed to read the Root certificate\n"); + return ret; + } + if (ErrorCode::OK != mProvision.provisionAttestationCertificateParams(tmp)) { + return ret; + } + } else { return ret; } } else { @@ -804,89 +499,88 @@ bool parseJsonFile(const char* filename) { int main(int argc, char* argv[]) { - int c; - struct option longOpts[] = { - {"all", required_argument, NULL, 'a'}, - {"attest_key", required_argument, NULL, 'k'}, - {"cert_chain", required_argument, NULL, 'c'}, - {"cert_params", required_argument, NULL,'p'}, - {"attest_ids", required_argument, NULL, 'i'}, - {"shared_secret", required_argument, NULL, 'r'}, - {"set_boot_params", required_argument, NULL, 'b'}, - {"provision_status", no_argument, NULL, 's'}, - {"lock_provision", no_argument, NULL, 'l'}, - {"help", no_argument, NULL, 'h'}, + int c; + struct option longOpts[] = { + {"all", required_argument, NULL, 'a'}, + {"attest_key", required_argument, NULL, 'k'}, + {"cert_chain", required_argument, NULL, 'c'}, + {"cert_params", required_argument, NULL,'p'}, + {"attest_ids", required_argument, NULL, 'i'}, + {"shared_secret", required_argument, NULL, 'r'}, + {"set_boot_params", required_argument, NULL, 'b'}, + {"provision_status", no_argument, NULL, 's'}, + {"lock_provision", no_argument, NULL, 'l'}, + {"help", no_argument, NULL, 'h'}, {0,0,0,0} - }; - -printf("\n main step0 \n"); - sbKeymaster = IKeymasterDevice::getService(SB_KEYMASTER_SERVICE); - if(NULL == sbKeymaster) { - printf("\n Failed to get StrongBox Keymaster service\n"); - exit(0); - } - pTransportFactory = getTransportFactoryInstance(); - if(NULL == pTransportFactory) { - printf("\n Failed to create transport factory\n"); - exit(0); - } + }; if (argc <= 1) { printf("\n Invalid command \n"); usage(); } -printf("\n main step1 \n"); - /* getopt_long stores the option index here. */ - while ((c = getopt_long(argc, argv, ":slha:k:c:p:i:r:b:", longOpts, NULL)) != -1) { - switch(c) { + /* Initialize provision */ + mProvision.initProvision(); + + /* getopt_long stores the option index here. */ + while ((c = getopt_long(argc, argv, ":slha:k:c:p:i:r:b:", longOpts, NULL)) != -1) { + switch(c) { case 'a': //all provision(optarg); break; case 'k': //attest key - provisionAttestationKey(optarg); + if(!provisionAttestationKey(optarg)) + printf("\n Failed to provision attestaion key\n"); break; case 'c': //attest certchain - provisionAttestationCertificateChain(optarg); + if(!provisionAttestationCertificateChain(optarg)) + printf("\n Failed to provision attestaion certificate chain\n"); break; case 'p': //attest cert params - provisionAttestationCertificateParams(optarg); + if(!provisionAttestationCertificateParams(optarg)) + printf("\n Failed to provision attestaion certificate paramaters\n"); + break; + case 'i': + //attestation ids. + if(!provisionAttestationIds(optarg)) + printf("\n Failed to provision attestaion ids\n"); + break; + //shared secret + case 'r': + if(!provisionSharedSecret(optarg)) + printf("\n Failed to provision shared secret\n"); break; - case 'i': - provisionAttestationIds(optarg); - break; - case 'r': - provisionSharedSecret(optarg); - break; case 'b': //set boot params - setBootParameters(optarg); + if(!setBootParameters(optarg)) + printf("\n Failed to set boot parameters.\n"); break; - case 's': - getProvisionStatus(); - break; - case 'l': + case 's': + if(!getProvisionStatus()) + printf("\n Failed to get provision status \n"); + break; + case 'l': lockProvision(); - break; - case 'h': + break; + case 'h': usage(); - break; - case ':': - printf("\n missing argument\n"); + break; + case ':': + printf("\n missing argument\n"); usage(); - break; - case '?': - default: - printf("\n Invalid option\n"); + break; + case '?': + default: + printf("\n Invalid option\n"); usage(); - break; - } - } + break; + } + } if(optind < argc) { usage(); } - return 0; + return 0; } diff --git a/provisioning_tool/sample_json.txt b/provisioning_tool/sample_json.txt index 1435e133..841c9843 100644 --- a/provisioning_tool/sample_json.txt +++ b/provisioning_tool/sample_json.txt @@ -17,9 +17,12 @@ "boot_patch_level": 0, "verified_boot_key": "0000000000000000000000000000000000000000000000000000000000000000", "verified_boot_key_hash": "0000000000000000000000000000000000000000000000000000000000000000", - "boot_state": 0, + "boot_state": 2, "device_locked": 0 }, "attest_key": "/data/vendor/ec_key.der", - "attest_cert_chain": "/data/vendor/ec_cert_chain.der" + "attest_cert_chain": [ + "/data/vendor/ec_cert.der", + "/data/vendor/ec_root_cert.der" + ] } From 2134a5e8b6ea3233869c085f6976ead0b023188c Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Mon, 25 Jan 2021 15:35:50 +0530 Subject: [PATCH 71/99] Removed sample_json.txt --- HAL/keymaster/sample_json.txt | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100644 HAL/keymaster/sample_json.txt diff --git a/HAL/keymaster/sample_json.txt b/HAL/keymaster/sample_json.txt deleted file mode 100644 index b65164aa..00000000 --- a/HAL/keymaster/sample_json.txt +++ /dev/null @@ -1,25 +0,0 @@ -{ - "attest_ids": { - "brand": "Google", - "device": "Pixel 3A", - "product": "Pixel", - "serial": "UGYJFDjFeRuBEH", - "imei": "987080543071019", - "meid": "27863510227963", - "manufacturer": "Foxconn", - "model": "HD1121" - }, - "shared_secret": "0000000000000000000000000000000000000000000000000000000000000000", - "set_boot_params": { - "os_version": 100, - "os_patch_level": 100, - "vendor_patch_level": 0, - "boot_patch_level": 0, - "verified_boot_key": "0000000000000000000000000000000000000000000000000000000000000000", - "verified_boot_key_hash": "0000000000000000000000000000000000000000000000000000000000000000", - "boot_state": 0, - "device_locked": 0 - }, - "attest_key": "/data/data/ec_key.der", - "attest_cert_chain": "/data/data/ec_cert_chain.der" -} From dc379c7d6ce21535ff6d25bacae047d9f2d0dcd0 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Mon, 25 Jan 2021 19:43:42 +0530 Subject: [PATCH 72/99] Added uninit function --- HAL/keymaster/4.1/Provision.cpp | 11 ++++++++++- HAL/keymaster/include/Provision.h | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/HAL/keymaster/4.1/Provision.cpp b/HAL/keymaster/4.1/Provision.cpp index a896db88..c8f97660 100644 --- a/HAL/keymaster/4.1/Provision.cpp +++ b/HAL/keymaster/4.1/Provision.cpp @@ -197,7 +197,8 @@ ErrorCode Provision::initProvision() { if(pTransportFactory == nullptr) { pTransportFactory = std::unique_ptr(new se_transport::TransportFactory( android::base::GetBoolProperty("ro.kernel.qemu", false))); - pTransportFactory->openConnection(); + if(!pTransportFactory->openConnection()) + return ErrorCode::UNKNOWN_ERROR; } return ErrorCode::OK; } @@ -399,6 +400,14 @@ ErrorCode Provision::lockProvision() { } return errorCode; } + +ErrorCode Provision::uninit() { + if(pTransportFactory != nullptr) { + if(!pTransportFactory->closeConnection()) + return ErrorCode::UNKNOWN_ERROR; + } + return ErrorCode::OK; +} // Provision End } // namespace javacard diff --git a/HAL/keymaster/include/Provision.h b/HAL/keymaster/include/Provision.h index e6b670f2..64b56641 100644 --- a/HAL/keymaster/include/Provision.h +++ b/HAL/keymaster/include/Provision.h @@ -58,6 +58,7 @@ class Provision { ErrorCode provisionBootParameters(BootParams& bootParams ); ErrorCode lockProvision(); ErrorCode getProvisionStatus(uint64_t&); + ErrorCode uninit(); private: std::unique_ptr pTransportFactory; From 697a0405ecb8c59467dea1392c30854d29ea97c2 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Tue, 26 Jan 2021 15:09:55 +0530 Subject: [PATCH 73/99] modified the function to init and uninit --- HAL/keymaster/4.1/Provision.cpp | 4 +--- HAL/keymaster/include/Provision.h | 32 +++++++++++++++++++++++++++- provisioning_tool/provision_tool.cpp | 4 +++- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/HAL/keymaster/4.1/Provision.cpp b/HAL/keymaster/4.1/Provision.cpp index c8f97660..85bdd241 100644 --- a/HAL/keymaster/4.1/Provision.cpp +++ b/HAL/keymaster/4.1/Provision.cpp @@ -191,9 +191,7 @@ extendedOutput) { return ret; } -// Class Provision Start - -ErrorCode Provision::initProvision() { +ErrorCode Provision::init() { if(pTransportFactory == nullptr) { pTransportFactory = std::unique_ptr(new se_transport::TransportFactory( android::base::GetBoolProperty("ro.kernel.qemu", false))); diff --git a/HAL/keymaster/include/Provision.h b/HAL/keymaster/include/Provision.h index 64b56641..e541c496 100644 --- a/HAL/keymaster/include/Provision.h +++ b/HAL/keymaster/include/Provision.h @@ -49,15 +49,45 @@ typedef struct AttestIDParams_ { class Provision { public: - ErrorCode initProvision(); + /** + * Initalizes the transport layer. + */ + ErrorCode init(); + /** + * Provision the Attestation key. + */ ErrorCode provisionAttestationKey(std::vector& batchKey); + /** + * Provision the Attestation certificate chain. + */ ErrorCode provisionAtestationCertificateChain(std::vector>& CertChain); + /** + * Provision the Attestation certificate paramters. + */ ErrorCode provisionAttestationCertificateParams(std::vector& batchCertificate); + /** + * Provision the Attestation ID. + */ ErrorCode provisionAttestationID(AttestIDParams& attestParams); + /** + * Provision the pre-shared secret. + */ ErrorCode provisionPreSharedSecret(std::vector& preSharedSecret); + /** + * Provision the boot parameters. + */ ErrorCode provisionBootParameters(BootParams& bootParams ); + /** + * Locks the provision. After this no more provision commanands are allowed. + */ ErrorCode lockProvision(); + /** + * Get the provision status. + */ ErrorCode getProvisionStatus(uint64_t&); + /** + * Uninitialize the transport layer. + */ ErrorCode uninit(); private: diff --git a/provisioning_tool/provision_tool.cpp b/provisioning_tool/provision_tool.cpp index 820384b1..e3148fec 100644 --- a/provisioning_tool/provision_tool.cpp +++ b/provisioning_tool/provision_tool.cpp @@ -519,7 +519,7 @@ int main(int argc, char* argv[]) usage(); } /* Initialize provision */ - mProvision.initProvision(); + mProvision.init(); /* getopt_long stores the option index here. */ while ((c = getopt_long(argc, argv, ":slha:k:c:p:i:r:b:", longOpts, NULL)) != -1) { @@ -582,5 +582,7 @@ int main(int argc, char* argv[]) if(optind < argc) { usage(); } + /*Uninitalize */ + mProvision.uninit(); return 0; } From 6dcb7ced192a1605972f75d8f4a29f087d27c926 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Wed, 27 Jan 2021 11:17:06 +0530 Subject: [PATCH 74/99] 1. Renamed the certiicate and key file names in sample_json.txt 2. Separated the Provision library from HAL and put it inside the provisioning_tool folder --- HAL/keymaster/Android.bp | 7 ++--- provisioning_tool/Android.bp | 27 +++++++++++++++++++ .../4.1 => provisioning_tool}/Provision.cpp | 0 .../include => provisioning_tool}/Provision.h | 0 provisioning_tool/sample_json.txt | 6 ++--- 5 files changed, 32 insertions(+), 8 deletions(-) rename {HAL/keymaster/4.1 => provisioning_tool}/Provision.cpp (100%) rename {HAL/keymaster/include => provisioning_tool}/Provision.h (100%) diff --git a/HAL/keymaster/Android.bp b/HAL/keymaster/Android.bp index 9db148da..1bcc6e2c 100644 --- a/HAL/keymaster/Android.bp +++ b/HAL/keymaster/Android.bp @@ -25,8 +25,6 @@ cc_binary { "4.1/JavacardKeymaster4Device.cpp", "4.1/JavacardSoftKeymasterContext.cpp", "4.1/JavacardOperationContext.cpp", - "4.1/CommonUtils.cpp", - "4.1/CborConverter.cpp", ], local_include_dirs: [ "include", @@ -46,6 +44,7 @@ cc_binary { "android.hardware.keymaster@4.1", "android.hardware.keymaster@4.0", "libjc_transport", + "libjc_common", "libcrypto", ], product_variables: { @@ -111,12 +110,11 @@ cc_library { } cc_library { - name: "libjc_provision", + name: "libjc_common", vendor_available: true, srcs: [ "4.1/CommonUtils.cpp", "4.1/CborConverter.cpp", - "4.1/Provision.cpp", ], local_include_dirs: [ "include", @@ -138,7 +136,6 @@ cc_library { "libcppbor", "android.hardware.keymaster@4.1", "android.hardware.keymaster@4.0", - "libjc_transport", "libcrypto", ], } diff --git a/provisioning_tool/Android.bp b/provisioning_tool/Android.bp index b9b39808..579d2ff4 100644 --- a/provisioning_tool/Android.bp +++ b/provisioning_tool/Android.bp @@ -36,6 +36,33 @@ cc_binary { "libjc_transport", "libcrypto", "libjsoncpp", + "libjc_common", "libjc_provision", ], } + +cc_library { + name: "libjc_provision", + vendor_available: true, + srcs: [ + "Provision.cpp", + ], + shared_libs: [ + "liblog", + "libcutils", + "libdl", + "libbase", + "libutils", + "libhardware", + "libhidlbase", + "libsoftkeymasterdevice", + "libkeymaster_messages", + "libkeymaster_portable", + "libcppbor", + "android.hardware.keymaster@4.1", + "android.hardware.keymaster@4.0", + "libjc_transport", + "libcrypto", + "libjc_common", + ], +} diff --git a/HAL/keymaster/4.1/Provision.cpp b/provisioning_tool/Provision.cpp similarity index 100% rename from HAL/keymaster/4.1/Provision.cpp rename to provisioning_tool/Provision.cpp diff --git a/HAL/keymaster/include/Provision.h b/provisioning_tool/Provision.h similarity index 100% rename from HAL/keymaster/include/Provision.h rename to provisioning_tool/Provision.h diff --git a/provisioning_tool/sample_json.txt b/provisioning_tool/sample_json.txt index 841c9843..8751c6b4 100644 --- a/provisioning_tool/sample_json.txt +++ b/provisioning_tool/sample_json.txt @@ -20,9 +20,9 @@ "boot_state": 2, "device_locked": 0 }, - "attest_key": "/data/vendor/ec_key.der", + "attest_key": "/data/vendor/batch_key.der", "attest_cert_chain": [ - "/data/vendor/ec_cert.der", - "/data/vendor/ec_root_cert.der" + "/data/vendor/batch_cert.der", + "/data/vendor/root_cert.der" ] } From 8f6e409cc9e34c4aa10405c01ab4b45611b9801e Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Fri, 29 Jan 2021 10:34:08 +0530 Subject: [PATCH 75/99] Store master key as Key object rather than as a byte array --- .../keymaster/KMAndroidSEProvider.java | 4 +- .../javacard/keymaster/KMJCardSimulator.java | 4 +- .../javacard/keymaster/KMKeymasterApplet.java | 12 +++- .../javacard/keymaster/KMRepository.java | 62 ++++++++++++------- 4 files changed, 53 insertions(+), 29 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java index 4b0994f4..20417d0f 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java @@ -105,7 +105,7 @@ public class KMAndroidSEProvider 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 CERT_CHAIN_MAX_SIZE = 2050;//First 2 bytes for length. + public static final short CERT_CHAIN_MAX_SIZE = 2500;//First 2 bytes for length. final byte[] CIPHER_ALGS = { Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, @@ -1143,7 +1143,7 @@ public void persistPartialCertificateChain(byte[] buf, short offset, short len, // 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. - if (totalLen > CERT_CHAIN_MAX_SIZE) { + if (totalLen > (short) (CERT_CHAIN_MAX_SIZE - 2)) { KMException.throwIt(KMError.INVALID_INPUT_LENGTH); } short persistedLen = Util.getShort(certificateChain, (short) 0); diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java index a9a6a937..08c3d0ea 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java @@ -71,7 +71,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 short CERT_CHAIN_MAX_SIZE = 2050;//First 2 bytes for length. + private static final short CERT_CHAIN_MAX_SIZE = 2500;//First 2 bytes for length. public static boolean jcardSim = false; @@ -1246,7 +1246,7 @@ public void persistPartialCertificateChain(byte[] buf, short offset, // 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. - if (totalLen > CERT_CHAIN_MAX_SIZE) { + if (totalLen > (short) (CERT_CHAIN_MAX_SIZE - 2)) { KMException.throwIt(KMError.INVALID_INPUT_LENGTH); } short persistedLen = Util.getShort(certificateChain, (short) 0); diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index a85a7243..6074038b 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -1530,7 +1530,11 @@ private void setUniqueId(KMAttestationCert cert, byte[] scratchPad) { } //master key. - tmpVariables[2] = repository.getMasterKeySecret(); + tmpVariables[2] = KMByteBlob.instance(KMRepository.MASTER_KEY_SIZE); + repository.getMasterKeySecret( + KMByteBlob.cast(tmpVariables[2]).getBuffer(), + KMByteBlob.cast(tmpVariables[2]).getStartOff(), + KMByteBlob.cast(tmpVariables[2]).length()); cert.makeUniqueId( scratchPad, (short) 0, @@ -3903,7 +3907,11 @@ private static short deriveKey(byte[] scratchPad) { // 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[4] = KMByteBlob.instance(KMRepository.MASTER_KEY_SIZE); + repository.getMasterKeySecret( + KMByteBlob.cast(tmpVariables[4]).getBuffer(), + KMByteBlob.cast(tmpVariables[4]).getStartOff(), + KMByteBlob.cast(tmpVariables[4]).length()); tmpVariables[5] = repository.alloc(AES_GCM_AUTH_TAG_LENGTH); tmpVariables[3] = seProvider.aesGCMEncrypt( diff --git a/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/src/com/android/javacard/keymaster/KMRepository.java index 4c30a613..94951348 100644 --- a/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/Applet/src/com/android/javacard/keymaster/KMRepository.java @@ -22,6 +22,8 @@ import javacard.framework.ISOException; import javacard.framework.JCSystem; import javacard.framework.Util; +import javacard.security.AESKey; +import javacard.security.KeyBuilder; /** * KMRepository class manages persistent and volatile memory usage by the applet. Note the repository @@ -29,7 +31,7 @@ */ public class KMRepository implements KMUpgradable { // Data table configuration - public static final short DATA_INDEX_SIZE = 24; + public static final short DATA_INDEX_SIZE = 23; public static final short DATA_INDEX_ENTRY_SIZE = 4; public static final short DATA_MEM_SIZE = 2048; public static final short HEAP_SIZE = 10000; @@ -42,10 +44,9 @@ public class KMRepository implements KMUpgradable { private static final short OPERATION_HANDLE_ENTRY_SIZE = OPERATION_HANDLE_SIZE + OPERATION_HANDLE_STATUS_SIZE; // Data table offsets - public static final byte MASTER_KEY = 8; - public static final byte SHARED_KEY = 9; - public static final byte COMPUTED_HMAC_KEY = 10; - public static final byte HMAC_NONCE = 11; + public static final byte SHARED_KEY = 8; + public static final byte COMPUTED_HMAC_KEY = 9; + public static final byte HMAC_NONCE = 10; public static final byte ATT_ID_BRAND = 0; public static final byte ATT_ID_DEVICE = 1; public static final byte ATT_ID_PRODUCT = 2; @@ -54,18 +55,18 @@ public class KMRepository implements KMUpgradable { 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_EC_KEY = 12; - public static final byte CERT_ISSUER = 13; - public static final byte CERT_EXPIRY_TIME = 14; - public static final byte BOOT_OS_VERSION = 15; - public static final byte BOOT_OS_PATCH = 16; - public static final byte VENDOR_PATCH_LEVEL = 17; - public static final byte BOOT_PATCH_LEVEL = 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 ATT_EC_KEY = 11; + public static final byte CERT_ISSUER = 12; + public static final byte CERT_EXPIRY_TIME = 13; + public static final byte BOOT_OS_VERSION = 14; + public static final byte BOOT_OS_PATCH = 15; + public static final byte VENDOR_PATCH_LEVEL = 16; + public static final byte BOOT_PATCH_LEVEL = 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; // Data Item sizes public static final short MASTER_KEY_SIZE = 16; @@ -90,6 +91,7 @@ public class KMRepository implements KMUpgradable { private byte[] dataTable; private short dataIndex; private short reclaimIndex; + private AESKey masterKey; // Singleton instance private static KMRepository repository; @@ -249,9 +251,19 @@ public void releaseOperation(KMOperationState op) { } } - public void initMasterKey(byte[] key, short start, short len) { - if(len != MASTER_KEY_SIZE) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); - writeDataEntry(MASTER_KEY,key, start, len); + /** + * Masterkey is stored as a Javacard Key object instead of byte array. + * When master key is stored as a Key object, the Javacard OS internally + * provides appropriate security measures for the key to protect the key. + * The master key is maintained by Repository class so the Key object is + * created in this class itself rather than creating it in the SEProvider. + */ + public void initMasterKey(byte[] buf, short off, short len) { + if (len != MASTER_KEY_SIZE) + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + masterKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, + (short) (MASTER_KEY_SIZE * 8), false); + masterKey.setKey(buf, off); } public void initHmacSharedSecretKey(byte[] key, short start, short len) { @@ -296,8 +308,10 @@ public void onSelect() { // If write through caching is implemented then this method will restore the data into cache } - public short getMasterKeySecret() { - return readData(MASTER_KEY); + public void getMasterKeySecret(byte[] buffer, short offset, short length) { + if (length != MASTER_KEY_SIZE) + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + masterKey.getKey(buffer, offset); } // This function uses memory from the back of the heap(transient memory). Call @@ -629,12 +643,14 @@ public void setBootState(byte state){ public void onSave(Element ele) { ele.write(dataIndex); ele.write(dataTable); + ele.write(masterKey); } @Override public void onRestore(Element ele) { dataIndex = ele.readShort(); dataTable = (byte[]) ele.readObject(); + masterKey = (AESKey) ele.readObject(); } @Override @@ -646,6 +662,6 @@ public short getBackupPrimitiveByteCount() { @Override public short getBackupObjectCount() { // dataTable - return (short) 1; + return (short) 2; } } From d32c0c0c38193246522c1bbc16dccfb4ed383593 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Sun, 31 Jan 2021 08:37:33 +0530 Subject: [PATCH 76/99] updated the sample_json.txt to use 3 certificates instead of 2 --- HAL/keymaster/4.1/SocketTransport.cpp | 2 +- provisioning_tool/sample_json.txt | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/HAL/keymaster/4.1/SocketTransport.cpp b/HAL/keymaster/4.1/SocketTransport.cpp index 51c28675..331a00b1 100644 --- a/HAL/keymaster/4.1/SocketTransport.cpp +++ b/HAL/keymaster/4.1/SocketTransport.cpp @@ -24,7 +24,7 @@ #define PORT 8080 #define IPADDR "10.9.40.24" //#define IPADDR "192.168.0.5" -#define MAX_RECV_BUFFER_SIZE 2048 +#define MAX_RECV_BUFFER_SIZE 2500 namespace se_transport { diff --git a/provisioning_tool/sample_json.txt b/provisioning_tool/sample_json.txt index 8751c6b4..fbfd71de 100644 --- a/provisioning_tool/sample_json.txt +++ b/provisioning_tool/sample_json.txt @@ -23,6 +23,7 @@ "attest_key": "/data/vendor/batch_key.der", "attest_cert_chain": [ "/data/vendor/batch_cert.der", - "/data/vendor/root_cert.der" + "/data/vendor/intermediate_cert.der", + "/data/vendor/ca_cert.der" ] } From ee9ddb367472c1fecf173eb5f89ba9dbd20f86c7 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Mon, 1 Feb 2021 10:10:40 +0530 Subject: [PATCH 77/99] Removed the changes relating to storing master key as Key object --- .../javacard/keymaster/KMKeymasterApplet.java | 12 +--- .../javacard/keymaster/KMRepository.java | 62 +++++++------------ 2 files changed, 25 insertions(+), 49 deletions(-) diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 6074038b..a85a7243 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -1530,11 +1530,7 @@ private void setUniqueId(KMAttestationCert cert, byte[] scratchPad) { } //master key. - tmpVariables[2] = KMByteBlob.instance(KMRepository.MASTER_KEY_SIZE); - repository.getMasterKeySecret( - KMByteBlob.cast(tmpVariables[2]).getBuffer(), - KMByteBlob.cast(tmpVariables[2]).getStartOff(), - KMByteBlob.cast(tmpVariables[2]).length()); + tmpVariables[2] = repository.getMasterKeySecret(); cert.makeUniqueId( scratchPad, (short) 0, @@ -3907,11 +3903,7 @@ private static short deriveKey(byte[] scratchPad) { // 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] = KMByteBlob.instance(KMRepository.MASTER_KEY_SIZE); - repository.getMasterKeySecret( - KMByteBlob.cast(tmpVariables[4]).getBuffer(), - KMByteBlob.cast(tmpVariables[4]).getStartOff(), - KMByteBlob.cast(tmpVariables[4]).length()); + tmpVariables[4] = repository.getMasterKeySecret(); tmpVariables[5] = repository.alloc(AES_GCM_AUTH_TAG_LENGTH); tmpVariables[3] = seProvider.aesGCMEncrypt( diff --git a/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/src/com/android/javacard/keymaster/KMRepository.java index 94951348..4c30a613 100644 --- a/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/Applet/src/com/android/javacard/keymaster/KMRepository.java @@ -22,8 +22,6 @@ import javacard.framework.ISOException; import javacard.framework.JCSystem; import javacard.framework.Util; -import javacard.security.AESKey; -import javacard.security.KeyBuilder; /** * KMRepository class manages persistent and volatile memory usage by the applet. Note the repository @@ -31,7 +29,7 @@ */ public class KMRepository implements KMUpgradable { // Data table configuration - public static final short DATA_INDEX_SIZE = 23; + public static final short DATA_INDEX_SIZE = 24; public static final short DATA_INDEX_ENTRY_SIZE = 4; public static final short DATA_MEM_SIZE = 2048; public static final short HEAP_SIZE = 10000; @@ -44,9 +42,10 @@ public class KMRepository implements KMUpgradable { private static final short OPERATION_HANDLE_ENTRY_SIZE = OPERATION_HANDLE_SIZE + OPERATION_HANDLE_STATUS_SIZE; // Data table offsets - public static final byte SHARED_KEY = 8; - public static final byte COMPUTED_HMAC_KEY = 9; - public static final byte HMAC_NONCE = 10; + public static final byte MASTER_KEY = 8; + public static final byte SHARED_KEY = 9; + public static final byte COMPUTED_HMAC_KEY = 10; + public static final byte HMAC_NONCE = 11; public static final byte ATT_ID_BRAND = 0; public static final byte ATT_ID_DEVICE = 1; public static final byte ATT_ID_PRODUCT = 2; @@ -55,18 +54,18 @@ public class KMRepository implements KMUpgradable { 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_EC_KEY = 11; - public static final byte CERT_ISSUER = 12; - public static final byte CERT_EXPIRY_TIME = 13; - public static final byte BOOT_OS_VERSION = 14; - public static final byte BOOT_OS_PATCH = 15; - public static final byte VENDOR_PATCH_LEVEL = 16; - public static final byte BOOT_PATCH_LEVEL = 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 ATT_EC_KEY = 12; + public static final byte CERT_ISSUER = 13; + public static final byte CERT_EXPIRY_TIME = 14; + public static final byte BOOT_OS_VERSION = 15; + public static final byte BOOT_OS_PATCH = 16; + public static final byte VENDOR_PATCH_LEVEL = 17; + public static final byte BOOT_PATCH_LEVEL = 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; // Data Item sizes public static final short MASTER_KEY_SIZE = 16; @@ -91,7 +90,6 @@ public class KMRepository implements KMUpgradable { private byte[] dataTable; private short dataIndex; private short reclaimIndex; - private AESKey masterKey; // Singleton instance private static KMRepository repository; @@ -251,19 +249,9 @@ public void releaseOperation(KMOperationState op) { } } - /** - * Masterkey is stored as a Javacard Key object instead of byte array. - * When master key is stored as a Key object, the Javacard OS internally - * provides appropriate security measures for the key to protect the key. - * The master key is maintained by Repository class so the Key object is - * created in this class itself rather than creating it in the SEProvider. - */ - public void initMasterKey(byte[] buf, short off, short len) { - if (len != MASTER_KEY_SIZE) - ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); - masterKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, - (short) (MASTER_KEY_SIZE * 8), false); - masterKey.setKey(buf, off); + public void initMasterKey(byte[] key, short start, short len) { + if(len != MASTER_KEY_SIZE) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + writeDataEntry(MASTER_KEY,key, start, len); } public void initHmacSharedSecretKey(byte[] key, short start, short len) { @@ -308,10 +296,8 @@ public void onSelect() { // If write through caching is implemented then this method will restore the data into cache } - public void getMasterKeySecret(byte[] buffer, short offset, short length) { - if (length != MASTER_KEY_SIZE) - ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); - masterKey.getKey(buffer, offset); + public short getMasterKeySecret() { + return readData(MASTER_KEY); } // This function uses memory from the back of the heap(transient memory). Call @@ -643,14 +629,12 @@ public void setBootState(byte state){ public void onSave(Element ele) { ele.write(dataIndex); ele.write(dataTable); - ele.write(masterKey); } @Override public void onRestore(Element ele) { dataIndex = ele.readShort(); dataTable = (byte[]) ele.readObject(); - masterKey = (AESKey) ele.readObject(); } @Override @@ -662,6 +646,6 @@ public short getBackupPrimitiveByteCount() { @Override public short getBackupObjectCount() { // dataTable - return (short) 2; + return (short) 1; } } From 4c9794e7160140b54c94cb3682e3a723c920eac8 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Tue, 2 Feb 2021 18:06:17 +0530 Subject: [PATCH 78/99] Added log statements --- provisioning_tool/provision_tool.cpp | 44 ++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/provisioning_tool/provision_tool.cpp b/provisioning_tool/provision_tool.cpp index e3148fec..0f240b3c 100644 --- a/provisioning_tool/provision_tool.cpp +++ b/provisioning_tool/provision_tool.cpp @@ -177,6 +177,7 @@ bool getBootParameterBlobValue(Json::Value& bootParamsObj, const char* key, std: bool setBootParameters(const char* filename) { Json::Value bootParamsObj; bool ret = false; + ErrorCode err = ErrorCode::OK; keymaster::V4_1::javacard::BootParams bootParams; if(!parseJsonFile(filename)) @@ -219,10 +220,12 @@ bool setBootParameters(const char* filename) { } } else { + printf("\n Fail: Improper value found for set_boot_params key inside the json file\n"); return ret; } - if (ErrorCode::OK != mProvision.provisionBootParameters(bootParams)) { + if (ErrorCode::OK != (err = mProvision.provisionBootParameters(bootParams))) { + printf("\n set boot parameters failed with err:%d \n", (int32_t)err); return ret; } @@ -233,6 +236,7 @@ bool setBootParameters(const char* filename) { bool provisionAttestationIds(const char *filename) { Json::Value attestIds; bool ret = false; + ErrorCode err = ErrorCode::OK; keymaster::V4_1::javacard::AttestIDParams params; if(!parseJsonFile(filename)) @@ -248,6 +252,7 @@ bool provisionAttestationIds(const char *filename) { continue; } if (!value.isString()) { + printf("\n Fail: Value for each attest ids key should be a string in the json file \n"); return ret; } @@ -273,10 +278,12 @@ bool provisionAttestationIds(const char *filename) { } } - if (ErrorCode::OK != mProvision.provisionAttestationID(params)) { + if (ErrorCode::OK != (err = mProvision.provisionAttestationID(params))) { + printf("\n Provision attestationID parameters failed with err:%d \n", (int32_t)err); return ret; } } else { + printf("\n Fail: Improper value found for attest_ids key inside the json file \n"); return ret; } printf("\n provisioned attestation ids successfully \n"); @@ -330,6 +337,7 @@ bool getProvisionStatus() { bool provisionSharedSecret(const char* filename) { Json::Value sharedSecret; bool ret = false; + ErrorCode err = ErrorCode::OK; if(!parseJsonFile(filename)) return ret; @@ -338,14 +346,17 @@ bool provisionSharedSecret(const char* filename) { if (!sharedSecret.isNull()) { if (!sharedSecret.isString()) { + printf("\n Fail: Value for shared secret key should be string inside the json file\n"); return ret; } std::string secret = hex2str(sharedSecret.asString()); std::vector data(secret.begin(), secret.end()); - if(ErrorCode::OK != mProvision.provisionPreSharedSecret(data)) { + if(ErrorCode::OK != (err = mProvision.provisionPreSharedSecret(data))) { + printf("\n Provision pre-shared secret failed with err:%d \n", (int32_t)err); return ret; } } else { + printf("\n Fail: Improper value for shared_secret key inside the json file\n"); return ret; } printf("\n Provisioned shared secret successfully \n"); @@ -355,6 +366,7 @@ bool provisionSharedSecret(const char* filename) { static bool provisionAttestationKey(const char* filename) { Json::Value keyFile; bool ret = false; + ErrorCode err = ErrorCode::OK; if(!parseJsonFile(filename)) return ret; @@ -368,10 +380,12 @@ static bool provisionAttestationKey(const char* filename) { printf("\n Failed to read the Root ec key\n"); return ret; } - if(ErrorCode::OK != mProvision.provisionAttestationKey(data)) { + if(ErrorCode::OK != (err = mProvision.provisionAttestationKey(data))) { + printf("\n Provision attestation key failed with error: %d\n", (int32_t)err); return ret; } } else { + printf("\n Improper value for attest_key in json file \n"); return ret; } printf("\n Provisioned attestation key successfully\n"); @@ -381,6 +395,7 @@ static bool provisionAttestationKey(const char* filename) { bool provisionAttestationCertificateChain(const char* filename) { Json::Value certChainFile; bool ret = false; + ErrorCode err = ErrorCode::OK; if(!parseJsonFile(filename)) return ret; @@ -400,16 +415,20 @@ bool provisionAttestationCertificateChain(const char* filename) { } certData.push_back(std::move(tmp)); } else { + printf("\n Fail: Only proper certificate paths as a string is allowed inside the json file. \n"); return ret; } } } else { + printf("\n Fail: cert chain value should be an array inside the json file. \n"); return ret; } - if (ErrorCode::OK != mProvision.provisionAtestationCertificateChain(certData)) { + if (ErrorCode::OK != (err = mProvision.provisionAtestationCertificateChain(certData))) { + printf("\n Provision certificate chain failed with error: %d\n", (int32_t)err); return ret; } } else { + printf("\n Fail: Improper value found for attest_cert_chain key inside json file \n"); return ret; } printf("\n Provisioned attestation certificate chain successfully\n"); @@ -419,6 +438,7 @@ bool provisionAttestationCertificateChain(const char* filename) { bool provisionAttestationCertificateParams(const char* filename) { Json::Value certChainFile; bool ret = false; + ErrorCode err = ErrorCode::OK; if(!parseJsonFile(filename)) return ret; @@ -436,13 +456,16 @@ bool provisionAttestationCertificateParams(const char* filename) { printf("\n Failed to read the Root certificate\n"); return ret; } - if (ErrorCode::OK != mProvision.provisionAttestationCertificateParams(tmp)) { + if (ErrorCode::OK != (err = mProvision.provisionAttestationCertificateParams(tmp))) { + printf("\n Provision certificate params failed with error: %d\n", (int32_t)err); return ret; } } else { + printf("\n Fail: cert chain value should be an array inside the json file. \n"); return ret; } } else { + printf("\n Fail: Improper value found for attest_cert_chain key inside json file \n"); return ret; } printf("\n Provisioned attestation certificate parameters successfully\n"); @@ -452,27 +475,21 @@ bool provisionAttestationCertificateParams(const char* filename) { bool provision(const char* filename) { if(!provisionAttestationKey(filename)) { - printf("\n Failed to provision attestation Key\n"); return false; } if(!provisionAttestationCertificateChain(filename)) { - printf("\n Failed to provision certificate chain\n"); return false; } if(!provisionAttestationCertificateParams(filename)) { - printf("\n Failed to provision certificate paramters\n"); return false; } if(!provisionSharedSecret(filename)) { - printf("\n Failed to provision shared secret\n"); return false; } if(!provisionAttestationIds(filename)) { - printf("\n Failed to provision attestation ids\n"); return false; } if(!setBootParameters(filename)) { - printf("\n Failed to set boot parameters\n"); return false; } return true; @@ -526,7 +543,8 @@ int main(int argc, char* argv[]) switch(c) { case 'a': //all - provision(optarg); + if(!provision(optarg)) + printf("\n Failed to provision the device \n"); break; case 'k': //attest key From e51ab8a0922d868a86eb7769b6f50414fb5bb676 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Tue, 2 Feb 2021 18:11:17 +0530 Subject: [PATCH 79/99] 1. Corrected the convertToDate algorithm to generate correct time and date. 2. Added new method for UnsignedArrayCompare. --- .../android/javacard/keymaster/KMUtils.java | 172 ++++++++++++++---- .../keymaster/KMRsa2048NoDigestSignature.java | 2 +- .../android/javacard/keymaster/KMUtils.java | 170 +++++++++++++---- .../android/javacard/keymaster/KMInteger.java | 2 +- .../javacard/keymaster/KMKeymasterApplet.java | 4 +- 5 files changed, 281 insertions(+), 69 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java index d9d7e111..cb8df259 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java @@ -14,23 +14,36 @@ public class KMUtils { 0, 0, 0, 0, 0x05, 0x26, 0x5C, 0x00 }; // 86400000 msec public static final byte[] oneMonthMsec = { 0, 0, 0, 0, (byte) 0x9C,(byte) 0xBE, (byte) 0xBD, 0x50}; // 2629746000 msec - public static final byte[] oneYearMsec = { - 0, 0, 0, 0x07, 0x58, (byte) 0xF0, (byte) 0xDF, (byte) 0xC0 }; // 31556952000 msec - // Leap year + 3 yrs + public static final byte[] leapYearMsec = { + 0, 0, 0, 0x07, (byte) 0x5C, (byte) 0xD7, (byte) 0x88, 0x00}; //31622400000; + public static final byte[] yearMsec = { + 0, 0, 0, 0x07, 0x57, (byte) 0xB1, 0x2C, 0x00}; //31536000000 + //Leap year(366) + 3 * 365 public static final byte[] fourYrsMsec = { - 0, 0, 0, 0x1D, 0x63, (byte) 0xC3, 0x7F, 0x00 }; // 126227808000 msec + 0, 0, 0, 0x1D, 0x63, (byte) 0xEB, 0x0C, 0x00};//126230400000 public static final byte[] firstJan2020 = { - 0, 0, 0x01, 0x6F, 0x5E, 0x66, (byte)0xE8, 0x00 }; // 1577836800000 msec + 0, 0, 0x01, 0x6F, 0x5E, 0x66, (byte)0xE8, 0x00 }; // 1577836800000 msec public static final byte[] firstJan2051 = { 0, 0, 0x02, 0x53, 0x26, (byte) 0x0E, (byte) 0x1C, 0x00 }; // 2556144000000 // msec + public static final byte[] febMonthLeapMSec = { + 0, 0, 0, 0, (byte) 0x95, 0x58, 0x6C, 0x00 }; //2505600000 + public static final byte[] febMonthMsec = { + 0, 0, 0, 0, (byte) 0x90, 0x32, 0x10, 0x00 }; //2419200000 + public static final byte[] ThirtyOneDaysMonthMsec = { + 0, 0, 0, 0, (byte) 0x9F, (byte) 0xA5, 0x24, 0x00 };//2678400000 + public static final byte[] ThirtDaysMonthMsec = { + 0, 0, 0, 0, (byte) 0x9A, 0x7E, (byte) 0xC8, 0x00 };//2592000000 + public static final short year2051 = 2051; + public static final short year2020 = 2020; // -------------------------------------- public static short convertToDate(short time, byte[] scratchPad, boolean utcFlag) { + short yrsCount = 0; short monthCount = 1; - short dayCount = 0; + short dayCount = 1; short hhCount = 0; short mmCount = 0; short ssCount = 0; @@ -42,17 +55,17 @@ public static short convertToDate(short time, byte[] 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, + if (unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2020, (short) 0, (short) 8) < 0) { KMException.throwIt(KMError.INVALID_ARGUMENT); } if (utcFlag - && Util.arrayCompare(scratchPad, (short) 0, firstJan2051, + && unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, (short) 0, (short) 8) >= 0) { KMException.throwIt(KMError.INVALID_ARGUMENT); } - if (Util.arrayCompare(scratchPad, (short) 0, firstJan2051, (short) 0, + if (unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, (short) 0, (short) 8) < 0) { Util.arrayCopyNonAtomic(firstJan2020, (short) 0, scratchPad, (short) 8, (short) 8); @@ -68,7 +81,7 @@ public static short convertToDate(short time, byte[] scratchPad, (short) 8); } // divide the given time with four yrs msec count - if (Util.arrayCompare(scratchPad, (short) 0, fourYrsMsec, (short) 0, + if (unsignedByteArrayCompare(scratchPad, (short) 0, fourYrsMsec, (short) 0, (short) 8) >= 0) { Util.arrayCopyNonAtomic(fourYrsMsec, (short) 0, scratchPad, (short) 8, (short) 8); @@ -81,44 +94,97 @@ public static short convertToDate(short time, byte[] scratchPad, 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); + + //Get the leap year index starting from the (base Year + yrsCount) Year. + short leapYrIdx = getLeapYrIndex(from2020, yrsCount); + + // if leap year index is 0, then the number of days for the 1st year will be 366 days. + // if leap year index is not 0, then the number of days for the 1st year will be 365 days. + if (((leapYrIdx == 0) && + (unsignedByteArrayCompare(scratchPad, (short) 0, leapYearMsec, (short) 0,(short) 8) >= 0)) || + ((leapYrIdx != 0) && + (unsignedByteArrayCompare(scratchPad, (short) 0, yearMsec, (short) 0,(short) 8) >= 0))) { + for (short i = 0; i < 4; i++) { + yrsCount++; + if (i == leapYrIdx) { + Util.arrayCopyNonAtomic(leapYearMsec, (short) 0, scratchPad, + (short) 8, (short) 8); + } else { + Util.arrayCopyNonAtomic(yearMsec, (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); + if (((short) (i + 1) == leapYrIdx)) { + if (unsignedByteArrayCompare(scratchPad, (short) 0, leapYearMsec, + (short) 0, (short) 8) < 0) { + break; + } + } else { + if (unsignedByteArrayCompare(scratchPad, (short) 0, yearMsec, + (short) 0, (short) 8) < 0) { + break; + } + } + } } + // total yrs from 1970 if (from2020) - yrsCount = (short) (2020 + yrsCount); + yrsCount = (short) (year2020 + yrsCount); else - yrsCount = (short) (2051 + yrsCount); + yrsCount = (short) (year2051 + yrsCount); // divide the given time with one month msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneMonthMsec, (short) 0, + if (unsignedByteArrayCompare(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); - monthCount++; - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); + for (short i = 0; i < 12; i++) { + if (i == 1) { + // Feb month + if (isLeapYear(yrsCount)) { + // Leap year 29 days + Util.arrayCopyNonAtomic(febMonthLeapMSec, (short) 0, scratchPad, + (short) 8, (short) 8); + } else { + // 28 days + Util.arrayCopyNonAtomic(febMonthMsec, (short) 0, scratchPad, + (short) 8, (short) 8); + } + } else if (((i <= 6) && ((i % 2 == 0))) || ((i > 6) && ((i % 2 == 1)))) { + Util.arrayCopyNonAtomic(ThirtyOneDaysMonthMsec, (short) 0, + scratchPad, (short) 8, (short) 8); + } else { + // 30 Days + Util.arrayCopyNonAtomic(ThirtDaysMonthMsec, (short) 0, scratchPad, + (short) 8, (short) 8); + } + + if (unsignedByteArrayCompare(scratchPad, (short) 0, scratchPad, (short) 8, + (short) 8) >= 0) { + subtract(scratchPad, (short) 0, (short) 8, (short) 16); + Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, + (short) 8); + } else { + break; + } + monthCount++; + } } // divide the given time with one day msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneDayMsec, (short) 0, + if (unsignedByteArrayCompare(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); + dayCount++; 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, + if (unsignedByteArrayCompare(scratchPad, (short) 0, oneHourMsec, (short) 0, (short) 8) >= 0) { Util.arrayCopyNonAtomic(oneHourMsec, (short) 0, scratchPad, (short) 8, (short) 8); @@ -128,7 +194,7 @@ public static short convertToDate(short time, byte[] scratchPad, } // divide the given time with one minute msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneMinMsec, (short) 0, + if (unsignedByteArrayCompare(scratchPad, (short) 0, oneMinMsec, (short) 0, (short) 8) >= 0) { Util.arrayCopyNonAtomic(oneMinMsec, (short) 0, scratchPad, (short) 8, (short) 8); @@ -138,7 +204,7 @@ public static short convertToDate(short time, byte[] scratchPad, } // divide the given time with one second msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneSecMsec, (short) 0, + if (unsignedByteArrayCompare(scratchPad, (short) 0, oneSecMsec, (short) 0, (short) 8) >= 0) { Util.arrayCopyNonAtomic(oneSecMsec, (short) 0, scratchPad, (short) 8, (short) 8); @@ -163,6 +229,25 @@ public static short convertToDate(short time, byte[] scratchPad, return KMByteBlob.instance(scratchPad, (short) 0, len); // YYYY } + public static byte unsignedByteArrayCompare(byte[] a1, short offset1, byte[] a2, short offset2, short length) { + byte count = (byte) 0; + short val1 = (short)0; + short val2 = (short)0; + + for (; count < length; count++) { + val1 = (short) (a1[(short) (count + offset1)] & 0x00FF); + val2 = (short) (a2[(short) (count + offset2)] & 0x00FF); + + if (val1 < val2) { + return -1; + } + if (val1 > val2) { + return 1; + } + } + return 0; + } + public static short numberToString(short number, byte[] scratchPad, short offset) { byte zero = 0x30; @@ -211,7 +296,7 @@ public static void copy(byte[] buf, short from, short to) { } public static byte compare(byte[] buf, short lhs, short rhs) { - return Util.arrayCompare(buf, lhs, buf, rhs, (short) 8); + return unsignedByteArrayCompare(buf, lhs, buf, rhs, (short) 8); } public static void shiftLeft(byte[] buf, short start) { @@ -319,4 +404,25 @@ public static short countTemporalCount(byte[] bufTime, short timeOff, return divide(scratchPad, (short) 0, (short) 8, (short) 16); } -} + public static boolean isLeapYear(short year) { + if ((short)(year%4) == (short) 0) { + if (((short)(year % 100) == (short) 0) && + ((short) (year % 400)) != (short) 0) { + return false; + } + return true; + } + return false; + } + + public static short getLeapYrIndex(boolean from2020, short yrsCount) { + short newBaseYr = (short) (from2020 ? (year2020 + yrsCount) : (year2051 + yrsCount)); + for(short i = 0; i < 4; i++) { + if(isLeapYear((short)(newBaseYr + i))) { + return i; + } + } + return -1; + } + +} \ No newline at end of file diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java index 38e9a3bc..3ebf5fe0 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java @@ -107,7 +107,7 @@ 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); + short v = KMUtils.unsignedByteArrayCompare(buf, start, rsaModulus, (short) 0, len); if (v > 0) return false; } } else {//pkcs1 no digest diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java index 41bbe1ff..cb8df259 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java @@ -14,23 +14,36 @@ public class KMUtils { 0, 0, 0, 0, 0x05, 0x26, 0x5C, 0x00 }; // 86400000 msec public static final byte[] oneMonthMsec = { 0, 0, 0, 0, (byte) 0x9C,(byte) 0xBE, (byte) 0xBD, 0x50}; // 2629746000 msec - public static final byte[] oneYearMsec = { - 0, 0, 0, 0x07, 0x58, (byte) 0xF0, (byte) 0xDF, (byte) 0xC0 }; // 31556952000 msec - // Leap year + 3 yrs + public static final byte[] leapYearMsec = { + 0, 0, 0, 0x07, (byte) 0x5C, (byte) 0xD7, (byte) 0x88, 0x00}; //31622400000; + public static final byte[] yearMsec = { + 0, 0, 0, 0x07, 0x57, (byte) 0xB1, 0x2C, 0x00}; //31536000000 + //Leap year(366) + 3 * 365 public static final byte[] fourYrsMsec = { - 0, 0, 0, 0x1D, 0x63, (byte) 0xC3, 0x7F, 0x00 }; // 126227808000 msec + 0, 0, 0, 0x1D, 0x63, (byte) 0xEB, 0x0C, 0x00};//126230400000 public static final byte[] firstJan2020 = { 0, 0, 0x01, 0x6F, 0x5E, 0x66, (byte)0xE8, 0x00 }; // 1577836800000 msec public static final byte[] firstJan2051 = { 0, 0, 0x02, 0x53, 0x26, (byte) 0x0E, (byte) 0x1C, 0x00 }; // 2556144000000 // msec + public static final byte[] febMonthLeapMSec = { + 0, 0, 0, 0, (byte) 0x95, 0x58, 0x6C, 0x00 }; //2505600000 + public static final byte[] febMonthMsec = { + 0, 0, 0, 0, (byte) 0x90, 0x32, 0x10, 0x00 }; //2419200000 + public static final byte[] ThirtyOneDaysMonthMsec = { + 0, 0, 0, 0, (byte) 0x9F, (byte) 0xA5, 0x24, 0x00 };//2678400000 + public static final byte[] ThirtDaysMonthMsec = { + 0, 0, 0, 0, (byte) 0x9A, 0x7E, (byte) 0xC8, 0x00 };//2592000000 + public static final short year2051 = 2051; + public static final short year2020 = 2020; // -------------------------------------- public static short convertToDate(short time, byte[] scratchPad, boolean utcFlag) { + short yrsCount = 0; short monthCount = 1; - short dayCount = 0; + short dayCount = 1; short hhCount = 0; short mmCount = 0; short ssCount = 0; @@ -42,17 +55,17 @@ public static short convertToDate(short time, byte[] 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, + if (unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2020, (short) 0, (short) 8) < 0) { KMException.throwIt(KMError.INVALID_ARGUMENT); } if (utcFlag - && Util.arrayCompare(scratchPad, (short) 0, firstJan2051, + && unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, (short) 0, (short) 8) >= 0) { KMException.throwIt(KMError.INVALID_ARGUMENT); } - if (Util.arrayCompare(scratchPad, (short) 0, firstJan2051, (short) 0, + if (unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, (short) 0, (short) 8) < 0) { Util.arrayCopyNonAtomic(firstJan2020, (short) 0, scratchPad, (short) 8, (short) 8); @@ -68,7 +81,7 @@ public static short convertToDate(short time, byte[] scratchPad, (short) 8); } // divide the given time with four yrs msec count - if (Util.arrayCompare(scratchPad, (short) 0, fourYrsMsec, (short) 0, + if (unsignedByteArrayCompare(scratchPad, (short) 0, fourYrsMsec, (short) 0, (short) 8) >= 0) { Util.arrayCopyNonAtomic(fourYrsMsec, (short) 0, scratchPad, (short) 8, (short) 8); @@ -81,44 +94,97 @@ public static short convertToDate(short time, byte[] scratchPad, 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); + + //Get the leap year index starting from the (base Year + yrsCount) Year. + short leapYrIdx = getLeapYrIndex(from2020, yrsCount); + + // if leap year index is 0, then the number of days for the 1st year will be 366 days. + // if leap year index is not 0, then the number of days for the 1st year will be 365 days. + if (((leapYrIdx == 0) && + (unsignedByteArrayCompare(scratchPad, (short) 0, leapYearMsec, (short) 0,(short) 8) >= 0)) || + ((leapYrIdx != 0) && + (unsignedByteArrayCompare(scratchPad, (short) 0, yearMsec, (short) 0,(short) 8) >= 0))) { + for (short i = 0; i < 4; i++) { + yrsCount++; + if (i == leapYrIdx) { + Util.arrayCopyNonAtomic(leapYearMsec, (short) 0, scratchPad, + (short) 8, (short) 8); + } else { + Util.arrayCopyNonAtomic(yearMsec, (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); + if (((short) (i + 1) == leapYrIdx)) { + if (unsignedByteArrayCompare(scratchPad, (short) 0, leapYearMsec, + (short) 0, (short) 8) < 0) { + break; + } + } else { + if (unsignedByteArrayCompare(scratchPad, (short) 0, yearMsec, + (short) 0, (short) 8) < 0) { + break; + } + } + } } + // total yrs from 1970 if (from2020) - yrsCount = (short) (2020 + yrsCount); + yrsCount = (short) (year2020 + yrsCount); else - yrsCount = (short) (2051 + yrsCount); + yrsCount = (short) (year2051 + yrsCount); // divide the given time with one month msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneMonthMsec, (short) 0, + if (unsignedByteArrayCompare(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); - monthCount++; - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); + for (short i = 0; i < 12; i++) { + if (i == 1) { + // Feb month + if (isLeapYear(yrsCount)) { + // Leap year 29 days + Util.arrayCopyNonAtomic(febMonthLeapMSec, (short) 0, scratchPad, + (short) 8, (short) 8); + } else { + // 28 days + Util.arrayCopyNonAtomic(febMonthMsec, (short) 0, scratchPad, + (short) 8, (short) 8); + } + } else if (((i <= 6) && ((i % 2 == 0))) || ((i > 6) && ((i % 2 == 1)))) { + Util.arrayCopyNonAtomic(ThirtyOneDaysMonthMsec, (short) 0, + scratchPad, (short) 8, (short) 8); + } else { + // 30 Days + Util.arrayCopyNonAtomic(ThirtDaysMonthMsec, (short) 0, scratchPad, + (short) 8, (short) 8); + } + + if (unsignedByteArrayCompare(scratchPad, (short) 0, scratchPad, (short) 8, + (short) 8) >= 0) { + subtract(scratchPad, (short) 0, (short) 8, (short) 16); + Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, + (short) 8); + } else { + break; + } + monthCount++; + } } // divide the given time with one day msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneDayMsec, (short) 0, + if (unsignedByteArrayCompare(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); + dayCount++; 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, + if (unsignedByteArrayCompare(scratchPad, (short) 0, oneHourMsec, (short) 0, (short) 8) >= 0) { Util.arrayCopyNonAtomic(oneHourMsec, (short) 0, scratchPad, (short) 8, (short) 8); @@ -128,7 +194,7 @@ public static short convertToDate(short time, byte[] scratchPad, } // divide the given time with one minute msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneMinMsec, (short) 0, + if (unsignedByteArrayCompare(scratchPad, (short) 0, oneMinMsec, (short) 0, (short) 8) >= 0) { Util.arrayCopyNonAtomic(oneMinMsec, (short) 0, scratchPad, (short) 8, (short) 8); @@ -138,7 +204,7 @@ public static short convertToDate(short time, byte[] scratchPad, } // divide the given time with one second msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneSecMsec, (short) 0, + if (unsignedByteArrayCompare(scratchPad, (short) 0, oneSecMsec, (short) 0, (short) 8) >= 0) { Util.arrayCopyNonAtomic(oneSecMsec, (short) 0, scratchPad, (short) 8, (short) 8); @@ -163,6 +229,25 @@ public static short convertToDate(short time, byte[] scratchPad, return KMByteBlob.instance(scratchPad, (short) 0, len); // YYYY } + public static byte unsignedByteArrayCompare(byte[] a1, short offset1, byte[] a2, short offset2, short length) { + byte count = (byte) 0; + short val1 = (short)0; + short val2 = (short)0; + + for (; count < length; count++) { + val1 = (short) (a1[(short) (count + offset1)] & 0x00FF); + val2 = (short) (a2[(short) (count + offset2)] & 0x00FF); + + if (val1 < val2) { + return -1; + } + if (val1 > val2) { + return 1; + } + } + return 0; + } + public static short numberToString(short number, byte[] scratchPad, short offset) { byte zero = 0x30; @@ -211,7 +296,7 @@ public static void copy(byte[] buf, short from, short to) { } public static byte compare(byte[] buf, short lhs, short rhs) { - return Util.arrayCompare(buf, lhs, buf, rhs, (short) 8); + return unsignedByteArrayCompare(buf, lhs, buf, rhs, (short) 8); } public static void shiftLeft(byte[] buf, short start) { @@ -319,4 +404,25 @@ public static short countTemporalCount(byte[] bufTime, short timeOff, return divide(scratchPad, (short) 0, (short) 8, (short) 16); } -} + public static boolean isLeapYear(short year) { + if ((short)(year%4) == (short) 0) { + if (((short)(year % 100) == (short) 0) && + ((short) (year % 400)) != (short) 0) { + return false; + } + return true; + } + return false; + } + + public static short getLeapYrIndex(boolean from2020, short yrsCount) { + short newBaseYr = (short) (from2020 ? (year2020 + yrsCount) : (year2051 + yrsCount)); + for(short i = 0; i < 4; i++) { + if(isLeapYear((short)(newBaseYr + i))) { + return i; + } + } + return -1; + } + +} \ No newline at end of file diff --git a/Applet/src/com/android/javacard/keymaster/KMInteger.java b/Applet/src/com/android/javacard/keymaster/KMInteger.java index 090f6e86..18944e4d 100644 --- a/Applet/src/com/android/javacard/keymaster/KMInteger.java +++ b/Applet/src/com/android/javacard/keymaster/KMInteger.java @@ -162,7 +162,7 @@ public static short compare(short num1, short num2){ KMInteger.cast(num1).getValue(repository.getHeap(),(short)(num1Buf+(short)(8-len)),len); len = KMInteger.cast(num2).length(); KMInteger.cast(num2).getValue(repository.getHeap(),(short)(num2Buf+(short)(8-len)),len); - return Util.arrayCompare( + return KMUtils.unsignedByteArrayCompare( repository.getHeap(), num1Buf, repository.getHeap(), num2Buf, (short)8); diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index a85a7243..adedf6f5 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -3611,7 +3611,7 @@ private void checkVersionAndPatchLevel(byte[] scratchPad) { if (tmpVariables[0] != KMType.INVALID_VALUE) { tmpVariables[1] = repository.getOsVersion(); tmpVariables[1] = - Util.arrayCompare( + KMUtils.unsignedByteArrayCompare( KMInteger.cast(tmpVariables[1]).getBuffer(), KMInteger.cast(tmpVariables[1]).getStartOff(), scratchPad, @@ -3644,7 +3644,7 @@ private void checkVersionAndPatchLevel(byte[] scratchPad) { if (tmpVariables[0] != KMType.INVALID_VALUE) { tmpVariables[1] = repository.getOsPatch(); tmpVariables[1] = - Util.arrayCompare( + KMUtils.unsignedByteArrayCompare( KMInteger.cast(tmpVariables[1]).getBuffer(), KMInteger.cast(tmpVariables[1]).getStartOff(), scratchPad, From 5d3413efcb15c149cf18e75a76b6101934d275c6 Mon Sep 17 00:00:00 2001 From: BKSSMVenkateswarlu <40534495+BKSSMVenkateswarlu@users.noreply.github.com> Date: Tue, 2 Feb 2021 19:35:03 +0530 Subject: [PATCH 80/99] Update README.md --- provisioning_tool/README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/provisioning_tool/README.md b/provisioning_tool/README.md index feb804cb..b2960204 100644 --- a/provisioning_tool/README.md +++ b/provisioning_tool/README.md @@ -1 +1,9 @@ -jlkjs +# Provisioning tool +This directory contains provisioning tool which helps in provisioning +the secure element by using the APIs exposed by Provision library. +This tool takes the input parameters from json file. A sample +json file is located in this directory with name sample_json.txt for +your reference. + +#### Build +This tool has dependency on [libjc_common](https://github.com/BKSSMVenkateswarlu/JavaCardKeymaster/blob/master/HAL/keymaster/Android.bp) From 4fed4281663622627a9b7a835cf55eb03adf5db2 Mon Sep 17 00:00:00 2001 From: BKSSMVenkateswarlu <40534495+BKSSMVenkateswarlu@users.noreply.github.com> Date: Tue, 2 Feb 2021 19:39:44 +0530 Subject: [PATCH 81/99] Update README.md --- provisioning_tool/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/provisioning_tool/README.md b/provisioning_tool/README.md index b2960204..295dba93 100644 --- a/provisioning_tool/README.md +++ b/provisioning_tool/README.md @@ -6,4 +6,6 @@ json file is located in this directory with name sample_json.txt for your reference. #### Build -This tool has dependency on [libjc_common](https://github.com/BKSSMVenkateswarlu/JavaCardKeymaster/blob/master/HAL/keymaster/Android.bp) +This tool can be built along with aosp build. It has dependency on +[libjc_common](https://github.com/BKSSMVenkateswarlu/JavaCardKeymaster/blob/master/HAL/keymaster/Android.bp) and +libjc_provision. From f8ae39f913b013fc8d6a746b993889209ff166fc Mon Sep 17 00:00:00 2001 From: BKSSMVenkateswarlu <40534495+BKSSMVenkateswarlu@users.noreply.github.com> Date: Tue, 2 Feb 2021 19:49:13 +0530 Subject: [PATCH 82/99] Update README.md --- provisioning_tool/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/provisioning_tool/README.md b/provisioning_tool/README.md index 295dba93..2b9d5a23 100644 --- a/provisioning_tool/README.md +++ b/provisioning_tool/README.md @@ -9,3 +9,17 @@ your reference. This tool can be built along with aosp build. It has dependency on [libjc_common](https://github.com/BKSSMVenkateswarlu/JavaCardKeymaster/blob/master/HAL/keymaster/Android.bp) and libjc_provision. + +#### Usage +Usage: provision_tool *options* +Valid options are: +-h, --help show the help message and exit. +-a, --all jsonFile Executes all the provision commands. +-k, --attest_key jsonFile Provision attestation key. +-c, --cert_chain jsonFile Provision attestation certificate chain. +-p, --cert_params jsonFile Provision attestation certificate parameters. +-i, --attest_ids jsonFile Provision attestation IDs. +-r, --shared_secret jsonFile Provision pre-shared secret. +-b, --set_boot_params jsonFile Provision boot parameters. +-s, --provision_stautus Prints the current provision status. +-l, --lock_provision Locks the provision commands. From be8e975835970c5d4aa7d78bb7e13df9f86ec713 Mon Sep 17 00:00:00 2001 From: BKSSMVenkateswarlu <40534495+BKSSMVenkateswarlu@users.noreply.github.com> Date: Tue, 2 Feb 2021 19:52:15 +0530 Subject: [PATCH 83/99] Update README.md --- provisioning_tool/README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/provisioning_tool/README.md b/provisioning_tool/README.md index 2b9d5a23..1d69731a 100644 --- a/provisioning_tool/README.md +++ b/provisioning_tool/README.md @@ -11,15 +11,15 @@ This tool can be built along with aosp build. It has dependency on libjc_provision. #### Usage -Usage: provision_tool *options* -Valid options are: --h, --help show the help message and exit. --a, --all jsonFile Executes all the provision commands. --k, --attest_key jsonFile Provision attestation key. --c, --cert_chain jsonFile Provision attestation certificate chain. --p, --cert_params jsonFile Provision attestation certificate parameters. --i, --attest_ids jsonFile Provision attestation IDs. --r, --shared_secret jsonFile Provision pre-shared secret. --b, --set_boot_params jsonFile Provision boot parameters. --s, --provision_stautus Prints the current provision status. +Usage: provision_tool *options*\ +Valid options are:\ +-h, --help show the help message and exit.\ +-a, --all jsonFile Executes all the provision commands.\ +-k, --attest_key jsonFile Provision attestation key.\ +-c, --cert_chain jsonFile Provision attestation certificate chain.\ +-p, --cert_params jsonFile Provision attestation certificate parameters.\ +-i, --attest_ids jsonFile Provision attestation IDs.\ +-r, --shared_secret jsonFile Provision pre-shared secret.\ +-b, --set_boot_params jsonFile Provision boot parameters.\ +-s, --provision_stautus Prints the current provision status.\ -l, --lock_provision Locks the provision commands. From 7899e3b3925f684d34ee502da32bf665920a3d39 Mon Sep 17 00:00:00 2001 From: BKSSMVenkateswarlu <40534495+BKSSMVenkateswarlu@users.noreply.github.com> Date: Tue, 2 Feb 2021 19:55:33 +0530 Subject: [PATCH 84/99] Update README.md --- provisioning_tool/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/provisioning_tool/README.md b/provisioning_tool/README.md index 1d69731a..a6a15908 100644 --- a/provisioning_tool/README.md +++ b/provisioning_tool/README.md @@ -11,6 +11,7 @@ This tool can be built along with aosp build. It has dependency on libjc_provision. #### Usage +
 Usage: provision_tool *options*\
 Valid options are:\
 -h, --help                        show the help message and exit.\
@@ -23,3 +24,4 @@ Valid options are:\
 -b, --set_boot_params jsonFile    Provision boot parameters.\
 -s, --provision_stautus           Prints the current provision status.\
 -l, --lock_provision              Locks the provision commands.
+
From 91cc7fbb271d9934a520415a7ec888804c4fd661 Mon Sep 17 00:00:00 2001 From: BKSSMVenkateswarlu <40534495+BKSSMVenkateswarlu@users.noreply.github.com> Date: Tue, 2 Feb 2021 19:56:15 +0530 Subject: [PATCH 85/99] Update README.md --- provisioning_tool/README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/provisioning_tool/README.md b/provisioning_tool/README.md index a6a15908..b2954495 100644 --- a/provisioning_tool/README.md +++ b/provisioning_tool/README.md @@ -12,16 +12,16 @@ libjc_provision. #### Usage
-Usage: provision_tool *options*\
-Valid options are:\
--h, --help                        show the help message and exit.\
--a, --all jsonFile                Executes all the provision commands.\
--k, --attest_key jsonFile         Provision attestation key.\
--c, --cert_chain jsonFile         Provision attestation certificate chain.\
--p, --cert_params jsonFile        Provision attestation certificate parameters.\
--i, --attest_ids jsonFile         Provision attestation IDs.\
--r, --shared_secret jsonFile      Provision pre-shared secret.\
--b, --set_boot_params jsonFile    Provision boot parameters.\
--s, --provision_stautus           Prints the current provision status.\
+Usage: provision_tool options
+Valid options are:
+-h, --help                        show the help message and exit.
+-a, --all jsonFile                Executes all the provision commands.
+-k, --attest_key jsonFile         Provision attestation key.
+-c, --cert_chain jsonFile         Provision attestation certificate chain.
+-p, --cert_params jsonFile        Provision attestation certificate parameters.
+-i, --attest_ids jsonFile         Provision attestation IDs.
+-r, --shared_secret jsonFile      Provision pre-shared secret.
+-b, --set_boot_params jsonFile    Provision boot parameters.
+-s, --provision_stautus           Prints the current provision status.
 -l, --lock_provision              Locks the provision commands.
 
From 8d32e8061f1c4fec35f7c29dab9b8610dc151b5c Mon Sep 17 00:00:00 2001 From: BKSSMVenkateswarlu <40534495+BKSSMVenkateswarlu@users.noreply.github.com> Date: Tue, 2 Feb 2021 19:57:23 +0530 Subject: [PATCH 86/99] Update README.md --- provisioning_tool/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/provisioning_tool/README.md b/provisioning_tool/README.md index b2954495..9f0dfbb4 100644 --- a/provisioning_tool/README.md +++ b/provisioning_tool/README.md @@ -2,7 +2,7 @@ This directory contains provisioning tool which helps in provisioning the secure element by using the APIs exposed by Provision library. This tool takes the input parameters from json file. A sample -json file is located in this directory with name sample_json.txt for +json file is located in this directory with name [sample_json.txt](https://github.com/BKSSMVenkateswarlu/JavaCardKeymaster/blob/master/provisioning_tool/sample_json.txt) for your reference. #### Build From 66d366aabba4f07583be5ce393546acf195cc40c Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Wed, 3 Feb 2021 10:34:29 +0530 Subject: [PATCH 87/99] Corrected the tag EARLY_BOOT_ENDED to EARLY_BOOT_ONLY --- Applet/src/com/android/javacard/keymaster/KMBoolTag.java | 2 +- .../src/com/android/javacard/keymaster/KMKeymasterApplet.java | 2 +- Applet/src/com/android/javacard/keymaster/KMType.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Applet/src/com/android/javacard/keymaster/KMBoolTag.java b/Applet/src/com/android/javacard/keymaster/KMBoolTag.java index d3b916e9..4396470b 100644 --- a/Applet/src/com/android/javacard/keymaster/KMBoolTag.java +++ b/Applet/src/com/android/javacard/keymaster/KMBoolTag.java @@ -42,7 +42,7 @@ public class KMBoolTag extends KMTag { TRUSTED_CONFIRMATION_REQUIRED, UNLOCKED_DEVICE_REQUIRED, RESET_SINCE_ID_ROTATION, - EARLY_BOOT_ENDED, + EARLY_BOOT_ONLY, DEVICE_UNIQUE_ATTESTATION }; diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index adedf6f5..1b156d53 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -3315,7 +3315,7 @@ private static void processGenerateKey(APDU apdu) { data[KEY_PARAMETERS] = KMArray.cast(tmpVariables[2]).get((short) 0); // Check if EarlyBootEnded tag is present. tmpVariables[0] = - KMKeyParameters.findTag(KMType.BOOL_TAG, KMType.EARLY_BOOT_ENDED, data[KEY_PARAMETERS]); + KMKeyParameters.findTag(KMType.BOOL_TAG, KMType.EARLY_BOOT_ONLY, data[KEY_PARAMETERS]); if (tmpVariables[0] != KMType.INVALID_VALUE) { KMException.throwIt(KMError.EARLY_BOOT_ENDED); } diff --git a/Applet/src/com/android/javacard/keymaster/KMType.java b/Applet/src/com/android/javacard/keymaster/KMType.java index bf6b12e5..4d81de45 100644 --- a/Applet/src/com/android/javacard/keymaster/KMType.java +++ b/Applet/src/com/android/javacard/keymaster/KMType.java @@ -231,7 +231,7 @@ public abstract class KMType { // Reset Since Id Rotation public static final short RESET_SINCE_ID_ROTATION = (short) 0x03EC; //Early boot ended. - public static final short EARLY_BOOT_ENDED = (short) 0x0131; + public static final short EARLY_BOOT_ONLY = (short) 0x0131; //Device unique attestation. public static final short DEVICE_UNIQUE_ATTESTATION = (short) 0x02D0; From 6ab06673d808041dd8c164f2fcc10db505a4e6bb Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Fri, 5 Feb 2021 18:32:45 +0530 Subject: [PATCH 88/99] store secrets as keyobjects instead as byte arrays. --- .../android/javacard/keymaster/KMAESKey.java | 46 +++++ .../keymaster/KMAndroidSEProvider.java | 181 +++++++++++++++--- .../keymaster/KMAttestationCertImpl.java | 32 ++-- .../javacard/keymaster/KMECPrivateKey.java | 68 +++++++ .../android/javacard/keymaster/KMHmacKey.java | 59 ++++++ .../javacard/keymaster/KMRsaOAEPEncoding.java | 2 - .../android/javacard/keymaster/KMAESKey.java | 58 ++++++ .../keymaster/KMAttestationCertImpl.java | 26 +-- .../javacard/keymaster/KMECPrivateKey.java | 38 ++++ .../android/javacard/keymaster/KMHmacKey.java | 38 ++++ .../javacard/keymaster/KMJCardSimulator.java | 117 +++++++++-- .../javacard/keymaster/KMAttestationCert.java | 14 +- .../javacard/keymaster/KMAttestationKey.java | 28 +++ .../javacard/keymaster/KMKeymasterApplet.java | 31 ++- .../javacard/keymaster/KMMasterKey.java | 28 +++ .../javacard/keymaster/KMPreSharedKey.java | 28 +++ .../javacard/keymaster/KMRepository.java | 62 ++---- .../javacard/keymaster/KMSEProvider.java | 114 +++++++++-- 18 files changed, 809 insertions(+), 161 deletions(-) create mode 100644 Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAESKey.java create mode 100644 Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMECPrivateKey.java create mode 100644 Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMHmacKey.java create mode 100644 Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAESKey.java create mode 100644 Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMECPrivateKey.java create mode 100644 Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMHmacKey.java create mode 100644 Applet/src/com/android/javacard/keymaster/KMAttestationKey.java create mode 100644 Applet/src/com/android/javacard/keymaster/KMMasterKey.java create mode 100644 Applet/src/com/android/javacard/keymaster/KMPreSharedKey.java diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAESKey.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAESKey.java new file mode 100644 index 00000000..95896b13 --- /dev/null +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAESKey.java @@ -0,0 +1,46 @@ +package com.android.javacard.keymaster; + +import org.globalplatform.upgrade.Element; + +import com.android.javacard.keymaster.KMMasterKey; + +import javacard.security.AESKey; + +public class KMAESKey implements KMMasterKey { + private AESKey aesKey; + + public KMAESKey(AESKey key) { + aesKey = key; + } + + public void setKey(byte[] keyData, short kOff) { + aesKey.setKey(keyData, kOff); + } + + public AESKey getKey() { + return aesKey; + } + + public short getKeySizeBits() { + return aesKey.getSize(); + } + + public static void onSave(Element element, KMAESKey kmKey) { + element.write(kmKey.aesKey); + } + + public static KMAESKey onRestore(Element element) { + AESKey aesKey = (AESKey) element.readObject(); + KMAESKey kmKey = new KMAESKey(aesKey); + return kmKey; + } + + public static short getBackupPrimitiveByteCount() { + return (short) 0; + } + + public static short getBackupObjectCount() { + return (short) 1; + } + +} diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java index 20417d0f..d182ca02 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java @@ -37,6 +37,13 @@ import javacardx.crypto.AEADCipher; import javacardx.crypto.Cipher; +import com.android.javacard.keymaster.KMAESKey; +import com.android.javacard.keymaster.KMAttestationKey; +import com.android.javacard.keymaster.KMECPrivateKey; +import com.android.javacard.keymaster.KMHmacKey; +import com.android.javacard.keymaster.KMMasterKey; +import com.android.javacard.keymaster.KMPreSharedKey; + public class KMAndroidSEProvider implements KMSEProvider { // static final variables // -------------------------------------------------------------- @@ -158,6 +165,9 @@ public class KMAndroidSEProvider implements KMSEProvider { private RandomData rng; //For storing root certificate and intermediate certificates. private byte[] certificateChain; + private KMAESKey masterKey; + private KMECPrivateKey attestationKey; + private KMHmacKey preSharedKey; private static KMAndroidSEProvider androidSEProvider = null; @@ -177,7 +187,8 @@ public KMAndroidSEProvider() { hmacKey = (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC, (short) 512, false); rsaKeyPair = new KeyPair(KeyPair.ALG_RSA, KeyBuilder.LENGTH_RSA_2048); - initECKey(); + ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256); + initECKey(ecKeyPair); // Re-usable cipher and signature instances cipherPool = new Object[(short) (CIPHER_ALGS.length * 4)]; @@ -210,8 +221,7 @@ public void clean() { Util.arrayFillNonAtomic(tmpArray, (short) 0, (short) 256, (byte) 0); } - private void initECKey() { - ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256); + private void initECKey(KeyPair ecKeyPair) { ECPrivateKey privKey = (ECPrivateKey) ecKeyPair.getPrivate(); ECPublicKey pubkey = (ECPublicKey) ecKeyPair.getPublic(); pubkey.setFieldFP(secp256r1_P, (short) 0, (short) secp256r1_P.length); @@ -600,13 +610,11 @@ public void addRngEntropy(byte[] num, short offset, short length) { rng.setSeed(num, offset, length); } - @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) { - + public short aesGCMEncrypt(AESKey key, + 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) { CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } @@ -617,7 +625,6 @@ public short aesGCMEncrypt(byte[] aesKey, short aesKeyStart, short aesKeyLen, aesGcmCipher = (AEADCipher) Cipher.getInstance(AEADCipher.ALG_AES_GCM, false); } - AESKey key = createAESKey(aesKey, aesKeyStart, aesKeyLen); aesGcmCipher.init(key, Cipher.MODE_ENCRYPT, nonce, nonceStart, nonceLen); aesGcmCipher.updateAAD(authData, authDataStart, authDataLen); short ciphLen = aesGcmCipher.doFinal(secret, secretStart, secretLen, @@ -626,6 +633,32 @@ public short aesGCMEncrypt(byte[] aesKey, short aesKeyStart, short aesKeyLen, return ciphLen; } + @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) { + + AESKey key = createAESKey(aesKey, aesKeyStart, aesKeyLen); + return aesGCMEncrypt( + key, + secret, + secretStart, + secretLen, + encSecret, + encSecretStart, + nonce, + nonceStart, + nonceLen, + authData, + authDataStart, + authDataLen, + authTag, + authTagStart, + authTagLen); + } + @Override public boolean aesGCMDecrypt(byte[] aesKey, short aesKeyStart, short aesKeyLen, byte[] encSecret, short encSecretStart, @@ -648,8 +681,7 @@ public boolean aesGCMDecrypt(byte[] aesKey, short aesKeyStart, return verification; } - public HMACKey cmacKdf(byte[] keyMaterial, short keyMaterialStart, - short keyMaterialLen, byte[] label, short labelStart, short labelLen, + public HMACKey cmacKdf(KMPreSharedKey preSharedKey, byte[] label, short labelStart, short labelLen, byte[] context, short contextStart, short contextLength) { try { // This is hardcoded to requirement - 32 byte output with two concatenated @@ -667,10 +699,18 @@ public HMACKey cmacKdf(byte[] keyMaterial, short keyMaterialStart, // [i] counter - 32 bits short iBufLen = 4; short keyOutLen = n * 16; + //Convert Hmackey to AES Key as the algorithm is ALG_AES_CMAC_128. + KMHmacKey hmacKey = ((KMHmacKey) preSharedKey); + hmacKey.getKey(tmpArray, (short) 0); + aesKeys[KEYSIZE_256_OFFSET].setKey(tmpArray, (short) 0); + //Initialize the key derivation function. + kdf.init(aesKeys[KEYSIZE_256_OFFSET], Signature.MODE_SIGN); + //Clear the tmpArray buffer. + Util.arrayFillNonAtomic(tmpArray, (short) 0, (short) 256, (byte) 0); + 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) { @@ -733,17 +773,15 @@ public short rsaDecipherOAEP256(byte[] secret, short secretStart, outputDataBuf, (short) outputDataStart); } - public short ecSign256(byte[] secret, short secretStart, short secretLength, + public short ecSign256(KMAttestationKey attestationKey, byte[] inputDataBuf, short inputDataStart, short inputDataLength, byte[] outputDataBuf, short outputDataStart) { Signature.OneShot signer = null; try { - ECPrivateKey key = (ECPrivateKey) ecKeyPair.getPrivate(); - 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); + signer.init(((KMECPrivateKey)attestationKey).getPrivateKey(), Signature.MODE_SIGN); return signer.sign(inputDataBuf, inputDataStart, inputDataLength, outputDataBuf, outputDataStart); } finally { @@ -975,7 +1013,7 @@ public Cipher createRsaCipher(short padding, short digest, byte[] modBuffer, short modOff, short modLength) { try { byte cipherAlg = mapCipherAlg(KMType.RSA, (byte) padding, (byte) 0, (byte)digest); - // TODO Java Card does not support MGF1-SHA1 and digest as SHA256. + // 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) { @@ -1116,12 +1154,11 @@ public KMAttestationCert getAttestationCert(boolean rsaCert) { } @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); + public short cmacKdf(KMPreSharedKey pSharedKey, byte[] label, + short labelStart, short labelLen, byte[] context, short contextStart, + short contextLength, byte[] keyBuf, short keyStart) { + HMACKey key = cmacKdf(pSharedKey, label, labelStart, labelLen, context, + contextStart, contextLength); return key.getKey(keyBuf, keyStart); } @@ -1187,25 +1224,113 @@ public void clearDeviceBooted(boolean resetBootFlag) { @Override public void onSave(Element element) { element.write(certificateChain); + KMAESKey.onSave(element, masterKey); + KMECPrivateKey.onSave(element, attestationKey); + KMHmacKey.onSave(element, preSharedKey); } @Override public void onRestore(Element element) { certificateChain = (byte[]) element.readObject(); + masterKey = KMAESKey.onRestore(element); + attestationKey = KMECPrivateKey.onRestore(element); + preSharedKey = KMHmacKey.onRestore(element); } @Override public short getBackupPrimitiveByteCount() { - return (short) 0; + short count = + (short) (KMAESKey.getBackupPrimitiveByteCount() + + KMECPrivateKey.getBackupPrimitiveByteCount() + + KMHmacKey.getBackupPrimitiveByteCount()); + return count; } @Override public short getBackupObjectCount() { - return (short) 1; + short count = + (short) (1 /*Certificate chain */ + + KMAESKey.getBackupObjectCount() + + KMECPrivateKey.getBackupObjectCount() + + KMHmacKey.getBackupObjectCount()); + return count; } @Override public boolean isUpgrading() { return UpgradeManager.isUpgrading(); } + + @Override + public KMMasterKey createMasterKey(short keySizeBits) { + try { + if (masterKey == null) { + AESKey key = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, + keySizeBits, false); + masterKey = new KMAESKey(key); + short keyLen = (short) (keySizeBits / 8); + getTrueRandomNumber(tmpArray, (short) 0, keyLen); + masterKey.setKey(tmpArray, (short) 0); + } + return (KMMasterKey) masterKey; + } finally { + clean(); + } + } + + @Override + public KMAttestationKey createAttestationKey(byte[] keyData, short offset, + short length) { + if (attestationKey == null) { + // Strongbox supports only P-256 curve for EC key. + KeyPair ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256); + initECKey(ecKeyPair); + attestationKey = new KMECPrivateKey(ecKeyPair); + } + attestationKey.setS(keyData, offset, length); + return (KMAttestationKey) attestationKey; + } + + @Override + public KMPreSharedKey createPresharedKey(byte[] keyData, short offset, short length) { + short lengthInBits = (short)(length * 8); + if ((lengthInBits % 8 != 0) || !(lengthInBits >= 64 && lengthInBits <= 512)) { + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } + if (preSharedKey == null) { + HMACKey key = (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC, lengthInBits, + false); + preSharedKey = new KMHmacKey(key); + } + preSharedKey.setKey(keyData, offset, length); + return (KMPreSharedKey) preSharedKey; + } + + @Override + public KMMasterKey getMasterKey() { + return (KMMasterKey) masterKey; + } + + @Override + public KMAttestationKey getAttestationKey() { + return (KMAttestationKey) attestationKey; + } + + @Override + public KMPreSharedKey getPresharedKey() { + return (KMPreSharedKey) preSharedKey; + } + + @Override + public short aesGCMEncrypt(KMMasterKey key, 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) { + + return aesGCMEncrypt(((KMAESKey) key).getKey(), secret, secretStart, + secretLen, encSecret, encSecretStart, nonce, nonceStart, nonceLen, + authData, authDataStart, authDataLen, authTag, authTagStart, + authTagLen); + } } diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java index 5a36e3c3..bf6ae9b7 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -1,7 +1,13 @@ package com.android.javacard.keymaster; +import com.android.javacard.keymaster.KMAESKey; +import com.android.javacard.keymaster.KMByteBlob; +import com.android.javacard.keymaster.KMECPrivateKey; +import com.android.javacard.keymaster.KMMasterKey; + import javacard.framework.JCSystem; import javacard.framework.Util; +import javacard.security.AESKey; // 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. @@ -774,12 +780,6 @@ public KMAttestationCert buffer(byte[] buf, short bufStart, short maxLen) { return this; } - @Override - public KMAttestationCert signingKey(short privKey) { - signPriv = privKey; - return this; - } - @Override public short getCertStart() { return certStart; @@ -808,11 +808,10 @@ public void build() { tbsLength = (short) (tbsLength - tbsOffset); pushSequenceHeader((short) (last - stackPtr)); certStart = stackPtr; - short sigLen = KMAndroidSEProvider.getInstance() + KMAndroidSEProvider androidSeProvider = KMAndroidSEProvider.getInstance(); + short sigLen = androidSeProvider .ecSign256( - KMByteBlob.cast(signPriv).getBuffer(), - KMByteBlob.cast(signPriv).getStartOff(), - KMByteBlob.cast(signPriv).length(), + androidSeProvider.getAttestationKey(), stack, tbsOffset, tbsLength, @@ -833,7 +832,7 @@ public void build() { 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) { + byte resetSinceIdRotation, KMMasterKey masterKey) { // Concatenate T||C||R // temporal count T short temp = KMUtils.countTemporalCount(creationTime, timeOffset, @@ -852,7 +851,16 @@ public KMAttestationCert makeUniqueId(byte[] scratchPad, short scratchPadOff, scratchPadOff++; timeOffset = KMByteBlob.instance((short) 32); - appIdOff = KMAndroidSEProvider.getInstance().hmacSign(key, keyOff, keyLen, + //Get the key data from the master key and use it for HMAC Sign. + AESKey aesKey = ((KMAESKey) masterKey).getKey(); + short mKeyData = KMByteBlob.instance((short) (aesKey.getSize() / 8)); + aesKey.getKey( + KMByteBlob.cast(mKeyData).getBuffer(), + KMByteBlob.cast(mKeyData).getStartOff()); + appIdOff = KMAndroidSEProvider.getInstance().hmacSign( + KMByteBlob.cast(mKeyData).getBuffer(), /* Key */ + KMByteBlob.cast(mKeyData).getStartOff(), /* Key start*/ + KMByteBlob.cast(mKeyData).length(), /* Key length*/ scratchPad, /* data */ temp, /* data start */ scratchPadOff, /* data length */ diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMECPrivateKey.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMECPrivateKey.java new file mode 100644 index 00000000..fe6a636f --- /dev/null +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMECPrivateKey.java @@ -0,0 +1,68 @@ +/* + * 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 org.globalplatform.upgrade.Element; + +import com.android.javacard.keymaster.KMAESKey; +import com.android.javacard.keymaster.KMAttestationCert; +import com.android.javacard.keymaster.KMAttestationKey; + +import javacard.security.AESKey; +import javacard.security.ECPrivateKey; +import javacard.security.KeyPair; + +public class KMECPrivateKey implements KMAttestationKey { + + private KeyPair ecKeyPair; + + public KMECPrivateKey(KeyPair ecPair) { + ecKeyPair = ecPair; + } + + public void setS(byte[] buffer, short offset, short length) { + ECPrivateKey ecPriv = (ECPrivateKey) ecKeyPair.getPrivate(); + ecPriv.setS(buffer, offset, length); + } + + public short getS(byte[] buffer, short offset) { + ECPrivateKey ecPriv = (ECPrivateKey) ecKeyPair.getPrivate(); + return ecPriv.getS(buffer, offset); + } + + public ECPrivateKey getPrivateKey() { + return (ECPrivateKey) ecKeyPair.getPrivate(); + } + + public static void onSave(Element element, KMECPrivateKey kmKey) { + element.write(kmKey.ecKeyPair); + } + + public static KMECPrivateKey onRestore(Element element) { + KeyPair ecKey = (KeyPair) element.readObject(); + KMECPrivateKey kmKey = new KMECPrivateKey(ecKey); + return kmKey; + } + + public static short getBackupPrimitiveByteCount() { + return (short) 0; + } + + public static short getBackupObjectCount() { + return (short) 1; + } + +} diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMHmacKey.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMHmacKey.java new file mode 100644 index 00000000..b4ca3af4 --- /dev/null +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMHmacKey.java @@ -0,0 +1,59 @@ +/* + * 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 org.globalplatform.upgrade.Element; + +import com.android.javacard.keymaster.KMPreSharedKey; + +import javacard.security.HMACKey; + +public class KMHmacKey implements KMPreSharedKey { + private HMACKey hmacKey; + + public KMHmacKey(HMACKey key) { + hmacKey = key; + } + + public void setKey(byte[] keyData, short kOff, short length) { + hmacKey.setKey(keyData, kOff, length); + } + + public byte getKey(byte[] keyData, short kOff) { + return hmacKey.getKey(keyData, kOff); + } + + public short getKeySizeBits() { + return hmacKey.getSize(); + } + public static void onSave(Element element, KMHmacKey kmKey) { + element.write(kmKey.hmacKey); + } + + public static KMHmacKey onRestore(Element element) { + HMACKey hmacKey = (HMACKey) element.readObject(); + KMHmacKey kmKey = new KMHmacKey(hmacKey); + return kmKey; + } + + public static short getBackupPrimitiveByteCount() { + return (short) 0; + } + + public static short getBackupObjectCount() { + return (short) 1; + } +} diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsaOAEPEncoding.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsaOAEPEncoding.java index d4f4cb83..b8c7b30e 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsaOAEPEncoding.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsaOAEPEncoding.java @@ -80,13 +80,11 @@ public byte getAlgorithm() { @Override public byte getCipherAlgorithm() { - // TODO return 0; } @Override public byte getPaddingAlgorithm() { - // TODO return 0; } diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAESKey.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAESKey.java new file mode 100644 index 00000000..c16a8188 --- /dev/null +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAESKey.java @@ -0,0 +1,58 @@ +/* + * 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 org.globalplatform.upgrade.Element; + +import javacard.security.AESKey; + +public class KMAESKey implements KMMasterKey { + private AESKey aesKey; + + public KMAESKey(AESKey key) { + aesKey = key; + } + + public void setKey(byte[] keyData, short kOff) { + aesKey.setKey(keyData, kOff); + } + + public byte getKey(byte[] keyData, short kOff) { + return aesKey.getKey(keyData, kOff); + } + + public short getKeySizeBits() { + return aesKey.getSize(); + } + + public static void onSave(Element element, KMAESKey kmKey) { + element.write(kmKey.aesKey); + } + + public static KMAESKey onRestore(Element element) { + AESKey aesKey = (AESKey) element.readObject(); + KMAESKey kmKey = new KMAESKey(aesKey); + return kmKey; + } + + public static short getBackupPrimitiveByteCount() { + return (short) 0; + } + + public static short getBackupObjectCount() { + return (short) 1; + } +} diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java index cd9567d3..b89b50ca 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -774,12 +774,6 @@ public KMAttestationCert buffer(byte[] buf, short bufStart, short maxLen) { return this; } - @Override - public KMAttestationCert signingKey(short privKey) { - signPriv = privKey; - return this; - } - @Override public short getCertStart() { return certStart; @@ -808,11 +802,10 @@ public void build() { tbsLength = (short) (tbsLength - tbsOffset); pushSequenceHeader((short) (last - stackPtr)); certStart = stackPtr; - short sigLen = KMJCardSimulator.getInstance() + KMJCardSimulator provider = KMJCardSimulator.getInstance(); + short sigLen = provider .ecSign256( - KMByteBlob.cast(signPriv).getBuffer(), - KMByteBlob.cast(signPriv).getStartOff(), - KMByteBlob.cast(signPriv).length(), + provider.getAttestationKey(), stack, tbsOffset, tbsLength, @@ -833,7 +826,7 @@ public void build() { 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) { + byte resetSinceIdRotation, KMMasterKey masterKey) { // Concatenate T||C||R // temporal count T short temp = KMUtils.countTemporalCount(creationTime, timeOffset, @@ -851,8 +844,17 @@ public KMAttestationCert makeUniqueId(byte[] scratchPad, short scratchPadOff, scratchPad[scratchPadOff] = resetSinceIdRotation; scratchPadOff++; + //Get the key data from the master key + KMAESKey aesKey = (KMAESKey) masterKey; + short mKeyData = KMByteBlob.instance((short) (aesKey.getKeySizeBits() / 8)); + aesKey.getKey( + KMByteBlob.cast(mKeyData).getBuffer(), /* Key */ + KMByteBlob.cast(mKeyData).getStartOff()); /* Key start*/ timeOffset = KMByteBlob.instance((short) 32); - appIdOff = KMJCardSimulator.getInstance().hmacSign(key, keyOff, keyLen, + appIdOff = KMJCardSimulator.getInstance().hmacSign( + KMByteBlob.cast(mKeyData).getBuffer(), /* Key */ + KMByteBlob.cast(mKeyData).getStartOff(), /* Key start*/ + KMByteBlob.cast(mKeyData).length(), /* Key length*/ scratchPad, /* data */ temp, /* data start */ scratchPadOff, /* data length */ diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMECPrivateKey.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMECPrivateKey.java new file mode 100644 index 00000000..65c069d1 --- /dev/null +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMECPrivateKey.java @@ -0,0 +1,38 @@ +/* + * 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 javacard.security.ECPrivateKey; +import javacard.security.KeyPair; + +public class KMECPrivateKey implements KMAttestationKey { + + private KeyPair ecKeyPair; + + public KMECPrivateKey(KeyPair ecPair) { + ecKeyPair = ecPair; + } + + public void setS(byte[] buffer, short offset, short length) { + ECPrivateKey ecPriv = (ECPrivateKey) ecKeyPair.getPrivate(); + ecPriv.setS(buffer, offset, length); + } + + public ECPrivateKey getPrivateKey() { + return (ECPrivateKey) ecKeyPair.getPrivate(); + } + +} diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMHmacKey.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMHmacKey.java new file mode 100644 index 00000000..8b75827a --- /dev/null +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMHmacKey.java @@ -0,0 +1,38 @@ +/* + * 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 javacard.security.HMACKey; + +public class KMHmacKey implements KMPreSharedKey { + private HMACKey hmacKey; + + public KMHmacKey(HMACKey key) { + hmacKey = key; + } + + public void setKey(byte[] keyData, short kOff, short length) { + hmacKey.setKey(keyData, kOff, length); + } + + public byte getKey(byte[] keyData, short kOff) { + return hmacKey.getKey(keyData, kOff); + } + + public short getKeySizeBits() { + return hmacKey.getSize(); + } +} diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java index 08c3d0ea..2c7001b2 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java @@ -84,6 +84,9 @@ public class KMJCardSimulator implements KMSEProvider { private static byte[] entropyPool; private static byte[] rndNum; private byte[] certificateChain; + private KMAESKey masterKey; + private KMECPrivateKey attestationKey; + private KMHmacKey preSharedKey; private static KMJCardSimulator jCardSimulator = null; @@ -320,6 +323,7 @@ public short aesGCMEncrypt( key.getKey(keyMaterial,(short)0); */ + //print("KeyMaterial Enc", keyMaterial); //print("Authdata Enc", authData, authDataStart, authDataLen); java.security.Key aesKey = new SecretKeySpec(keyBuf,keyStart,keyLen, "AES"); @@ -511,10 +515,16 @@ public HMACKey cmacKdf(byte[] keyMaterial, short keyMaterialStart, short keyMate } @Override - public short cmacKdf(byte[] keyMaterial, short keyMaterialStart, short keyMaterialLen, byte[] label, + public short cmacKdf(KMPreSharedKey pSharedKey, 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); + KMHmacKey key = (KMHmacKey) pSharedKey; + short keyMaterialLen = key.getKeySizeBits(); + keyMaterialLen = (short) (keyMaterialLen / 8); + short keyMaterialStart = 0; + byte[] keyMaterial = new byte[keyMaterialLen]; + key.getKey(keyMaterial, keyMaterialStart); + HMACKey hmacKey = cmacKdf(keyMaterial,keyMaterialStart, keyMaterialLen, label, labelStart, labelLen,context,contextStart,contextLength); + return hmacKey.getKey(keyBuf,keyStart); } @@ -1213,13 +1223,11 @@ public short getCertificateChainLength() { } @Override - public short ecSign256(byte[] secret, short secretStart, short secretLength, + public short ecSign256(KMAttestationKey attestationKey, byte[] inputDataBuf, short inputDataStart, short inputDataLength, byte[] outputDataBuf, short outputDataStart) { - ECPrivateKey key = (ECPrivateKey) KeyBuilder.buildKey( - KeyBuilder.TYPE_EC_FP_PRIVATE, KeyBuilder.LENGTH_EC_FP_256, false); - key.setS(secret, secretStart, secretLength); + ECPrivateKey key = ((KMECPrivateKey)attestationKey).getPrivateKey(); Signature signer = Signature .getInstance(Signature.ALG_ECDSA_SHA_256, false); @@ -1272,36 +1280,115 @@ public boolean isDeviceRebooted() { @Override 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; } @Override public boolean isUpgrading() { - // TODO Auto-generated method stub return false; } + + @Override + public KMMasterKey createMasterKey(short keySizeBits) { + if (masterKey == null) { + AESKey key = (AESKey) KeyBuilder.buildKey( + KeyBuilder.TYPE_AES, keySizeBits, false); + masterKey = new KMAESKey(key); + short keyLen = (short) (keySizeBits / 8); + byte[] keyData = new byte[keyLen]; + getTrueRandomNumber(keyData, (short) 0, keyLen); + masterKey.setKey(keyData, (short) 0); + } + return (KMMasterKey) masterKey; + } + + @Override + public KMAttestationKey createAttestationKey(byte[] keyData, short offset, + short length) { + if (attestationKey == null) { + // Strongbox supports only P-256 curve for EC key. + KeyPair ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256); + attestationKey = new KMECPrivateKey(ecKeyPair); + } + attestationKey.setS(keyData, offset, length); + return (KMAttestationKey) attestationKey; + } + + @Override + public KMPreSharedKey createPresharedKey(byte[] keyData, short offset, short length) { + short lengthInBits = (short)(length * 8); + if ((lengthInBits % 8 != 0) || !(lengthInBits >= 64 && lengthInBits <= 512)) { + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } + if (preSharedKey == null) { + HMACKey key = (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC, lengthInBits, + false); + preSharedKey = new KMHmacKey(key); + } + preSharedKey.setKey(keyData, offset, length); + return (KMPreSharedKey) preSharedKey; + } + + @Override + public KMMasterKey getMasterKey() { + return (KMMasterKey) masterKey; + } + + @Override + public KMAttestationKey getAttestationKey() { + return (KMAttestationKey) attestationKey; + } + + @Override + public KMPreSharedKey getPresharedKey() { + return (KMPreSharedKey) preSharedKey; + } + + @Override + public short aesGCMEncrypt(KMMasterKey masterKey, 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) { + KMAESKey aesKey = (KMAESKey) masterKey; + short keyLen = aesKey.getKeySizeBits(); + keyLen = (short) (keyLen / 8); + byte[] keyBuf = new byte[keyLen]; + aesKey.getKey(keyBuf, (short)0); + return aesGCMEncrypt( + keyBuf, + (short) 0, + keyLen, + secret, + secretStart, + secretLen, + encSecret, + encSecretStart, + nonce, + nonceStart, + nonceLen, + authData, + authDataStart, + authDataLen, + authTag, + authTagStart, + authTagLen); + } } diff --git a/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java b/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java index d27f015a..f3d36663 100644 --- a/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java +++ b/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java @@ -44,15 +44,13 @@ public interface KMAttestationCert { * @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. + * @param instance 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); + KMMasterKey masterKey); /** * Set start time received from creation/activation time tag. Used for certificate's valid period. @@ -130,14 +128,6 @@ KMAttestationCert notAfter(short usageExpiryTimeObj, */ KMAttestationCert buffer(byte[] buf, short bufStart, short maxLen); - /** - * Set signing key to be used to sign the cert. - * - * @param privateKey This is ECPrivateKey with curve P-256. - * @return instance of KMAttestationCert - */ - KMAttestationCert signingKey(short privateKey); - /** * Get the start of the certificate * diff --git a/Applet/src/com/android/javacard/keymaster/KMAttestationKey.java b/Applet/src/com/android/javacard/keymaster/KMAttestationKey.java new file mode 100644 index 00000000..4b6213ee --- /dev/null +++ b/Applet/src/com/android/javacard/keymaster/KMAttestationKey.java @@ -0,0 +1,28 @@ +/* + * 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; + +/** + * KMAttestationKey is a marker interface and the SE Provider has to implement + * this interface. KMAttestationKey is stored as a Javacard KeyPair object instead + * of byte array. When the attestation key is stored as a KeyPair object, + * the Javacard OS internally provides appropriate security measures + * to protect the key. The attestation key is maintained by the + * SEProvider. + */ +public interface KMAttestationKey { + +} diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 1b156d53..4cf028e5 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -190,8 +190,7 @@ protected KMKeymasterApplet(KMSEProvider seImpl) { JCSystem.makeTransientShortArray((short) TMP_VARIABLE_ARRAY_SIZE, JCSystem.CLEAR_ON_RESET); if(!isUpgrading) { keymasterState = KMKeymasterApplet.INIT_STATE; - seProvider.getTrueRandomNumber(buf, (short) 0, KMRepository.MASTER_KEY_SIZE); - repository.initMasterKey(buf, (short)0, KMRepository.MASTER_KEY_SIZE); + seProvider.createMasterKey((short) (KMRepository.MASTER_KEY_SIZE * 8)); } KMType.initialize(); encoder = new KMEncoder(); @@ -752,7 +751,10 @@ private void processProvisionAttestationKey(APDU apdu) { importECKeys(scratchPad); // persist key - repository.persistAttestationKey(data[SECRET]); + seProvider.createAttestationKey( + KMByteBlob.cast(data[SECRET]).getBuffer(), + KMByteBlob.cast(data[SECRET]).getStartOff(), + KMByteBlob.cast(data[SECRET]).length()); } private void processProvisionAttestIdsCmd(APDU apdu) { @@ -795,7 +797,7 @@ private void processProvisionSharedSecretCmd(APDU apdu) { KMException.throwIt(KMError.INVALID_ARGUMENT); } // Persist shared Hmac. - repository.initHmacSharedSecretKey( + seProvider.createPresharedKey( KMByteBlob.cast(tmpVariables[0]).getBuffer(), KMByteBlob.cast(tmpVariables[0]).getStartOff(), KMByteBlob.cast(tmpVariables[0]).length()); @@ -1033,12 +1035,9 @@ private void processComputeSharedHmacCmd(APDU apdu) { } // generate the key and store it in scratch pad - 32 bytes - tmpVariables[8] = repository.getSharedKey(); tmpVariables[6] = seProvider.cmacKdf( - KMByteBlob.cast(tmpVariables[8]).getBuffer(), - KMByteBlob.cast(tmpVariables[8]).getStartOff(), - KMByteBlob.cast(tmpVariables[8]).length(), + seProvider.getPresharedKey(), ckdfLable, (short) 0, (short) ckdfLable.length, @@ -1397,7 +1396,7 @@ private void processAttestKeyCmd(APDU apdu) { // validity period // active time or creation time - byte blob - // TODO current assumption is that if active and creation time are missing from characteristics + // current assumption is that if active and creation time are missing from characteristics // then // then it is an error. tmpVariables[1] = @@ -1425,7 +1424,6 @@ private void processAttestKeyCmd(APDU apdu) { cert.deviceLocked(repository.getDeviceLock()); cert.issuer(repository.getIssuer()); cert.publicKey(data[PUB_KEY]); - cert.signingKey(repository.getAttKey()); cert.verifiedBootHash(repository.getVerifiedBootHash()); cert.verifiedBootKey(repository.getVerifiedBootKey()); @@ -1529,8 +1527,6 @@ private void setUniqueId(KMAttestationCert cert, byte[] scratchPad) { resetAfterRotation = 0x01; } - //master key. - tmpVariables[2] = repository.getMasterKeySecret(); cert.makeUniqueId( scratchPad, (short) 0, @@ -1540,9 +1536,7 @@ private void setUniqueId(KMAttestationCert cert, byte[] scratchPad) { 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()); + seProvider.getMasterKey()); } private void processDestroyAttIdsCmd(APDU apdu) { @@ -3893,7 +3887,7 @@ private static short deriveKey(byte[] scratchPad) { // 1. AesGCM Encryption, with below input parameters. // authData - HIDDEN_PARAMTERS // Key - Master Key - // InputData - AUTH_DATA + // InputData - KeyCharacteristics // IV - NONCE // 2. After encryption it generates two outputs // a. Encrypted output @@ -3903,13 +3897,10 @@ private static short deriveKey(byte[] scratchPad) { // 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(), + seProvider.getMasterKey(), repository.getHeap(), data[AUTH_DATA], data[AUTH_DATA_LENGTH], diff --git a/Applet/src/com/android/javacard/keymaster/KMMasterKey.java b/Applet/src/com/android/javacard/keymaster/KMMasterKey.java new file mode 100644 index 00000000..0b7b1a6a --- /dev/null +++ b/Applet/src/com/android/javacard/keymaster/KMMasterKey.java @@ -0,0 +1,28 @@ +/* + * 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; + +/** + * KMMasterKey is a marker interface and the SE Provider has to implement + * this interface. Masterkey is stored as a Javacard Key object instead + * of byte array. When master key is stored as a Key object, + * the Javacard OS internally provides appropriate security measures + * to protect the key. The master key is maintained by the + * SEProvider. + */ +public interface KMMasterKey { + +} diff --git a/Applet/src/com/android/javacard/keymaster/KMPreSharedKey.java b/Applet/src/com/android/javacard/keymaster/KMPreSharedKey.java new file mode 100644 index 00000000..7d02db4e --- /dev/null +++ b/Applet/src/com/android/javacard/keymaster/KMPreSharedKey.java @@ -0,0 +1,28 @@ +/* + * 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; + +/** + * KMPreSharedKey is a marker interface and the SE Provider has to implement + * this interface. KMPreSharedKey is stored as a Javacard Key object instead + * of byte array. When the shared key is stored as a Key object, + * the Javacard OS internally provides appropriate security measures + * to protect the key. The pre shared key is maintained by the + * SEProvider. + */ +public interface KMPreSharedKey { + +} diff --git a/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/src/com/android/javacard/keymaster/KMRepository.java index 4c30a613..7785c5b6 100644 --- a/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/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 = 24; + public static final short DATA_INDEX_SIZE = 21; public static final short DATA_INDEX_ENTRY_SIZE = 4; public static final short DATA_MEM_SIZE = 2048; public static final short HEAP_SIZE = 10000; @@ -42,10 +42,8 @@ public class KMRepository implements KMUpgradable { private static final short OPERATION_HANDLE_ENTRY_SIZE = OPERATION_HANDLE_SIZE + OPERATION_HANDLE_STATUS_SIZE; // Data table offsets - public static final byte MASTER_KEY = 8; - public static final byte SHARED_KEY = 9; - public static final byte COMPUTED_HMAC_KEY = 10; - public static final byte HMAC_NONCE = 11; + public static final byte COMPUTED_HMAC_KEY = 8; + public static final byte HMAC_NONCE = 9; public static final byte ATT_ID_BRAND = 0; public static final byte ATT_ID_DEVICE = 1; public static final byte ATT_ID_PRODUCT = 2; @@ -54,18 +52,17 @@ public class KMRepository implements KMUpgradable { 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_EC_KEY = 12; - public static final byte CERT_ISSUER = 13; - public static final byte CERT_EXPIRY_TIME = 14; - public static final byte BOOT_OS_VERSION = 15; - public static final byte BOOT_OS_PATCH = 16; - public static final byte VENDOR_PATCH_LEVEL = 17; - public static final byte BOOT_PATCH_LEVEL = 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 CERT_ISSUER = 10; + public static final byte CERT_EXPIRY_TIME = 11; + public static final byte BOOT_OS_VERSION = 12; + public static final byte BOOT_OS_PATCH = 13; + public static final byte VENDOR_PATCH_LEVEL = 14; + public static final byte BOOT_PATCH_LEVEL = 15; + public static final byte BOOT_VERIFIED_BOOT_KEY = 16; + public static final byte BOOT_VERIFIED_BOOT_HASH = 17; + public static final byte BOOT_VERIFIED_BOOT_STATE = 18; + public static final byte BOOT_DEVICE_LOCKED_STATUS = 19; + public static final byte BOOT_DEVICE_LOCKED_TIME = 20; // Data Item sizes public static final short MASTER_KEY_SIZE = 16; @@ -249,16 +246,6 @@ public void releaseOperation(KMOperationState op) { } } - public void initMasterKey(byte[] key, short start, short len) { - if(len != MASTER_KEY_SIZE) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); - writeDataEntry(MASTER_KEY,key, start, len); - } - - public void initHmacSharedSecretKey(byte[] key, short start, short len) { - if(len != SHARED_SECRET_KEY_SIZE) KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - writeDataEntry(SHARED_KEY,key,start,len); - } - public void initComputedHmac(byte[] key, short start, short len) { if(len != COMPUTED_HMAC_KEY_SIZE) KMException.throwIt(KMError.INVALID_INPUT_LENGTH); writeDataEntry(COMPUTED_HMAC_KEY,key,start,len); @@ -296,14 +283,9 @@ public void onSelect() { // If write through caching is implemented then this method will restore the data into cache } - 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); @@ -376,7 +358,6 @@ 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); } JCSystem.commitTransaction(); } @@ -422,10 +403,6 @@ public byte[] getHeap() { return heap; } - public short getSharedKey() { - return readData(SHARED_KEY); - } - public short getHmacNonce() { return readData(HMAC_NONCE); } @@ -434,17 +411,6 @@ public short getComputedHmacKey() { return readData(COMPUTED_HMAC_KEY); } - public void persistAttestationKey(short secret) { - writeDataEntry(ATT_EC_KEY, - KMByteBlob.cast(secret).getBuffer(), - KMByteBlob.cast(secret).getStartOff(), - KMByteBlob.cast(secret).length()); - } - - public short getAttKey() { - return readData(ATT_EC_KEY); - } - public void persistAttId(byte id, byte[] buf, short start, short len){ writeDataEntry(id, buf,start,len); } diff --git a/Applet/src/com/android/javacard/keymaster/KMSEProvider.java b/Applet/src/com/android/javacard/keymaster/KMSEProvider.java index 3e981c9a..3b7edcf4 100644 --- a/Applet/src/com/android/javacard/keymaster/KMSEProvider.java +++ b/Applet/src/com/android/javacard/keymaster/KMSEProvider.java @@ -159,6 +159,46 @@ short aesGCMEncrypt( short authTagStart, short authTagLen); + /** + * This function is used to derive a partial secret, which is used to encrypt the keyBlobs. + * This is a oneshot operation that performs encryption operation using AES GCM algorithm. It throws + * CryptoException if algorithm is not supported or if tag length is not equal to 16 or + * nonce length is not equal to 12. + * + * @param aesKey instance of KMMasterKey. + * @param data is the buffer that contains data to encrypt. + * @param dataStart is the start of the data buffer. + * @param dataLen is the length of the data buffer. + * @param encData is the buffer of the output encrypted data. + * @param encDataStart is the start of the encrypted data buffer. + * @param nonce is the buffer of nonce. + * @param nonceStart is the start of the nonce buffer. + * @param nonceLen is the length of the nonce buffer. + * @param authData is the authentication data buffer. + * @param authDataStart is the start of the authentication buffer. + * @param authDataLen is the length of the authentication buffer. + * @param authTag is the buffer to output authentication tag. + * @param authTagStart is the start of the buffer. + * @param authTagLen is the length of the buffer. + * @return length of the encrypted data. + */ + short aesGCMEncrypt( + KMMasterKey aesKey, + byte[] data, + short dataStart, + short dataLen, + byte[] encData, + short encDataStart, + byte[] nonce, + short nonceStart, + short nonceLen, + byte[] authData, + short authDataStart, + short authDataLen, + byte[] authTag, + short authTagStart, + short authTagLen); + /** * This is a oneshot operation that performs decryption operation using AES GCM algorithm. It throws * CryptoException if algorithm is not supported. @@ -205,9 +245,7 @@ boolean aesGCMDecrypt( * This is a oneshot operation that performs key derivation function using cmac kdf (CKDF) as * defined in android keymaster hal definition. * - * @param aesKey is the key to use for ckdf. - * @param aesKeyStart is the start of the aes key buffer. - * @param aesKeyLen is the length of the aes key buffer. + * @param instance of pre-shared key. * @param label is the label to be used for ckdf. * @param labelStart is the start of label. * @param labelLen is the length of the label. @@ -219,9 +257,7 @@ boolean aesGCMDecrypt( * @return length of the derived key buffer in bytes. */ short cmacKdf( - byte[] aesKey, - short aesKeyStart, - short aesKeyLen, + KMPreSharedKey hmacKey, byte[] label, short labelStart, short labelLen, @@ -313,9 +349,7 @@ short rsaDecipherOAEP256( /** * This is a oneshot operation that signs the data using EC private key. * - * @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 instance of KMAttestationKey. * @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. @@ -324,9 +358,7 @@ short rsaDecipherOAEP256( * @return length of the decrypted data. */ short ecSign256( - byte[] secret, - short secretStart, - short secretLength, + KMAttestationKey ecPrivKey, byte[] inputDataBuf, short inputDataStart, short inputDataLength, @@ -472,4 +504,62 @@ KMOperation initAsymmetricOperation( * @return true if upgrading, otherwise false. */ boolean isUpgrading(); + + /** + * This function generates an AES Key of keySizeBits, which is used as + * an master key. This generated key is maintained by the SEProvider. + * This function should be called only once at the time of installation. + * + * @param keySizeBits key size in bits. + * @return An instance of KMMasterKey. + */ + KMMasterKey createMasterKey(short keySizeBits); + + /** + * This function creates an ECKey and initializes the ECPrivateKey with + * the provided input key data. The initialized Key is maintained by the + * SEProvider. This function should be called only while provisioning the + * attestation key. + * + * @param keyData buffer containing the ec private key. + * @param offset start of the buffer. + * @param length length of the buffer. + * @return An instance of KMAttestationKey. + */ + KMAttestationKey createAttestationKey(byte[] keyData, short offset, short length); + + /** + * This function creates an HMACKey and initializes the key with the + * provided input key data. This created key is maintained by the + * SEProvider. This function should be called only while provisioing the + * pre-shared secret. + * + * @param keyData buffer containing the key data. + * @param offset start of the buffer. + * @param length length of the buffer. + * @return An instance of KMPreSharedKey. + */ + KMPreSharedKey createPresharedKey(byte[] keyData, short offset, short length); + + /** + * Returns the master key. + * + * @return Instance of the KMMasterKey + */ + KMMasterKey getMasterKey(); + + /** + * Returns the attestation key. + * + * @return Instance of the KMAttestationKey. + */ + KMAttestationKey getAttestationKey(); + + /** + * Returns the preshared key. + * + * @return Instance of the KMPreSharedKey. + */ + KMPreSharedKey getPresharedKey(); + } From 64e37fad5408f7cd7006133407f8b6c6a2bb775c Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Sat, 6 Feb 2021 20:35:12 +0530 Subject: [PATCH 89/99] Updated the documentation comments --- .../com/android/javacard/keymaster/KMAttestationKey.java | 8 +++----- .../src/com/android/javacard/keymaster/KMMasterKey.java | 6 ++---- .../com/android/javacard/keymaster/KMPreSharedKey.java | 6 ++---- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/Applet/src/com/android/javacard/keymaster/KMAttestationKey.java b/Applet/src/com/android/javacard/keymaster/KMAttestationKey.java index 4b6213ee..8582d2b2 100644 --- a/Applet/src/com/android/javacard/keymaster/KMAttestationKey.java +++ b/Applet/src/com/android/javacard/keymaster/KMAttestationKey.java @@ -17,11 +17,9 @@ /** * KMAttestationKey is a marker interface and the SE Provider has to implement - * this interface. KMAttestationKey is stored as a Javacard KeyPair object instead - * of byte array. When the attestation key is stored as a KeyPair object, - * the Javacard OS internally provides appropriate security measures - * to protect the key. The attestation key is maintained by the - * SEProvider. + * this interface. Internally attestation key is stored as a Javacard EC + * key pair object, which will provide additional security. + * The attestation key is maintained by the SEProvider. */ public interface KMAttestationKey { diff --git a/Applet/src/com/android/javacard/keymaster/KMMasterKey.java b/Applet/src/com/android/javacard/keymaster/KMMasterKey.java index 0b7b1a6a..0ceb6291 100644 --- a/Applet/src/com/android/javacard/keymaster/KMMasterKey.java +++ b/Applet/src/com/android/javacard/keymaster/KMMasterKey.java @@ -17,10 +17,8 @@ /** * KMMasterKey is a marker interface and the SE Provider has to implement - * this interface. Masterkey is stored as a Javacard Key object instead - * of byte array. When master key is stored as a Key object, - * the Javacard OS internally provides appropriate security measures - * to protect the key. The master key is maintained by the + * this interface. Internally Masterkey is stored as a Javacard AES key object, + * which will provide additional security. The master key is maintained by the * SEProvider. */ public interface KMMasterKey { diff --git a/Applet/src/com/android/javacard/keymaster/KMPreSharedKey.java b/Applet/src/com/android/javacard/keymaster/KMPreSharedKey.java index 7d02db4e..71dfcae6 100644 --- a/Applet/src/com/android/javacard/keymaster/KMPreSharedKey.java +++ b/Applet/src/com/android/javacard/keymaster/KMPreSharedKey.java @@ -17,10 +17,8 @@ /** * KMPreSharedKey is a marker interface and the SE Provider has to implement - * this interface. KMPreSharedKey is stored as a Javacard Key object instead - * of byte array. When the shared key is stored as a Key object, - * the Javacard OS internally provides appropriate security measures - * to protect the key. The pre shared key is maintained by the + * this interface. Internally Preshared key is stored as a Javacard HMac key object, + * which will provide additional security. The pre-shared key is maintained by the * SEProvider. */ public interface KMPreSharedKey { From 2699c29d3dd45425fa968cd1a9429b1a6f3ec618 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Sat, 6 Feb 2021 20:44:06 +0530 Subject: [PATCH 90/99] Changed the key derivation alogorithm to hmac sign Root of trust now contains VerifiedBootKey, VerifiedBootKeyHash, bootState, deviceLocked state. --- .../keymaster/KMAndroidSEProvider.java | 28 +-- .../javacard/keymaster/KMJCardSimulator.java | 42 +--- .../javacard/keymaster/KMKeymasterApplet.java | 210 +++--------------- .../javacard/keymaster/KMRepository.java | 70 +++++- .../javacard/keymaster/KMSEProvider.java | 60 ++--- 5 files changed, 131 insertions(+), 279 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java index d182ca02..b04cb362 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java @@ -751,6 +751,21 @@ public short hmacSign(byte[] keyBuf, short keyStart, short keyLength, return hmacSign(key, data, dataStart, dataLength, mac, macStart); } + @Override + public short hmacSign(KMMasterKey masterkey, byte[] data, short dataStart, + short dataLength, byte[] signature, short signatureStart) { + try { + AESKey aesKey = ((KMAESKey) masterkey).getKey(); + aesKey.getKey(tmpArray, (short) 0); + HMACKey key = createHMACKey(tmpArray, (short) 0, + (short) (aesKey.getSize() / 8)); + return hmacSign(key, data, dataStart, dataLength, signature, + signatureStart); + } finally { + clean(); + } + } + @Override public boolean hmacVerify(byte[] keyBuf, short keyStart, short keyLength, byte[] data, short dataStart, short dataLength, byte[] mac, @@ -1320,17 +1335,4 @@ public KMAttestationKey getAttestationKey() { public KMPreSharedKey getPresharedKey() { return (KMPreSharedKey) preSharedKey; } - - @Override - public short aesGCMEncrypt(KMMasterKey key, 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) { - - return aesGCMEncrypt(((KMAESKey) key).getKey(), secret, secretStart, - secretLen, encSecret, encSecretStart, nonce, nonceStart, nonceLen, - authData, authDataStart, authDataLen, authTag, authTagStart, - authTagLen); - } } diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java index 2c7001b2..2ef4f873 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java @@ -539,6 +539,17 @@ public boolean hmacVerify(HMACKey key, byte[] data, short dataStart, short dataL return hmacSignature.verify(data, dataStart, dataLength, mac, macStart, macLength); } + @Override + public short hmacSignkdf(KMMasterKey masterkey, byte[] data, short dataStart, + short dataLength, byte[] signature, short signatureStart) { + KMAESKey aesKey = (KMAESKey) masterkey; + short keyLen = (short) (aesKey.getKeySizeBits() / 8); + byte[] keyData = new byte[keyLen]; + aesKey.getKey(keyData, (short) 0); + return hmacSign(keyData, (short) 0, keyLen, data, dataStart, dataLength, + signature, signatureStart); + } + @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); @@ -1360,35 +1371,4 @@ public KMAttestationKey getAttestationKey() { public KMPreSharedKey getPresharedKey() { return (KMPreSharedKey) preSharedKey; } - - @Override - public short aesGCMEncrypt(KMMasterKey masterKey, 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) { - KMAESKey aesKey = (KMAESKey) masterKey; - short keyLen = aesKey.getKeySizeBits(); - keyLen = (short) (keyLen / 8); - byte[] keyBuf = new byte[keyLen]; - aesKey.getKey(keyBuf, (short)0); - return aesGCMEncrypt( - keyBuf, - (short) 0, - keyLen, - secret, - secretStart, - secretLen, - encSecret, - encSecretStart, - nonce, - nonceStart, - nonceLen, - authData, - authDataStart, - authDataLen, - authTag, - authTagStart, - authTagLen); - } } diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 4cf028e5..f7b34db5 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -39,6 +39,7 @@ 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 DERIVE_KEY_INPUT_SIZE = (short) 256; // "Keymaster HMAC Verification" - used for HMAC key verification. public static final byte[] sharingCheck = { @@ -524,11 +525,8 @@ private void processDeviceLockedCmd(APDU apdu) { if (KMInteger.compare(verTime, lastDeviceLockedTime) > 0) { Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 8, (byte) 0); KMInteger.cast(verTime).getValue(scratchPad, (short) 0, (short) 8); - // repository.deviceLockedFlag = true; repository.setDeviceLock(true); - // repository.deviceUnlockPasswordOnly = (tmpVariables[1] == 0x01); repository.setDeviceLockPasswordOnly(tmpVariables[1] == 0x01); - // Util.arrayCopy(scratchPad,(short)0,repository.deviceLockedTimestamp,(short)0,(short)repository.deviceLockedTimestamp.length); repository.setDeviceLockTimestamp(scratchPad, (short) 0, (short) 8); } sendError(apdu, KMError.OK); @@ -549,7 +547,6 @@ public static void sendOutgoing(APDU apdu) { } // Send data apdu.setOutgoing(); - // short currentBlockSize = apdu.getOutBlockSize(); apdu.setOutgoingLength(bufferLength); apdu.sendBytesLong(buffer, bufferStartOffset, bufferLength); } @@ -917,7 +914,6 @@ private void processDeleteKeyCmd(APDU apdu) { // Receive the incoming request fully from the master. receiveIncoming(apdu); - // Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) apdu.getBuffer().length, (byte) 0); // Arguments short argsProto = KMArray.instance((short) 1); KMArray.cast(argsProto).add((short) 0, KMByteBlob.exp()); @@ -1421,7 +1417,7 @@ private void processAttestKeyCmd(APDU apdu) { addTags( KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getSoftwareEnforced(), false, cert); - cert.deviceLocked(repository.getDeviceLock()); + cert.deviceLocked(repository.getBootLoaderLock()); cert.issuer(repository.getIssuer()); cert.publicKey(data[PUB_KEY]); cert.verifiedBootHash(repository.getVerifiedBootHash()); @@ -1429,7 +1425,7 @@ private void processAttestKeyCmd(APDU apdu) { cert.verifiedBootKey(repository.getVerifiedBootKey()); cert.verifiedBootState(repository.getBootState()); // buffer for cert - we allocate 2KBytes buffer - // TODO make this buffer size configurable + // make this buffer size configurable tmpVariables[3] = KMByteBlob.instance(MAX_CERT_SIZE); buffer = KMByteBlob.cast(tmpVariables[3]).getBuffer(); bufferStartOffset = KMByteBlob.cast(tmpVariables[3]).getStartOff(); @@ -1465,24 +1461,6 @@ private void addAttestationIds(KMAttestationCert cert) { } index++; } - /* - if(repository.isAttIdSupported()){ - short attTag; - short blob; - byte index = 0; - while (index < repository.ATT_ID_TABLE_SIZE) { - if (repository.getAttIdLen(index) != 0) { - blob = KMByteBlob.instance( - repository.getAttIdBuffer(index), - repository.getAttIdOffset(index), - repository.getAttIdLen(index)); - attTag = KMByteTag.instance(repository.getAttIdTag(index), blob); - cert.extensionTag(attTag,true); - index++; - } - } - } - */ } private void addTags(short params, boolean hwEnforced, KMAttestationCert cert) { @@ -1631,10 +1609,6 @@ private void processFinishOperationCmd(APDU apdu) { private void finishEncryptOperation(KMOperationState op, byte[] scratchPad) { short len = KMByteBlob.cast(data[INPUT_DATA]).length(); switch (op.getAlgorithm()) { - // - // RSA Encryption is only supported for testing purpose - // TODO remove this later on if not required - // case KMType.RSA: // Output size is always 256 bytes data[OUTPUT_DATA] = KMByteBlob.instance((short) 256); @@ -1693,8 +1667,6 @@ private void finishEncryptOperation(KMOperationState op, byte[] scratchPad) { private void finishDecryptOperation(KMOperationState op, byte[] scratchPad) { short len = KMByteBlob.cast(data[INPUT_DATA]).length(); switch (op.getAlgorithm()) { - // Only supported for testing purpose - // TODO remove this later on case KMType.RSA: // Fill the scratch pad with zero Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0); @@ -1907,7 +1879,6 @@ private void authorizeUpdateFinishOperation(KMOperationState op, byte[] scratchP if (KMInteger.compare(tmpVariables[0], tmpVariables[2]) < 0) { KMException.throwIt(KMError.KEY_USER_NOT_AUTHENTICATED); } - // TODO this is not needed op.setAuthTimeoutValidated(true); } else if (op.isAuthPerOperationReqd()) { // If Auth per operation is required tmpVariables[0] = KMHardwareAuthToken.cast(data[HW_TOKEN]).getChallenge(); @@ -1930,11 +1901,6 @@ private void authorizeDeviceUnlock(short hwToken) { ptr = KMHardwareAuthToken.cast(hwToken).getTimestamp(); // Check if the current auth time stamp is greater then device locked time stamp short ts = repository.getDeviceTimeStamp(); - /*if (KMInteger.compare(ptr, KMInteger.uint_64(repository.deviceLockedTimestamp, (short) 0)) - <= 0) { - KMException.throwIt(KMError.DEVICE_LOCKED); - } - */ if (KMInteger.compare(ptr, ts) <= 0) { KMException.throwIt(KMError.DEVICE_LOCKED); } @@ -1951,7 +1917,6 @@ private void authorizeDeviceUnlock(short hwToken) { // repository.deviceLockedFlag = false; repository.setDeviceLock(false); repository.clearDeviceLockTimeStamp(); - // Util.arrayFillNonAtomic(repository.deviceLockedTimestamp, (short) 0, (short) 8, (byte) 0); } } @@ -2006,16 +1971,6 @@ private void validateVerificationToken(short verToken, byte[] scratchPad) { // hmac the data ptr = KMVerificationToken.cast(verToken).getMac(); short key = repository.getComputedHmacKey(); - /*boolean verified = - seProvider.hmacVerify(repository.getComputedHmacKey(), - (short) 0, - (short) repository.getComputedHmacKey().length, - scratchPad, (short) 0, len, - KMByteBlob.cast(ptr).getBuffer(), - KMByteBlob.cast(ptr).getStartOff(), - KMByteBlob.cast(ptr).length()); - - */ boolean verified = seProvider.hmacVerify( KMByteBlob.cast(key).getBuffer(), @@ -2509,8 +2464,6 @@ private void authorizeAndBeginOperation(KMOperationState op, byte[] scratchPad) private void beginCipherOperation(KMOperationState op) { switch (op.getAlgorithm()) { - // Not required to be supported - supported for testing purpose - // TODO remove this later case KMType.RSA: try { if (op.getPurpose() == KMType.DECRYPT) { @@ -2550,7 +2503,6 @@ private void beginCipherOperation(KMOperationState op) { op.setAesGcmUpdateStart(); } try { - // if (data[IV] != KMType.INVALID_VALUE) { op.setOperation( seProvider.initSymmetricOperation( (byte) op.getPurpose(), @@ -2769,15 +2721,6 @@ private boolean validateHwToken(short hwToken, byte[] scratchPad) { // hmac the data ptr = KMHardwareAuthToken.cast(hwToken).getMac(); short key = repository.getComputedHmacKey(); - /*return seProvider.hmacVerify( - repository.getComputedHmacKey(), - (short) 0, - (short) repository.getComputedHmacKey().length, - scratchPad, (short) 0, len, - KMByteBlob.cast(ptr).getBuffer(), - KMByteBlob.cast(ptr).getStartOff(), - KMByteBlob.cast(ptr).length()); - */ return seProvider.hmacVerify( KMByteBlob.cast(key).getBuffer(), KMByteBlob.cast(key).getStartOff(), @@ -3219,7 +3162,6 @@ private void processSetBootParamsCmd(APDU apdu) { 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); //reclaim memory repository.reclaimMemory(bufferLength); @@ -3280,7 +3222,7 @@ private void processSetBootParamsCmd(APDU apdu) { repository.setBootState(enumVal); enumVal = KMEnum.cast(tmpVariables[7]).getVal(); - repository.setDeviceLock(enumVal == KMType.DEVICE_LOCKED_TRUE); + repository.setBootloaderLocked(enumVal == KMType.DEVICE_LOCKED_TRUE); // Clear the Computed SharedHmac and Hmac nonce from persistent memory. repository.clearComputedHmac(); @@ -3422,7 +3364,6 @@ private static void generateRSAKey(byte[] scratchPad) { // Validate RSA Key validateRSAKey(scratchPad); // Now generate 2048 bit RSA keypair for the given exponent - // KeyPair rsaKey = seProvider.createRsaKeyPair(); short[] lengths = tmpVariables; data[PUB_KEY] = KMByteBlob.instance((short) 256); data[SECRET] = KMByteBlob.instance((short) 256); @@ -3480,8 +3421,6 @@ private static void generateAESKey(byte[] scratchPad) { validateAESKey(); tmpVariables[0] = KMIntegerTag.getShortValue(KMType.UINT_TAG, KMType.KEYSIZE, data[KEY_PARAMETERS]); - // AESKey aesKey = seProvider.createAESKey(tmpVariables[0]); - // tmpVariables[0] = aesKey.getKey(scratchPad, (short) 0); tmpVariables[0] = seProvider.createSymmetricKey(KMType.AES, tmpVariables[0], scratchPad, (short) 0); data[SECRET] = KMByteBlob.instance(scratchPad, (short) 0, tmpVariables[0]); @@ -3504,7 +3443,6 @@ private static void validateECKeys() { private static void generateECKeys(byte[] scratchPad) { validateECKeys(); - // KeyPair ecKey = seProvider.createECKeyPair(); short[] lengths = tmpVariables; seProvider.createAsymmetricKey( KMType.EC, @@ -3515,9 +3453,7 @@ private static void generateECKeys(byte[] scratchPad) { (short) 128, (short) 128, lengths); - // tmpVariables[5] = ((ECPublicKey) ecKey.getPublic()).getW(scratchPad, (short) 0); data[PUB_KEY] = KMByteBlob.instance(scratchPad, (short) 128, lengths[1]); - // tmpVariables[5] = ((ECPrivateKey) ecKey.getPrivate()).getS(scratchPad, (short) 0); data[SECRET] = KMByteBlob.instance(scratchPad, (short) 0, lengths[0]); data[KEY_BLOB] = KMArray.instance((short) 5); KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_PUB_KEY, data[PUB_KEY]); @@ -3543,8 +3479,6 @@ private static void validateTDESKey() { private static void generateTDESKey(byte[] scratchPad) { validateTDESKey(); - // DESKey desKey = seProvider.createTDESKey(); - // tmpVariables[0] = desKey.getKey(scratchPad, (short) 0); tmpVariables[0] = seProvider.createSymmetricKey(KMType.DES, (short) 168, scratchPad, (short) 0); data[SECRET] = KMByteBlob.instance(scratchPad, (short) 0, tmpVariables[0]); data[KEY_BLOB] = KMArray.instance((short) 4); @@ -3590,8 +3524,6 @@ private static void generateHmacKey(byte[] scratchPad) { tmpVariables[0] = KMIntegerTag.getShortValue(KMType.UINT_TAG, KMType.KEYSIZE, data[KEY_PARAMETERS]); // generate HMAC Key - // HMACKey hmacKey = seProvider.createHMACKey(tmpVariables[1]); - // tmpVariables[0] = hmacKey.getKey(scratchPad, (short) 0); tmpVariables[0] = seProvider.createSymmetricKey(KMType.HMAC, tmpVariables[0], scratchPad, (short) 0); data[SECRET] = KMByteBlob.instance(scratchPad, (short) 0, tmpVariables[0]); @@ -3618,20 +3550,6 @@ private void checkVersionAndPatchLevel(byte[] scratchPad) { KMException.throwIt(KMError.KEY_REQUIRES_UPGRADE); } } - /* - if ((tmpVariables[0] != KMType.INVALID_VALUE) - && (Util.arrayCompare( - repository.osVersion, (short) 0, scratchPad, (short) 0, tmpVariables[0]) - != 0)) { - if (Util.arrayCompare(repository.osVersion, (short) 0, scratchPad, (short) 0, tmpVariables[0]) - == -1) { - // If the key characteristics has os version > current os version - KMException.throwIt(KMError.INVALID_KEY_BLOB); - } else { - KMException.throwIt(KMError.KEY_REQUIRES_UPGRADE); - } - } - */ tmpVariables[0] = KMIntegerTag.getValue( scratchPad, (short) 0, KMType.UINT_TAG, KMType.OS_PATCH_LEVEL, data[HW_PARAMETERS]); @@ -3650,18 +3568,6 @@ private void checkVersionAndPatchLevel(byte[] scratchPad) { KMException.throwIt(KMError.KEY_REQUIRES_UPGRADE); } } - /*if ((tmpVariables[0] != KMType.INVALID_VALUE) - && (Util.arrayCompare(repository.osPatch, (short) 0, scratchPad, (short) 0, tmpVariables[0]) - != 0)) { - if (Util.arrayCompare(repository.osPatch, (short) 0, scratchPad, (short) 0, tmpVariables[0]) - == -1) { - // If the key characteristics has os patch level > current os patch - KMException.throwIt(KMError.INVALID_KEY_BLOB); - } else { - KMException.throwIt(KMError.KEY_REQUIRES_UPGRADE); - } - } - */ } private static void makeKeyCharacteristics(byte[] scratchPad) { @@ -3688,7 +3594,7 @@ 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] = repository.getVerifiedBootKey(); + data[ROT] = repository.readROT(); // make hidden key params list data[HIDDEN_PARAMETERS] = @@ -3747,11 +3653,7 @@ private static void parseEncryptedKeyBlob(byte[] scratchPad) { KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getHardwareEnforced(); data[SW_PARAMETERS] = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getSoftwareEnforced(); - // make root of trust blob - // data[ROT] = - // KMByteBlob.instance( - // repository.verifiedBootKey, (short) 0, (short) repository.verifiedBootKey.length); - data[ROT] = repository.getVerifiedBootKey(); + data[ROT] = repository.readROT(); data[HIDDEN_PARAMETERS] = KMKeyParameters.makeHidden(data[APP_ID], data[APP_DATA], data[ROT], scratchPad); @@ -3880,59 +3782,37 @@ private static short addPtrToAAD(short dataArrPtr, byte[] aadBuf, short offset) private static short deriveKey(byte[] scratchPad) { tmpVariables[0] = KMKeyParameters.cast(data[HIDDEN_PARAMETERS]).getVals(); - tmpVariables[1] = repository.alloc((short) 256); + tmpVariables[1] = repository.alloc(DERIVE_KEY_INPUT_SIZE); // generate derivation material from hidden parameters tmpVariables[2] = encoder.encode(tmpVariables[0], repository.getHeap(), tmpVariables[1]); + if (DERIVE_KEY_INPUT_SIZE > tmpVariables[2]) { + // Copy KeyCharacteristics in the remaining space of DERIVE_KEY_INPUT_SIZE + Util.arrayCopyNonAtomic(repository.getHeap(), (short) (data[AUTH_DATA]), + repository.getHeap(), + (short) (tmpVariables[1] + tmpVariables[2]), + (short) (DERIVE_KEY_INPUT_SIZE - tmpVariables[2])); + } // KeyDerivation: - // 1. AesGCM Encryption, with below input parameters. - // authData - HIDDEN_PARAMTERS - // Key - Master Key - // InputData - KeyCharacteristics - // 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. + // 1. Do HMAC Sign, with below input parameters. + // Key - 128 bit master key + // Input data - HIDDEN_PARAMETERS + KeyCharacateristics + // - Truncate beyond 256 bytes. + // 2. HMAC Sign generates an output of 32 bytes length. // Consume only first 16 bytes as derived key. - tmpVariables[5] = repository.alloc(AES_GCM_AUTH_TAG_LENGTH); - tmpVariables[3] = - seProvider.aesGCMEncrypt( - seProvider.getMasterKey(), - 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.getHeap(), - tmpVariables[5], - AES_GCM_AUTH_TAG_LENGTH); // Hmac sign. - tmpVariables[3] = seProvider.hmacSign( + tmpVariables[3] = seProvider.hmacSignkdf( + seProvider.getMasterKey(), repository.getHeap(), - tmpVariables[5], - AES_GCM_AUTH_TAG_LENGTH, + tmpVariables[1], + DERIVE_KEY_INPUT_SIZE, scratchPad, - (short) 0, - tmpVariables[3], - repository.getHeap(), - tmpVariables[1]); + (short) 0); 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]); + data[DERIVED_KEY] = tmpVariables[1]; Util.arrayCopyNonAtomic( scratchPad, (short) 0, repository.getHeap(), data[DERIVED_KEY], tmpVariables[3]); return tmpVariables[3]; @@ -3977,44 +3857,4 @@ 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; - } -*/ } diff --git a/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/src/com/android/javacard/keymaster/KMRepository.java index 7785c5b6..ee7cc6a8 100644 --- a/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/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 = 21; + public static final short DATA_INDEX_SIZE = 22; public static final short DATA_INDEX_ENTRY_SIZE = 4; public static final short DATA_MEM_SIZE = 2048; public static final short HEAP_SIZE = 10000; @@ -62,7 +62,8 @@ public class KMRepository implements KMUpgradable { public static final byte BOOT_VERIFIED_BOOT_HASH = 17; public static final byte BOOT_VERIFIED_BOOT_STATE = 18; public static final byte BOOT_DEVICE_LOCKED_STATUS = 19; - public static final byte BOOT_DEVICE_LOCKED_TIME = 20; + public static final byte DEVICE_LOCKED_TIME = 20; + public static final byte DEVICE_LOCKED = 21; // Data Item sizes public static final short MASTER_KEY_SIZE = 16; @@ -111,6 +112,11 @@ public KMRepository(boolean isUpgrading) { new Object[KMOperationState.MAX_REFS]}}; index++; } + //Initialize the device locked status + if (!isUpgrading) { + setDeviceLock(false); + setDeviceLockPasswordOnly(false); + } repository = this; } @@ -165,7 +171,6 @@ public KMOperationState reserveOperation(short opHandle){ return null; } - //TODO refactor following method public void persistOperation(byte[] data, short opHandle, KMOperation op) { short index = 0; byte[] opId; @@ -496,6 +501,39 @@ public short getOsPatch(){ } } + public short readROT() { + short length = dataLength(BOOT_VERIFIED_BOOT_KEY); + length += dataLength(BOOT_VERIFIED_BOOT_HASH); + length += dataLength(BOOT_VERIFIED_BOOT_STATE); + length += dataLength(BOOT_DEVICE_LOCKED_STATUS); + short blob = KMByteBlob.instance(length); + if((length = readDataEntry( + BOOT_VERIFIED_BOOT_KEY, + KMByteBlob.cast(blob).getBuffer(), + KMByteBlob.cast(blob).getStartOff())) == 0){ + return 0; + } + if((length += readDataEntry( + BOOT_VERIFIED_BOOT_HASH, + KMByteBlob.cast(blob).getBuffer(), + (short) (KMByteBlob.cast(blob).getStartOff() + length))) == 0){ + return 0; + } + if((length += readDataEntry( + BOOT_VERIFIED_BOOT_STATE, + KMByteBlob.cast(blob).getBuffer(), + (short) (KMByteBlob.cast(blob).getStartOff() + length))) == 0){ + return 0; + } + if((length += readDataEntry( + BOOT_DEVICE_LOCKED_STATUS, + KMByteBlob.cast(blob).getBuffer(), + (short) (KMByteBlob.cast(blob).getStartOff() + length))) == 0){ + return 0; + } + return blob; + } + public short getVerifiedBootKey(){ return readData(BOOT_VERIFIED_BOOT_KEY); } @@ -504,7 +542,7 @@ public short getVerifiedBootHash(){ return readData(BOOT_VERIFIED_BOOT_HASH); } - public boolean getDeviceLock(){ + public boolean getBootLoaderLock() { short blob = readData(BOOT_DEVICE_LOCKED_STATUS); return (byte)((getHeap())[KMByteBlob.cast(blob).getStartOff()] & 0xFE) != 0; } @@ -514,13 +552,18 @@ public byte getBootState(){ return (getHeap())[KMByteBlob.cast(blob).getStartOff()]; } + public boolean getDeviceLock(){ + short blob = readData(DEVICE_LOCKED); + return (byte)((getHeap())[KMByteBlob.cast(blob).getStartOff()] & 0xFE) != 0; + } + public boolean getDeviceLockPasswordOnly(){ - short blob = readData(BOOT_DEVICE_LOCKED_STATUS); + short blob = readData(DEVICE_LOCKED); return (byte)((getHeap())[KMByteBlob.cast(blob).getStartOff()] & 0xFD) != 0; } public short getDeviceTimeStamp(){ - short blob = readData(BOOT_DEVICE_LOCKED_TIME); + short blob = readData(DEVICE_LOCKED_TIME); if(blob != 0){ return KMInteger.uint_64(KMByteBlob.cast(blob).getBuffer(), KMByteBlob.cast(blob).getStartOff()); @@ -546,27 +589,34 @@ public void setBootPatchLevel(byte[] buf, short start, short len) { writeDataEntry(BOOT_PATCH_LEVEL, buf, start, len); } - public void setDeviceLock(boolean flag){ + public void setBootloaderLocked(boolean flag) { short start = alloc(DEVICE_LOCK_FLAG_SIZE); if(flag) (getHeap())[start] = (byte)((getHeap())[start] | 0x01); else (getHeap())[start] = (byte)((getHeap())[start] & 0xFE); writeDataEntry(BOOT_DEVICE_LOCKED_STATUS,getHeap(),start,DEVICE_LOCK_FLAG_SIZE); } + public void setDeviceLock(boolean flag){ + short start = alloc(DEVICE_LOCK_FLAG_SIZE); + if(flag) (getHeap())[start] = (byte)((getHeap())[start] | 0x01); + else (getHeap())[start] = (byte)((getHeap())[start] & 0xFE); + writeDataEntry(DEVICE_LOCKED,getHeap(),start,DEVICE_LOCK_FLAG_SIZE); + } + public void setDeviceLockPasswordOnly(boolean flag){ short start = alloc(DEVICE_LOCK_FLAG_SIZE); if(flag) (getHeap())[start] = (byte)((getHeap())[start] | 0x02); else (getHeap())[start] = (byte)((getHeap())[start] & 0xFD); - writeDataEntry(BOOT_DEVICE_LOCKED_STATUS,getHeap(),start,DEVICE_LOCK_FLAG_SIZE); + writeDataEntry(DEVICE_LOCKED,getHeap(),start,DEVICE_LOCK_FLAG_SIZE); } public void setDeviceLockTimestamp(byte[] buf, short start, short len){ if(len != DEVICE_LOCK_TS_SIZE) KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - writeDataEntry(BOOT_DEVICE_LOCKED_TIME, buf, start,len); + writeDataEntry(DEVICE_LOCKED_TIME, buf, start,len); } public void clearDeviceLockTimeStamp(){ - clearDataEntry(BOOT_DEVICE_LOCKED_TIME); + clearDataEntry(DEVICE_LOCKED_TIME); } public void setOsPatch(byte[] buf, short start, short len){ diff --git a/Applet/src/com/android/javacard/keymaster/KMSEProvider.java b/Applet/src/com/android/javacard/keymaster/KMSEProvider.java index 3b7edcf4..022eb6cd 100644 --- a/Applet/src/com/android/javacard/keymaster/KMSEProvider.java +++ b/Applet/src/com/android/javacard/keymaster/KMSEProvider.java @@ -159,46 +159,6 @@ short aesGCMEncrypt( short authTagStart, short authTagLen); - /** - * This function is used to derive a partial secret, which is used to encrypt the keyBlobs. - * This is a oneshot operation that performs encryption operation using AES GCM algorithm. It throws - * CryptoException if algorithm is not supported or if tag length is not equal to 16 or - * nonce length is not equal to 12. - * - * @param aesKey instance of KMMasterKey. - * @param data is the buffer that contains data to encrypt. - * @param dataStart is the start of the data buffer. - * @param dataLen is the length of the data buffer. - * @param encData is the buffer of the output encrypted data. - * @param encDataStart is the start of the encrypted data buffer. - * @param nonce is the buffer of nonce. - * @param nonceStart is the start of the nonce buffer. - * @param nonceLen is the length of the nonce buffer. - * @param authData is the authentication data buffer. - * @param authDataStart is the start of the authentication buffer. - * @param authDataLen is the length of the authentication buffer. - * @param authTag is the buffer to output authentication tag. - * @param authTagStart is the start of the buffer. - * @param authTagLen is the length of the buffer. - * @return length of the encrypted data. - */ - short aesGCMEncrypt( - KMMasterKey aesKey, - byte[] data, - short dataStart, - short dataLen, - byte[] encData, - short encDataStart, - byte[] nonce, - short nonceStart, - short nonceLen, - byte[] authData, - short authDataStart, - short authDataLen, - byte[] authTag, - short authTagStart, - short authTagLen); - /** * This is a oneshot operation that performs decryption operation using AES GCM algorithm. It throws * CryptoException if algorithm is not supported. @@ -290,6 +250,26 @@ short hmacSign( byte[] signature, short signatureStart); + /** + * This is a oneshot operation that signs the data using hmac algorithm. + * This is used to derive the key, which is used to encrypt the keyblob. + * + * @param instance of masterkey. + * @param data is the buffer containing data to be signed. + * @param dataStart is the start of the data. + * @param dataLength is the length of the data. + * @param signature is the output signature buffer + * @param signatureStart is the start of the signature + * @return length of the signature buffer in bytes. + */ + short hmacSignkdf( + KMMasterKey masterkey, + byte[] data, + short dataStart, + short dataLength, + byte[] signature, + short signatureStart); + /** * This is a oneshot operation that verifies the signature using hmac algorithm. * From b27520b051bb17ad47c3a6b1be61c99b06115057 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Sun, 7 Feb 2021 16:58:48 +0530 Subject: [PATCH 91/99] 1. Removed unused functions in KMAESKey.java 2. Renamed the KMSEProvider function names of hmacSign and cmacKdf --- .../keymaster/KMAndroidSEProvider.java | 4 ++-- .../android/javacard/keymaster/KMAESKey.java | 20 ------------------- .../javacard/keymaster/KMJCardSimulator.java | 4 ++-- .../javacard/keymaster/KMKeymasterApplet.java | 4 ++-- .../javacard/keymaster/KMSEProvider.java | 19 ++++++++++++++++-- 5 files changed, 23 insertions(+), 28 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java index b04cb362..6a5a0671 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java @@ -752,7 +752,7 @@ public short hmacSign(byte[] keyBuf, short keyStart, short keyLength, } @Override - public short hmacSign(KMMasterKey masterkey, byte[] data, short dataStart, + public short hmacKDF(KMMasterKey masterkey, byte[] data, short dataStart, short dataLength, byte[] signature, short signatureStart) { try { AESKey aesKey = ((KMAESKey) masterkey).getKey(); @@ -1169,7 +1169,7 @@ public KMAttestationCert getAttestationCert(boolean rsaCert) { } @Override - public short cmacKdf(KMPreSharedKey pSharedKey, byte[] label, + public short cmacKDF(KMPreSharedKey pSharedKey, byte[] label, short labelStart, short labelLen, byte[] context, short contextStart, short contextLength, byte[] keyBuf, short keyStart) { HMACKey key = cmacKdf(pSharedKey, label, labelStart, labelLen, context, diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAESKey.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAESKey.java index c16a8188..489d4f77 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAESKey.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAESKey.java @@ -15,8 +15,6 @@ */ package com.android.javacard.keymaster; -import org.globalplatform.upgrade.Element; - import javacard.security.AESKey; public class KMAESKey implements KMMasterKey { @@ -37,22 +35,4 @@ public byte getKey(byte[] keyData, short kOff) { public short getKeySizeBits() { return aesKey.getSize(); } - - public static void onSave(Element element, KMAESKey kmKey) { - element.write(kmKey.aesKey); - } - - public static KMAESKey onRestore(Element element) { - AESKey aesKey = (AESKey) element.readObject(); - KMAESKey kmKey = new KMAESKey(aesKey); - return kmKey; - } - - public static short getBackupPrimitiveByteCount() { - return (short) 0; - } - - public static short getBackupObjectCount() { - return (short) 1; - } } diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java index 2ef4f873..6b0596ae 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java @@ -515,7 +515,7 @@ public HMACKey cmacKdf(byte[] keyMaterial, short keyMaterialStart, short keyMate } @Override - public short cmacKdf(KMPreSharedKey pSharedKey, byte[] label, + public short cmacKDF(KMPreSharedKey pSharedKey, byte[] label, short labelStart, short labelLen, byte[] context, short contextStart, short contextLength, byte[] keyBuf, short keyStart) { KMHmacKey key = (KMHmacKey) pSharedKey; short keyMaterialLen = key.getKeySizeBits(); @@ -540,7 +540,7 @@ public boolean hmacVerify(HMACKey key, byte[] data, short dataStart, short dataL } @Override - public short hmacSignkdf(KMMasterKey masterkey, byte[] data, short dataStart, + public short hmacKDF(KMMasterKey masterkey, byte[] data, short dataStart, short dataLength, byte[] signature, short signatureStart) { KMAESKey aesKey = (KMAESKey) masterkey; short keyLen = (short) (aesKey.getKeySizeBits() / 8); diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index f7b34db5..b30e63c2 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -1032,7 +1032,7 @@ private void processComputeSharedHmacCmd(APDU apdu) { // generate the key and store it in scratch pad - 32 bytes tmpVariables[6] = - seProvider.cmacKdf( + seProvider.cmacKDF( seProvider.getPresharedKey(), ckdfLable, (short) 0, @@ -3800,7 +3800,7 @@ private static short deriveKey(byte[] scratchPad) { // 2. HMAC Sign generates an output of 32 bytes length. // Consume only first 16 bytes as derived key. // Hmac sign. - tmpVariables[3] = seProvider.hmacSignkdf( + tmpVariables[3] = seProvider.hmacKDF( seProvider.getMasterKey(), repository.getHeap(), tmpVariables[1], diff --git a/Applet/src/com/android/javacard/keymaster/KMSEProvider.java b/Applet/src/com/android/javacard/keymaster/KMSEProvider.java index 022eb6cd..a057eb9e 100644 --- a/Applet/src/com/android/javacard/keymaster/KMSEProvider.java +++ b/Applet/src/com/android/javacard/keymaster/KMSEProvider.java @@ -1,3 +1,18 @@ +/* + * 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 org.globalplatform.upgrade.Element; @@ -216,7 +231,7 @@ boolean aesGCMDecrypt( * @param keyStart is the start of the output buffer. * @return length of the derived key buffer in bytes. */ - short cmacKdf( + short cmacKDF( KMPreSharedKey hmacKey, byte[] label, short labelStart, @@ -262,7 +277,7 @@ short hmacSign( * @param signatureStart is the start of the signature * @return length of the signature buffer in bytes. */ - short hmacSignkdf( + short hmacKDF( KMMasterKey masterkey, byte[] data, short dataStart, From b6f8ce6bf8a4912eb5a0704381749f589d790050 Mon Sep 17 00:00:00 2001 From: BKSSMVenkateswarlu <40534495+BKSSMVenkateswarlu@users.noreply.github.com> Date: Sun, 7 Feb 2021 21:17:23 +0530 Subject: [PATCH 92/99] Update JavacardKeymaster4Device.cpp Changed the Javacard keymaster name to JavacardKeymaster4.1Device v1.0 --- HAL/keymaster/4.1/JavacardKeymaster4Device.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp index 3086e287..c9f3ab96 100644 --- a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp +++ b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp @@ -38,7 +38,7 @@ #include #include -#define JAVACARD_KEYMASTER_NAME "JavacardKeymaster4.1Device v0.1" +#define JAVACARD_KEYMASTER_NAME "JavacardKeymaster4.1Device v1.0" #define JAVACARD_KEYMASTER_AUTHOR "Android Open Source Project" #define APDU_CLS 0x80 From cc53a65798b7bf942865775c2a2f3c4a6d523be1 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Sun, 7 Feb 2021 21:24:45 +0530 Subject: [PATCH 93/99] Added Copyright comment --- .../com/android/javacard/keymaster/KMAESKey.java | 15 +++++++++++++++ .../javacard/keymaster/KMAndroidSEApplet.java | 15 +++++++++++++++ .../javacard/keymaster/KMAttestationCertImpl.java | 15 +++++++++++++++ .../keymaster/KMEcdsa256NoDigestSignature.java | 15 +++++++++++++++ .../android/javacard/keymaster/KMInstance.java | 15 +++++++++++++++ .../javacard/keymaster/KMOperationImpl.java | 15 +++++++++++++++ .../keymaster/KMRsa2048NoDigestSignature.java | 15 +++++++++++++++ .../javacard/keymaster/KMRsaOAEPEncoding.java | 15 +++++++++++++++ .../com/android/javacard/keymaster/KMUtils.java | 15 +++++++++++++++ .../javacard/keymaster/KMAttestationCertImpl.java | 15 +++++++++++++++ .../com/android/javacard/keymaster/KMCipher.java | 15 +++++++++++++++ .../android/javacard/keymaster/KMCipherImpl.java | 15 +++++++++++++++ .../keymaster/KMEcdsa256NoDigestSignature.java | 15 +++++++++++++++ .../javacard/keymaster/KMJCardSimApplet.java | 15 +++++++++++++++ .../javacard/keymaster/KMOperationImpl.java | 15 +++++++++++++++ .../keymaster/KMRsa2048NoDigestSignature.java | 15 +++++++++++++++ .../com/android/javacard/keymaster/KMUtils.java | 15 +++++++++++++++ .../javacard/keymaster/KMAttestationCert.java | 15 +++++++++++++++ .../com/android/javacard/keymaster/KMError.java | 15 +++++++++++++++ .../android/javacard/keymaster/KMOperation.java | 15 +++++++++++++++ .../android/javacard/keymaster/KMUpgradable.java | 15 +++++++++++++++ 21 files changed, 315 insertions(+) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAESKey.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAESKey.java index 95896b13..afdfb08e 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAESKey.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAESKey.java @@ -1,3 +1,18 @@ +/* + * 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 org.globalplatform.upgrade.Element; diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java index 99dd47ce..bb6a2e86 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java @@ -1,3 +1,18 @@ +/* + * 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 org.globalplatform.upgrade.Element; diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java index bf6ae9b7..6025feef 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -1,3 +1,18 @@ +/* + * 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.KMAESKey; diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java index 727641c0..3f11a3b1 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java @@ -1,3 +1,18 @@ +/* + * 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 javacard.security.CryptoException; diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMInstance.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMInstance.java index 3bf35e97..12655bc4 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMInstance.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMInstance.java @@ -1,3 +1,18 @@ +/* + * 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; public class KMInstance { diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMOperationImpl.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMOperationImpl.java index 1c7ab32d..a38ee518 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMOperationImpl.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMOperationImpl.java @@ -1,3 +1,18 @@ +/* + * 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 javacard.framework.JCSystem; diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java index 71c36a3d..991072e2 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java @@ -1,3 +1,18 @@ +/* + * 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 javacard.framework.Util; diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsaOAEPEncoding.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsaOAEPEncoding.java index b8c7b30e..066d828f 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsaOAEPEncoding.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsaOAEPEncoding.java @@ -1,3 +1,18 @@ +/* + * 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 javacard.framework.JCSystem; diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java index cb8df259..7b4352f8 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java @@ -1,3 +1,18 @@ +/* + * 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 javacard.framework.Util; diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java index b89b50ca..5be20599 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -1,3 +1,18 @@ +/* + * 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 javacard.framework.JCSystem; diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipher.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipher.java index 145fea9d..017a8398 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipher.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipher.java @@ -1,3 +1,18 @@ +/* + * 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; public abstract class KMCipher { diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipherImpl.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipherImpl.java index 264b74e5..7a1df761 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipherImpl.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipherImpl.java @@ -1,3 +1,18 @@ +/* + * 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 javacard.framework.Util; diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java index 242499ed..42468363 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java @@ -1,3 +1,18 @@ +/* + * 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 java.math.BigInteger; diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java index e1ec74f8..fd6dd910 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java @@ -1,3 +1,18 @@ +/* + * 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; public class KMJCardSimApplet extends KMKeymasterApplet { diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMOperationImpl.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMOperationImpl.java index dec071e6..78c01302 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMOperationImpl.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMOperationImpl.java @@ -1,3 +1,18 @@ +/* + * 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 javacard.security.Signature; diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java index 3ebf5fe0..855a3104 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java @@ -1,3 +1,18 @@ +/* + * 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 javacard.framework.Util; diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java index cb8df259..7b4352f8 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java @@ -1,3 +1,18 @@ +/* + * 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 javacard.framework.Util; diff --git a/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java b/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java index f3d36663..a472ff27 100644 --- a/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java +++ b/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java @@ -1,3 +1,18 @@ +/* + * 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; /** diff --git a/Applet/src/com/android/javacard/keymaster/KMError.java b/Applet/src/com/android/javacard/keymaster/KMError.java index 85c71654..8f842236 100644 --- a/Applet/src/com/android/javacard/keymaster/KMError.java +++ b/Applet/src/com/android/javacard/keymaster/KMError.java @@ -1,3 +1,18 @@ +/* + * 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; /** diff --git a/Applet/src/com/android/javacard/keymaster/KMOperation.java b/Applet/src/com/android/javacard/keymaster/KMOperation.java index 4011d7f5..8db3312b 100644 --- a/Applet/src/com/android/javacard/keymaster/KMOperation.java +++ b/Applet/src/com/android/javacard/keymaster/KMOperation.java @@ -1,3 +1,18 @@ +/* + * 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; /** diff --git a/Applet/src/com/android/javacard/keymaster/KMUpgradable.java b/Applet/src/com/android/javacard/keymaster/KMUpgradable.java index e3958a67..6815374e 100644 --- a/Applet/src/com/android/javacard/keymaster/KMUpgradable.java +++ b/Applet/src/com/android/javacard/keymaster/KMUpgradable.java @@ -1,3 +1,18 @@ +/* + * 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 org.globalplatform.upgrade.Element; From 3fecf13985cfe52be03382add1859a3b3c1f6e21 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Sun, 7 Feb 2021 22:27:26 +0530 Subject: [PATCH 94/99] Removed commented code --- .../src/com/android/javacard/keymaster/KMEncoder.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/Applet/src/com/android/javacard/keymaster/KMEncoder.java b/Applet/src/com/android/javacard/keymaster/KMEncoder.java index 72f906bf..685ba468 100644 --- a/Applet/src/com/android/javacard/keymaster/KMEncoder.java +++ b/Applet/src/com/android/javacard/keymaster/KMEncoder.java @@ -363,15 +363,4 @@ private void incrementStartOff(short inc){ ISOException.throwIt(ISO7816.SW_DATA_INVALID); } } - /* - 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()); - } - - */ } From af0de2ff06bf701d77c85485810086d9db11d61b Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Mon, 8 Feb 2021 22:11:47 +0530 Subject: [PATCH 95/99] Added few debug statements Added rsaPkcs1Success test in KMFunctionalTest --- .../javacard/keymaster/KMOperationImpl.java | 12 + .../javacard/test/KMFunctionalTest.java | 222 +++++++++++++++++- .../android/javacard/keymaster/KMError.java | 176 +++++++------- .../javacard/keymaster/KMKeymasterApplet.java | 1 + 4 files changed, 313 insertions(+), 98 deletions(-) diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMOperationImpl.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMOperationImpl.java index 78c01302..8379bfae 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMOperationImpl.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMOperationImpl.java @@ -41,9 +41,21 @@ public short update(byte[] inputDataBuf, short inputDataStart, short inputDataLe signature.update(inputDataBuf,inputDataStart,inputDataLength); return 0; } + + + 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()); + } + @Override public short finish(byte[] inputDataBuf, short inputDataStart, short inputDataLength, byte[] outputDataBuf, short outputDataStart) { + print(inputDataBuf, inputDataStart, inputDataLength); return cipher.doFinal(inputDataBuf,inputDataStart,inputDataLength,outputDataBuf,outputDataStart); } diff --git a/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java b/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java index 74892031..3b0797ea 100644 --- a/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java +++ b/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java @@ -41,15 +41,26 @@ import com.android.javacard.keymaster.KMRepository; import com.android.javacard.keymaster.KMType; import com.android.javacard.keymaster.KMVerificationToken; +//import com.licel.jcardsim.bouncycastle.crypto.Digest; import com.licel.jcardsim.smartcardio.CardSimulator; import com.licel.jcardsim.utils.AIDUtil; + import javacard.framework.AID; import javacard.framework.Util; +import javacard.security.KeyBuilder; +import javacard.security.KeyPair; +import javacard.security.RSAPrivateKey; +import javacard.security.RSAPublicKey; +import javacard.security.Signature; +import javacardx.crypto.Cipher; import java.security.spec.PKCS8EncodedKeySpec; +import java.util.Arrays; +import java.util.Random; import javax.smartcardio.CommandAPDU; import javax.smartcardio.ResponseAPDU; + import org.junit.Assert; import org.junit.Test; @@ -2027,6 +2038,159 @@ public void testSignWithRsaNonePkcs1(){ cleanUp(); } + public byte[] EncryptMessage(byte[] input, short params, byte[] keyBlob) { + short ret = begin(KMType.ENCRYPT, + KMByteBlob.instance(keyBlob, (short) 0, (short) keyBlob.length), + KMKeyParameters.instance(params), (short) 0); + // Get the operation handle. + short opHandle = KMArray.cast(ret).get((short) 2); + byte[] opHandleBuf = new byte[KMRepository.OPERATION_HANDLE_SIZE]; + KMInteger.cast(opHandle).getValue(opHandleBuf, (short) 0, + (short) opHandleBuf.length); + opHandle = KMInteger.uint_64(opHandleBuf, (short) 0); + + ret = finish(opHandle, + KMByteBlob.instance(input, (short) 0, (short) input.length), null, + (short) 0, (short) 0, (short) 0, KMError.OK); + short dataPtr = KMArray.cast(ret).get((short) 2); + byte[] output = new byte[KMByteBlob.cast(dataPtr).length()]; + if (KMByteBlob.cast(dataPtr).length() > 0) { + Util.arrayCopyNonAtomic(KMByteBlob.cast(dataPtr).getBuffer(), KMByteBlob + .cast(dataPtr).getStartOff(), output, (short) 0, + KMByteBlob.cast(dataPtr).length()); + } + return output; + } + + public byte[] DecryptMessage(byte[] input, short params, byte[] keyBlob) { + short ret = begin(KMType.DECRYPT, + KMByteBlob.instance(keyBlob, (short) 0, (short) keyBlob.length), + KMKeyParameters.instance(params), (short) 0); + // Get the operation handle. + short opHandle = KMArray.cast(ret).get((short) 2); + byte[] opHandleBuf = new byte[KMRepository.OPERATION_HANDLE_SIZE]; + KMInteger.cast(opHandle).getValue(opHandleBuf, (short) 0, + (short) opHandleBuf.length); + opHandle = KMInteger.uint_64(opHandleBuf, (short) 0); + + ret = finish(opHandle, + KMByteBlob.instance(input, (short) 0, (short) input.length), null, + (short) 0, (short) 0, (short) 0, KMError.OK); + short dataPtr = KMArray.cast(ret).get((short) 2); + byte[] output = new byte[KMByteBlob.cast(dataPtr).length()]; + if (KMByteBlob.cast(dataPtr).length() > 0) { + Util.arrayCopyNonAtomic(KMByteBlob.cast(dataPtr).getBuffer(), KMByteBlob + .cast(dataPtr).getStartOff(), output, (short) 0, + KMByteBlob.cast(dataPtr).length()); + } + return output; + } + + public short generateRandom(short upperBound) { + Random rand = new Random(); + short int_random = (short) rand.nextInt(upperBound); + return int_random; + } + + @Test + public void JCardTestRsaPkcs1() { + //Testing with Only Javacard APIs + byte[] message = { + 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, + 0x21 }; + for (int i = 0; i < 500; i++) { + byte[] out = new byte[256]; + byte[] dplain = new byte[256]; + KeyPair rsaKey = new KeyPair(KeyPair.ALG_RSA, KeyBuilder.LENGTH_RSA_2048); + rsaKey.genKeyPair(); + Cipher rsaCipher = Cipher.getInstance(Cipher.ALG_RSA_PKCS1, false); + RSAPublicKey key = (RSAPublicKey) rsaKey.getPublic(); + rsaCipher.init(key, Cipher.MODE_ENCRYPT); + + short outlen = rsaCipher.doFinal(message, (short) 0, + (short) message.length, out, (short) 0); + Assert.assertEquals(outlen, 256); + + RSAPrivateKey privKey = (RSAPrivateKey) rsaKey.getPrivate(); + rsaCipher.init(privKey, Cipher.MODE_DECRYPT); + short d_outlen = rsaCipher.doFinal(out, (short) 0, outlen, dplain, + (short) 0); + Assert.assertEquals(d_outlen, message.length); + byte[] plain = new byte[d_outlen]; + Util.arrayCopyNonAtomic(dplain, (short) 0, plain, (short) 0, d_outlen); + + Assert.assertTrue(Arrays.equals(message, plain)); + } + } + + @Test + public void testVtsRsaPkcs1Success() { + init(); + byte[] message = { + 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, + 0x21 }; // "Hello World!"; + for (int i = 0; i < 250; i++) { + short key = generateRsaKey(null, null); + short rsaKeyPtr = KMArray.cast(key).get((short) 1); + byte[] keyBlob = new byte[KMByteBlob.cast(rsaKeyPtr).length()]; + Util.arrayCopyNonAtomic(KMByteBlob.cast(rsaKeyPtr).getBuffer(), + KMByteBlob.cast(rsaKeyPtr).getStartOff(), keyBlob, (short) 0, + (short) keyBlob.length); + short pkcs1Params = getRsaParams(KMType.DIGEST_NONE, + KMType.RSA_PKCS1_1_5_ENCRYPT); + + byte[] cipherText1 = EncryptMessage(message, pkcs1Params, keyBlob); + Assert.assertEquals((2048 / 8), cipherText1.length); + + pkcs1Params = getRsaParams(KMType.DIGEST_NONE, + KMType.RSA_PKCS1_1_5_ENCRYPT); + byte[] cipherText2 = EncryptMessage(message, pkcs1Params, keyBlob); + Assert.assertEquals((2048 / 8), cipherText2.length); + System.out.println("stage-2"); + // PKCS1 v1.5 randomizes padding so every result should be different. + Assert.assertFalse(Arrays.equals(cipherText1, cipherText2)); + + print(cipherText1, (short) 0, (short) cipherText1.length); + pkcs1Params = getRsaParams(KMType.DIGEST_NONE, + KMType.RSA_PKCS1_1_5_ENCRYPT); + byte[] plainText = DecryptMessage(cipherText1, pkcs1Params, keyBlob); + Assert.assertTrue(Arrays.equals(message, plainText)); + + // Decrypting corrupted ciphertext should fail. + short offset_to_corrupt = generateRandom((short) cipherText1.length); + + byte corrupt_byte; + do { + corrupt_byte = (byte) generateRandom((short) 256); + } while (corrupt_byte == cipherText1[offset_to_corrupt]); + cipherText1[offset_to_corrupt] = corrupt_byte; + + pkcs1Params = getRsaParams(KMType.DIGEST_NONE, + KMType.RSA_PKCS1_1_5_ENCRYPT); + // Do Begin operation. + short ret = begin(KMType.DECRYPT, + KMByteBlob.instance(keyBlob, (short) 0, (short) keyBlob.length), + KMKeyParameters.instance(pkcs1Params), (short) 0); + System.out.println("stage-4"); + + // Get the operation handle. + short opHandle = KMArray.cast(ret).get((short) 2); + byte[] opHandleBuf = new byte[KMRepository.OPERATION_HANDLE_SIZE]; + KMInteger.cast(opHandle).getValue(opHandleBuf, (short) 0, + (short) opHandleBuf.length); + opHandle = KMInteger.uint_64(opHandleBuf, (short) 0); + System.out.println("stage-5"); + short dataPtr = KMByteBlob.instance(cipherText1, (short) 0, + (short) cipherText1.length); + // Finish should return UNKNOWN_ERROR. + ret = finish(opHandle, dataPtr, null, (short) 0, (short) 0, (short) 0, + KMError.UNKNOWN_ERROR); + System.out.println("stage-6"); + System.out.println("Count of i:" + i); + } + cleanUp(); + } + @Test public void testSignVerifyWithHmacSHA256WithUpdate(){ init(); @@ -2560,9 +2724,9 @@ public short processMessage( opHandle = KMInteger.uint_64(opHandleBuf, (short) 0); if (keyPurpose == KMType.VERIFY) { - ret = finish(opHandle, dataPtr, signature, (short) 0, (short) 0, (short) 0); + ret = finish(opHandle, dataPtr, signature, (short) 0, (short) 0, (short) 0, KMError.OK); } else { - ret = finish(opHandle, dataPtr, null, (short) 0, (short) 0, (short) 0); + ret = finish(opHandle, dataPtr, null, (short) 0, (short) 0, (short) 0, KMError.OK); } if(len >0){ dataPtr = KMArray.cast(ret).get((short)2); @@ -2610,7 +2774,34 @@ public short begin(byte keyPurpose, short keyBlob, short keyParmas, short hwToke } } - public short finish(short operationHandle, short data, byte[] signature, short inParams, short hwToken, short verToken) { + public short translateExtendedErrorCodes(short err) { + switch (err) { + case KMError.SW_CONDITIONS_NOT_SATISFIED: + case KMError.UNSUPPORTED_CLA: + case KMError.INVALID_P1P2: + case KMError.INVALID_DATA: + case KMError.CRYPTO_ILLEGAL_USE: + case KMError.CRYPTO_ILLEGAL_VALUE: + case KMError.CRYPTO_INVALID_INIT: + case KMError.CRYPTO_UNINITIALIZED_KEY: + case KMError.GENERIC_UNKNOWN_ERROR: + err = KMError.UNKNOWN_ERROR; + break; + case KMError.CRYPTO_NO_SUCH_ALGORITHM: + err = KMError.UNSUPPORTED_ALGORITHM; + break; + case KMError.UNSUPPORTED_INSTRUCTION: + case KMError.CMD_NOT_ALLOWED: + case KMError.SW_WRONG_LENGTH: + err = KMError.UNIMPLEMENTED; + break; + default: + break; + } + return err; + } + + public short finish(short operationHandle, short data, byte[] signature, short inParams, short hwToken, short verToken, short expectedErr) { if(hwToken == 0) { hwToken = KMHardwareAuthToken.instance(); } @@ -2637,16 +2828,27 @@ public short finish(short operationHandle, short data, byte[] signature, short i 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; + short ret; + short error; + if (expectedErr == KMError.OK) { + 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()); + } else { + ret = KMInteger.exp(); + } ret = decoder.decode(ret, respBuf, (short) 0, len); - short error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); - Assert.assertEquals(error, KMError.OK); + if (expectedErr == KMError.OK) { + error = KMInteger.cast(KMArray.cast(ret).get((short)0)).getShort(); + } else { + error = KMInteger.cast(ret).getShort(); + error = translateExtendedErrorCodes(error); + } + Assert.assertEquals(error, expectedErr); return ret; } public short update(short operationHandle, short data, short inParams, short hwToken, short verToken) { diff --git a/Applet/src/com/android/javacard/keymaster/KMError.java b/Applet/src/com/android/javacard/keymaster/KMError.java index 8f842236..83eb8c7c 100644 --- a/Applet/src/com/android/javacard/keymaster/KMError.java +++ b/Applet/src/com/android/javacard/keymaster/KMError.java @@ -20,100 +20,100 @@ * positive unlike negative values in keymaster hal. */ public class KMError { - public static short OK = 0; - public static short ROOT_OF_TRUST_ALREADY_SET = 1; - public static short UNSUPPORTED_PURPOSE = 2; - public static short INCOMPATIBLE_PURPOSE = 3; - public static short UNSUPPORTED_ALGORITHM = 4; - public static short INCOMPATIBLE_ALGORITHM = 5; - public static short UNSUPPORTED_KEY_SIZE = 6; - public static short UNSUPPORTED_BLOCK_MODE = 7; - public static short INCOMPATIBLE_BLOCK_MODE = 8; - public static short UNSUPPORTED_MAC_LENGTH = 9; - public static short UNSUPPORTED_PADDING_MODE = 10; - public static short INCOMPATIBLE_PADDING_MODE = 11; - public static short UNSUPPORTED_DIGEST = 12; - public static short INCOMPATIBLE_DIGEST = 13; - public static short INVALID_EXPIRATION_TIME = 14; - public static short INVALID_USER_ID = 15; - public static short INVALID_AUTHORIZATION_TIMEOUT = 16; - public static short UNSUPPORTED_KEY_FORMAT = 17; - public static short INCOMPATIBLE_KEY_FORMAT = 18; - public static short UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM = 19; + public static final short OK = 0; + public static final short ROOT_OF_TRUST_ALREADY_SET = 1; + public static final short UNSUPPORTED_PURPOSE = 2; + public static final short INCOMPATIBLE_PURPOSE = 3; + public static final short UNSUPPORTED_ALGORITHM = 4; + public static final short INCOMPATIBLE_ALGORITHM = 5; + public static final short UNSUPPORTED_KEY_SIZE = 6; + public static final short UNSUPPORTED_BLOCK_MODE = 7; + public static final short INCOMPATIBLE_BLOCK_MODE = 8; + public static final short UNSUPPORTED_MAC_LENGTH = 9; + public static final short UNSUPPORTED_PADDING_MODE = 10; + public static final short INCOMPATIBLE_PADDING_MODE = 11; + public static final short UNSUPPORTED_DIGEST = 12; + public static final short INCOMPATIBLE_DIGEST = 13; + public static final short INVALID_EXPIRATION_TIME = 14; + public static final short INVALID_USER_ID = 15; + public static final short INVALID_AUTHORIZATION_TIMEOUT = 16; + public static final short UNSUPPORTED_KEY_FORMAT = 17; + public static final short INCOMPATIBLE_KEY_FORMAT = 18; + public static final short UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM = 19; /** For PKCS8 & PKCS12 */ - public static short UNSUPPORTED_KEY_VERIFICATION_ALGORITHM = 20; + public static final short UNSUPPORTED_KEY_VERIFICATION_ALGORITHM = 20; /** For PKCS8 & PKCS12 */ - public static short INVALID_INPUT_LENGTH = 21; + public static final short INVALID_INPUT_LENGTH = 21; - public static short KEY_EXPORT_OPTIONS_INVALID = 22; - public static short DELEGATION_NOT_ALLOWED = 23; - public static short KEY_NOT_YET_VALID = 24; - public static short KEY_EXPIRED = 25; - public static short KEY_USER_NOT_AUTHENTICATED = 26; - public static short OUTPUT_PARAMETER_NULL = 27; - public static short INVALID_OPERATION_HANDLE = 28; - public static short INSUFFICIENT_BUFFER_SPACE = 29; - public static short VERIFICATION_FAILED = 30; - public static short TOO_MANY_OPERATIONS = 31; - public static short UNEXPECTED_NULL_POINTER = 32; - public static short INVALID_KEY_BLOB = 33; - public static short IMPORTED_KEY_NOT_ENCRYPTED = 34; - public static short IMPORTED_KEY_DECRYPTION_FAILED = 35; - public static short IMPORTED_KEY_NOT_SIGNED = 36; - public static short IMPORTED_KEY_VERIFICATION_FAILED = 37; - public static short INVALID_ARGUMENT = 38; - public static short UNSUPPORTED_TAG = 39; - public static short INVALID_TAG = 40; - public static short MEMORY_ALLOCATION_FAILED = 41; - public static short IMPORT_PARAMETER_MISMATCH = 44; - public static short SECURE_HW_ACCESS_DENIED = 45; - public static short OPERATION_CANCELLED = 46; - public static short CONCURRENT_ACCESS_CONFLICT = 47; - public static short SECURE_HW_BUSY = 48; - public static short SECURE_HW_COMMUNICATION_FAILED = 49; - public static short UNSUPPORTED_EC_FIELD = 50; - public static short MISSING_NONCE = 51; - public static short INVALID_NONCE = 52; - public static short MISSING_MAC_LENGTH = 53; - public static short KEY_RATE_LIMIT_EXCEEDED = 54; - public static short CALLER_NONCE_PROHIBITED = 55; - public static short KEY_MAX_OPS_EXCEEDED = 56; - public static short INVALID_MAC_LENGTH = 57; - public static short MISSING_MIN_MAC_LENGTH = 58; - public static short UNSUPPORTED_MIN_MAC_LENGTH = 59; - public static short UNSUPPORTED_KDF = 60; - public static short UNSUPPORTED_EC_CURVE = 61; - public static short KEY_REQUIRES_UPGRADE = 62; - public static short ATTESTATION_CHALLENGE_MISSING = 63; - public static short KEYMASTER_NOT_CONFIGURED = 64; - public static short ATTESTATION_APPLICATION_ID_MISSING = 65; - public static short CANNOT_ATTEST_IDS = 66; - public static short ROLLBACK_RESISTANCE_UNAVAILABLE = 67; - public static short HARDWARE_TYPE_UNAVAILABLE = 68; - public static short PROOF_OF_PRESENCE_REQUIRED = 69; - public static short CONCURRENT_PROOF_OF_PRESENCE_REQUESTED = 70; - public static short NO_USER_CONFIRMATION = 71; - public static short DEVICE_LOCKED = 72; - public static short EARLY_BOOT_ENDED = 73; - public static short UNIMPLEMENTED = 100; - public static short VERSION_MISMATCH = 101; - public static short UNKNOWN_ERROR = 1000; + public static final short KEY_EXPORT_OPTIONS_INVALID = 22; + public static final short DELEGATION_NOT_ALLOWED = 23; + public static final short KEY_NOT_YET_VALID = 24; + public static final short KEY_EXPIRED = 25; + public static final short KEY_USER_NOT_AUTHENTICATED = 26; + public static final short OUTPUT_PARAMETER_NULL = 27; + public static final short INVALID_OPERATION_HANDLE = 28; + public static final short INSUFFICIENT_BUFFER_SPACE = 29; + public static final short VERIFICATION_FAILED = 30; + public static final short TOO_MANY_OPERATIONS = 31; + public static final short UNEXPECTED_NULL_POINTER = 32; + public static final short INVALID_KEY_BLOB = 33; + public static final short IMPORTED_KEY_NOT_ENCRYPTED = 34; + public static final short IMPORTED_KEY_DECRYPTION_FAILED = 35; + public static final short IMPORTED_KEY_NOT_SIGNED = 36; + public static final short IMPORTED_KEY_VERIFICATION_FAILED = 37; + public static final short INVALID_ARGUMENT = 38; + public static final short UNSUPPORTED_TAG = 39; + public static final short INVALID_TAG = 40; + public static final short MEMORY_ALLOCATION_FAILED = 41; + public static final short IMPORT_PARAMETER_MISMATCH = 44; + public static final short SECURE_HW_ACCESS_DENIED = 45; + public static final short OPERATION_CANCELLED = 46; + public static final short CONCURRENT_ACCESS_CONFLICT = 47; + public static final short SECURE_HW_BUSY = 48; + public static final short SECURE_HW_COMMUNICATION_FAILED = 49; + public static final short UNSUPPORTED_EC_FIELD = 50; + public static final short MISSING_NONCE = 51; + public static final short INVALID_NONCE = 52; + public static final short MISSING_MAC_LENGTH = 53; + public static final short KEY_RATE_LIMIT_EXCEEDED = 54; + public static final short CALLER_NONCE_PROHIBITED = 55; + public static final short KEY_MAX_OPS_EXCEEDED = 56; + public static final short INVALID_MAC_LENGTH = 57; + public static final short MISSING_MIN_MAC_LENGTH = 58; + public static final short UNSUPPORTED_MIN_MAC_LENGTH = 59; + public static final short UNSUPPORTED_KDF = 60; + public static final short UNSUPPORTED_EC_CURVE = 61; + public static final short KEY_REQUIRES_UPGRADE = 62; + public static final short ATTESTATION_CHALLENGE_MISSING = 63; + public static final short KEYMASTER_NOT_CONFIGURED = 64; + public static final short ATTESTATION_APPLICATION_ID_MISSING = 65; + public static final short CANNOT_ATTEST_IDS = 66; + public static final short ROLLBACK_RESISTANCE_UNAVAILABLE = 67; + public static final short HARDWARE_TYPE_UNAVAILABLE = 68; + public static final short PROOF_OF_PRESENCE_REQUIRED = 69; + public static final short CONCURRENT_PROOF_OF_PRESENCE_REQUESTED = 70; + public static final short NO_USER_CONFIRMATION = 71; + public static final short DEVICE_LOCKED = 72; + public static final short EARLY_BOOT_ENDED = 73; + public static final short UNIMPLEMENTED = 100; + public static final short VERSION_MISMATCH = 101; + public static final short UNKNOWN_ERROR = 1000; //Extended errors - public static short SW_CONDITIONS_NOT_SATISFIED = 10001; - public static short UNSUPPORTED_CLA = 10002; - public static short INVALID_P1P2 = 10003; - public static short UNSUPPORTED_INSTRUCTION = 10004; - public static short CMD_NOT_ALLOWED = 10005; - public static short SW_WRONG_LENGTH = 10006; - public static short INVALID_DATA = 10007; + public static final short SW_CONDITIONS_NOT_SATISFIED = 10001; + public static final short UNSUPPORTED_CLA = 10002; + public static final short INVALID_P1P2 = 10003; + public static final short UNSUPPORTED_INSTRUCTION = 10004; + public static final short CMD_NOT_ALLOWED = 10005; + public static final short SW_WRONG_LENGTH = 10006; + public static final short INVALID_DATA = 10007; //Crypto errors - public static short CRYPTO_ILLEGAL_USE = 10008; - public static short CRYPTO_ILLEGAL_VALUE = 10009; - public static short CRYPTO_INVALID_INIT = 10010; - public static short CRYPTO_NO_SUCH_ALGORITHM = 10011; - public static short CRYPTO_UNINITIALIZED_KEY = 10012; + public static final short CRYPTO_ILLEGAL_USE = 10008; + public static final short CRYPTO_ILLEGAL_VALUE = 10009; + public static final short CRYPTO_INVALID_INIT = 10010; + public static final short CRYPTO_NO_SUCH_ALGORITHM = 10011; + public static final short CRYPTO_UNINITIALIZED_KEY = 10012; //Generic Unknown error. - public static short GENERIC_UNKNOWN_ERROR = 10013; + public static final short GENERIC_UNKNOWN_ERROR = 10013; } diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index b30e63c2..284a10c2 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -1672,6 +1672,7 @@ private void finishDecryptOperation(KMOperationState op, byte[] scratchPad) { Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0); if (op.getPadding() == KMType.PADDING_NONE && len != 256) KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + System.out.println("Heap Index:"+repository.alloc((short)0)); len = op.getOperation() .finish( From 530cb6755addd46f0d7cd4598a1894dd023d7107 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Tue, 9 Feb 2021 18:27:03 +0530 Subject: [PATCH 96/99] Fixed the issue with RSA private and public key buffer while copying --- .../keymaster/KMAndroidSEProvider.java | 23 +- .../javacard/keymaster/KMJCardSimulator.java | 208 +++++++----------- .../javacard/keymaster/KMOperationImpl.java | 12 - .../javacard/test/KMFunctionalTest.java | 39 +--- .../javacard/keymaster/KMKeymasterApplet.java | 6 +- 5 files changed, 102 insertions(+), 186 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java index 6a5a0671..78b90b57 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java @@ -112,6 +112,7 @@ public class KMAndroidSEProvider 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 short RSA_KEY_SIZE = 256; public static final short CERT_CHAIN_MAX_SIZE = 2500;//First 2 bytes for length. final byte[] CIPHER_ALGS = { @@ -532,13 +533,27 @@ public void createAsymmetricKey(byte alg, byte[] privKeyBuf, short pubModStart, short pubModLength, short[] lengths) { switch (alg) { case KMType.RSA: + if (RSA_KEY_SIZE != privKeyLength || RSA_KEY_SIZE != pubModLength) { + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } 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) { + //Copy exponent. + Util.arrayFillNonAtomic(tmpArray, (short) 0, RSA_KEY_SIZE, (byte) 0); + lengths[0] = privKey.getExponent(tmpArray, (short)0); + if (lengths[0] > privKeyLength) CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } + Util.arrayFillNonAtomic(privKeyBuf, privKeyStart, privKeyLength, (byte)0); + Util.arrayCopyNonAtomic(tmpArray, (short)0, + privKeyBuf, (short)(privKeyStart + privKeyLength - lengths[0]), lengths[0]); + //Copy modulus + Util.arrayFillNonAtomic(tmpArray, (short) 0, RSA_KEY_SIZE, (byte) 0); + lengths[1] = privKey.getModulus(tmpArray, (short)0); + if (lengths[1] > pubModLength) + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + Util.arrayFillNonAtomic(pubModBuf, pubModStart, pubModLength, (byte)0); + Util.arrayCopyNonAtomic(tmpArray, (short)0, + pubModBuf, (short)(pubModStart + pubModLength - lengths[1]), lengths[1]); break; case KMType.EC: KeyPair ecKey = createECKeyPair(); diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java index 6b0596ae..d97acc6d 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java @@ -72,6 +72,7 @@ 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 = 2500;//First 2 bytes for length. + private static final short RSA_KEY_SIZE = 256; public static boolean jcardSim = false; @@ -166,9 +167,6 @@ public AESKey createAESKey(byte[] buf, short startOff, short length) { key = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_256, false); key.setKey(buf, (short) startOff); } - // byte[] buffer = new byte[length]; - // Util.arrayCopyNonAtomic(buf, startOff, buffer, (short)0,length); - // print("AES Key", buffer); return key; } @@ -221,13 +219,27 @@ public void createAsymmetricKey(byte alg, byte[] privKeyBuf, short privKeyStart, byte[] pubModBuf, short pubModStart, short pubModLength, short[] lengths){ switch (alg){ case KMType.RSA: + if (RSA_KEY_SIZE != privKeyLength || RSA_KEY_SIZE != pubModLength) { + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } 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){ + //Copy exponent. + byte[] exp = new byte[RSA_KEY_SIZE]; + lengths[0] = privKey.getExponent(exp, (short)0); + if (lengths[0] > privKeyLength) CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } + Util.arrayFillNonAtomic(privKeyBuf, privKeyStart, privKeyLength, (byte)0); + Util.arrayCopyNonAtomic(exp, (short)0, + privKeyBuf, (short)(privKeyStart + privKeyLength - lengths[0]), lengths[0]); + //Copy modulus + byte[] mod = new byte[RSA_KEY_SIZE]; + lengths[1] = privKey.getModulus(mod, (short)0); + if (lengths[1] > pubModLength) + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + Util.arrayFillNonAtomic(pubModBuf, pubModStart, pubModLength, (byte)0); + Util.arrayCopyNonAtomic(mod, (short)0, + pubModBuf, (short)(pubModStart + pubModLength - lengths[1]), lengths[1]); break; case KMType.EC: KeyPair ecKey = createECKeyPair(); @@ -312,20 +324,6 @@ public short aesGCMEncrypt( if(keyLen != 32 && keyLen != 16){ CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } - /*byte[] keyMaterial = new byte[key]; - short keySize = 16; - if(key.getSize() == 128){ - keyMaterial = new byte[16]; - }else if(key.getSize() == 256){ - keyMaterial = new byte[32]; - keySize = 32; - } - key.getKey(keyMaterial,(short)0); - - */ - - //print("KeyMaterial Enc", keyMaterial); - //print("Authdata Enc", authData, authDataStart, authDataLen); java.security.Key aesKey = new SecretKeySpec(keyBuf,keyStart,keyLen, "AES"); // Create the cipher javax.crypto.Cipher cipher = null; @@ -402,73 +400,67 @@ public boolean aesGCMDecrypt( short authDataLen, byte[] authTag, short authTagStart, - short authTagLen) { - //Create the sun jce compliant aes key - if(keyLen != 32 && keyLen != 16){ + short authTagLen) { + // Create the sun jce compliant aes key + if (keyLen != 32 && keyLen != 16) { CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } - /*byte[] keyMaterial = new byte[16]; - short keySize = 16; - if(key.getSize() == 128){ - keyMaterial = new byte[16]; - }else if(key.getSize() == 256){ - keyMaterial = new byte[32]; - keySize = 32; - } - key.getKey(keyMaterial,(short)0); - - */ - //print("KeyMaterial Dec", keyMaterial); - //print("Authdata Dec", authData, authDataStart, authDataLen); - java.security.Key aesKey = new SecretKeySpec(keyBuf,keyStart,keyLen, "AES"); + java.security.Key aesKey = new SecretKeySpec(keyBuf, keyStart, keyLen, + "AES"); // Create the cipher - javax.crypto.Cipher cipher = null; - try { - cipher = javax.crypto.Cipher.getInstance("AES/GCM/NoPadding", "SunJCE"); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - } catch (NoSuchProviderException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.INVALID_INIT); - } catch (NoSuchPaddingException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - // Copy nonce - if(nonceLen != AES_GCM_NONCE_LENGTH){ - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - byte[] iv = new byte[AES_GCM_NONCE_LENGTH]; - Util.arrayCopyNonAtomic(nonce,nonceStart,iv,(short)0,AES_GCM_NONCE_LENGTH); - // Init Cipher - GCMParameterSpec spec = new GCMParameterSpec(authTagLen * 8, nonce,nonceStart,AES_GCM_NONCE_LENGTH); - try { - cipher.init(javax.crypto.Cipher.DECRYPT_MODE, aesKey, spec); - } catch (InvalidKeyException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.INVALID_INIT); - } catch (InvalidAlgorithmParameterException e) { - e.printStackTrace(); - CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - } - // Create auth data - byte[] aad = new byte[authDataLen]; - Util.arrayCopyNonAtomic(authData,authDataStart,aad,(short)0,authDataLen); - cipher.updateAAD(aad); - // Append the auth tag at the end of data - byte[] inputBuf = new byte[(short)(encSecretLen + authTagLen)]; - Util.arrayCopyNonAtomic(encSecret,encSecretStart,inputBuf,(short)0,encSecretLen); - Util.arrayCopyNonAtomic(authTag,authTagStart,inputBuf,encSecretLen,authTagLen); - // Decrypt + javax.crypto.Cipher cipher = null; + try { + cipher = javax.crypto.Cipher.getInstance("AES/GCM/NoPadding", "SunJCE"); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); + } catch (NoSuchProviderException e) { + e.printStackTrace(); + CryptoException.throwIt(CryptoException.INVALID_INIT); + } catch (NoSuchPaddingException e) { + e.printStackTrace(); + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } + // Copy nonce + if (nonceLen != AES_GCM_NONCE_LENGTH) { + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } + byte[] iv = new byte[AES_GCM_NONCE_LENGTH]; + Util.arrayCopyNonAtomic(nonce, nonceStart, iv, (short) 0, + AES_GCM_NONCE_LENGTH); + // Init Cipher + GCMParameterSpec spec = new GCMParameterSpec(authTagLen * 8, nonce, + nonceStart, AES_GCM_NONCE_LENGTH); + try { + cipher.init(javax.crypto.Cipher.DECRYPT_MODE, aesKey, spec); + } catch (InvalidKeyException e) { + e.printStackTrace(); + CryptoException.throwIt(CryptoException.INVALID_INIT); + } catch (InvalidAlgorithmParameterException e) { + e.printStackTrace(); + CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); + } + // Create auth data + byte[] aad = new byte[authDataLen]; + Util.arrayCopyNonAtomic(authData, authDataStart, aad, (short) 0, + authDataLen); + cipher.updateAAD(aad); + // Append the auth tag at the end of data + byte[] inputBuf = new byte[(short) (encSecretLen + authTagLen)]; + Util.arrayCopyNonAtomic(encSecret, encSecretStart, inputBuf, (short) 0, + encSecretLen); + Util.arrayCopyNonAtomic(authTag, authTagStart, inputBuf, encSecretLen, + authTagLen); + // Decrypt short len = 0; - byte[] outputBuf = new byte[cipher.getOutputSize((short)inputBuf.length)]; + byte[] outputBuf = new byte[cipher.getOutputSize((short) inputBuf.length)]; try { - len = (short)(cipher.doFinal(inputBuf,(short)0,(short)inputBuf.length,outputBuf,(short)0)); - }catch(AEADBadTagException e){ + len = (short) (cipher.doFinal(inputBuf, (short) 0, + (short) inputBuf.length, outputBuf, (short) 0)); + } catch (AEADBadTagException e) { e.printStackTrace(); return false; - }catch (ShortBufferException e) { + } catch (ShortBufferException e) { e.printStackTrace(); CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } catch (IllegalBlockSizeException e) { @@ -478,8 +470,8 @@ public boolean aesGCMDecrypt( e.printStackTrace(); CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } - //Copy the decrypted data - Util.arrayCopyNonAtomic(outputBuf, (short)0,secret,secretStart,len); + // Copy the decrypted data + Util.arrayCopyNonAtomic(outputBuf, (short) 0, secret, secretStart, len); return true; } @@ -641,50 +633,7 @@ public KMOperation initAsymmetricOperation(byte purpose, byte alg, byte padding, CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); return null; } -/* - @Override - public short updateOperation(short opHandle, byte[] inputDataBuf, short inputDataStart, short inputDataLength, byte[] outputDataBuf, short outputDataStart) { - Object op = findOperation(opHandle); - if(op instanceof Signature ){ - ((Signature)op).update(inputDataBuf,inputDataStart,inputDataLength); - return 0; - }else{ - return ((KMCipher)op).update(inputDataBuf,inputDataStart,inputDataLength,outputDataBuf,outputDataStart); - } - } - @Override - public short finishOperation(short opHandle, byte[] inputDataBuf, short inputDataStart, short inputDataLength, byte[] outputDataBuf, short outputDataStart) { - Object op = findOperation(opHandle); - short ret = 0; - if(op instanceof Signature ){ - ret = ((Signature)op).sign(inputDataBuf,inputDataStart,inputDataLength,outputDataBuf,outputDataStart); - }else{ - ret = ((KMCipher)op).doFinal(inputDataBuf,inputDataStart,inputDataLength,outputDataBuf,outputDataStart); - } - removeOperation(opHandle); - return ret; - } - - @Override - public void abortOperation(short opHandle) { - removeOperation(opHandle); - } - - @Override - public void updateAAD(short opHandle, byte[] dataBuf, short dataStart, short dataLength) { - KMCipher aesGcm = (KMCipher) findOperation(opHandle); - aesGcm.updateAAD(dataBuf, dataStart, dataLength); - } - - @Override - public void getAESGCMOutputSize(short opHandle, short dataSize, short macLength) { - KMCipher aesGcm = (KMCipher) findOperation(opHandle); - aesGcm.getAesGcmOutputSize(dataSize, 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); @@ -783,12 +732,7 @@ public Signature createRsaSigner(short digest, short padding, byte[] secret, (padding == KMType.RSA_PKCS1_1_5_SIGN && digest == KMType.DIGEST_NONE)) { return createNoDigestSigner(padding,secret, secretStart, secretLength, modBuffer, modOff, modLength); - }/* - 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 rsaSigner = Signature.getInstance((byte)alg, false); RSAPrivateKey key = (RSAPrivateKey) KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PRIVATE, KeyBuilder.LENGTH_RSA_2048, false); key.setExponent(secret,secretStart,secretLength); diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMOperationImpl.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMOperationImpl.java index 8379bfae..78c01302 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMOperationImpl.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMOperationImpl.java @@ -41,21 +41,9 @@ public short update(byte[] inputDataBuf, short inputDataStart, short inputDataLe signature.update(inputDataBuf,inputDataStart,inputDataLength); return 0; } - - - 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()); - } - @Override public short finish(byte[] inputDataBuf, short inputDataStart, short inputDataLength, byte[] outputDataBuf, short outputDataStart) { - print(inputDataBuf, inputDataStart, inputDataLength); return cipher.doFinal(inputDataBuf,inputDataStart,inputDataLength,outputDataBuf,outputDataStart); } diff --git a/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java b/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java index 3b0797ea..1e946df7 100644 --- a/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java +++ b/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java @@ -2092,37 +2092,6 @@ public short generateRandom(short upperBound) { return int_random; } - @Test - public void JCardTestRsaPkcs1() { - //Testing with Only Javacard APIs - byte[] message = { - 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, - 0x21 }; - for (int i = 0; i < 500; i++) { - byte[] out = new byte[256]; - byte[] dplain = new byte[256]; - KeyPair rsaKey = new KeyPair(KeyPair.ALG_RSA, KeyBuilder.LENGTH_RSA_2048); - rsaKey.genKeyPair(); - Cipher rsaCipher = Cipher.getInstance(Cipher.ALG_RSA_PKCS1, false); - RSAPublicKey key = (RSAPublicKey) rsaKey.getPublic(); - rsaCipher.init(key, Cipher.MODE_ENCRYPT); - - short outlen = rsaCipher.doFinal(message, (short) 0, - (short) message.length, out, (short) 0); - Assert.assertEquals(outlen, 256); - - RSAPrivateKey privKey = (RSAPrivateKey) rsaKey.getPrivate(); - rsaCipher.init(privKey, Cipher.MODE_DECRYPT); - short d_outlen = rsaCipher.doFinal(out, (short) 0, outlen, dplain, - (short) 0); - Assert.assertEquals(d_outlen, message.length); - byte[] plain = new byte[d_outlen]; - Util.arrayCopyNonAtomic(dplain, (short) 0, plain, (short) 0, d_outlen); - - Assert.assertTrue(Arrays.equals(message, plain)); - } - } - @Test public void testVtsRsaPkcs1Success() { init(); @@ -2146,11 +2115,10 @@ public void testVtsRsaPkcs1Success() { KMType.RSA_PKCS1_1_5_ENCRYPT); byte[] cipherText2 = EncryptMessage(message, pkcs1Params, keyBlob); Assert.assertEquals((2048 / 8), cipherText2.length); - System.out.println("stage-2"); + // PKCS1 v1.5 randomizes padding so every result should be different. Assert.assertFalse(Arrays.equals(cipherText1, cipherText2)); - print(cipherText1, (short) 0, (short) cipherText1.length); pkcs1Params = getRsaParams(KMType.DIGEST_NONE, KMType.RSA_PKCS1_1_5_ENCRYPT); byte[] plainText = DecryptMessage(cipherText1, pkcs1Params, keyBlob); @@ -2171,7 +2139,6 @@ public void testVtsRsaPkcs1Success() { short ret = begin(KMType.DECRYPT, KMByteBlob.instance(keyBlob, (short) 0, (short) keyBlob.length), KMKeyParameters.instance(pkcs1Params), (short) 0); - System.out.println("stage-4"); // Get the operation handle. short opHandle = KMArray.cast(ret).get((short) 2); @@ -2179,14 +2146,12 @@ public void testVtsRsaPkcs1Success() { KMInteger.cast(opHandle).getValue(opHandleBuf, (short) 0, (short) opHandleBuf.length); opHandle = KMInteger.uint_64(opHandleBuf, (short) 0); - System.out.println("stage-5"); + short dataPtr = KMByteBlob.instance(cipherText1, (short) 0, (short) cipherText1.length); // Finish should return UNKNOWN_ERROR. ret = finish(opHandle, dataPtr, null, (short) 0, (short) 0, (short) 0, KMError.UNKNOWN_ERROR); - System.out.println("stage-6"); - System.out.println("Count of i:" + i); } cleanUp(); } diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 284a10c2..61bcf931 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -538,6 +538,11 @@ private void resetData() { data[index] = KMType.INVALID_VALUE; index++; } + index = 0; + while (index < tmpVariables.length) { + tmpVariables[index] = KMType.INVALID_VALUE; + index++; + } } /** Sends a response, may be extended response, as requested by the command. */ public static void sendOutgoing(APDU apdu) { @@ -1672,7 +1677,6 @@ private void finishDecryptOperation(KMOperationState op, byte[] scratchPad) { Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0); if (op.getPadding() == KMType.PADDING_NONE && len != 256) KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - System.out.println("Heap Index:"+repository.alloc((short)0)); len = op.getOperation() .finish( From d4928a79acb545126a2d637d013daf9cd921f5f9 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Tue, 9 Feb 2021 20:41:30 +0530 Subject: [PATCH 97/99] Added testDesEcbPkcs7PaddingCorrupted test function --- .../javacard/test/KMFunctionalTest.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java b/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java index 1e946df7..2f6a9ba6 100644 --- a/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java +++ b/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java @@ -2092,6 +2092,50 @@ public short generateRandom(short upperBound) { return int_random; } + @Test + public void testDesEcbPkcs7PaddingCorrupted() { + init(); + short desKey = generateAesDesKey(KMType.DES, (short) 168, null, null, false); + short desKeyPtr = KMArray.cast(desKey).get((short) 1); + byte[] keyBlob = new byte[KMByteBlob.cast(desKeyPtr).length()]; + Util.arrayCopyNonAtomic(KMByteBlob.cast(desKeyPtr).getBuffer(), KMByteBlob + .cast(desKeyPtr).getStartOff(), keyBlob, (short) 0, + (short) keyBlob.length); + + byte[] message = { + 0x61 }; + short desPkcs7Params = getAesDesParams(KMType.DES, KMType.ECB, + KMType.PKCS7, null); + byte[] cipherText1 = EncryptMessage(message, desPkcs7Params, keyBlob); + Assert.assertEquals(8, cipherText1.length); + Assert.assertFalse(Arrays.equals(message, cipherText1)); + + // Corrupt the cipher text. + ++cipherText1[(cipherText1.length / 2)]; + + // Decrypt operation + // Begin + desPkcs7Params = getAesDesParams(KMType.DES, KMType.ECB, KMType.PKCS7, null); + + short ret = begin(KMType.DECRYPT, + KMByteBlob.instance(keyBlob, (short) 0, (short) keyBlob.length), + KMKeyParameters.instance(desPkcs7Params), (short) 0); + // Get the operation handle. + short opHandle = KMArray.cast(ret).get((short) 2); + byte[] opHandleBuf = new byte[KMRepository.OPERATION_HANDLE_SIZE]; + KMInteger.cast(opHandle).getValue(opHandleBuf, (short) 0, + (short) opHandleBuf.length); + opHandle = KMInteger.uint_64(opHandleBuf, (short) 0); + + // Finish + short dataPtr = KMByteBlob.instance(cipherText1, (short) 0, + (short) cipherText1.length); + opHandle = KMInteger.uint_64(opHandleBuf, (short) 0); + ret = finish(opHandle, dataPtr, null, (short) 0, (short) 0, (short) 0, + KMError.INVALID_ARGUMENT); + cleanUp(); + } + @Test public void testVtsRsaPkcs1Success() { init(); From 182ca2621850b39e98624cb87c278fc77d787067 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Tue, 9 Feb 2021 23:30:58 +0530 Subject: [PATCH 98/99] Removed unused imports --- .../com/android/javacard/test/KMFunctionalTest.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java b/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java index 2f6a9ba6..a6308513 100644 --- a/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java +++ b/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java @@ -17,8 +17,6 @@ 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; @@ -41,20 +39,11 @@ import com.android.javacard.keymaster.KMRepository; import com.android.javacard.keymaster.KMType; import com.android.javacard.keymaster.KMVerificationToken; -//import com.licel.jcardsim.bouncycastle.crypto.Digest; import com.licel.jcardsim.smartcardio.CardSimulator; import com.licel.jcardsim.utils.AIDUtil; import javacard.framework.AID; import javacard.framework.Util; -import javacard.security.KeyBuilder; -import javacard.security.KeyPair; -import javacard.security.RSAPrivateKey; -import javacard.security.RSAPublicKey; -import javacard.security.Signature; -import javacardx.crypto.Cipher; - -import java.security.spec.PKCS8EncodedKeySpec; import java.util.Arrays; import java.util.Random; From c766d68fb5633950208254c015125b75087eb73c Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Wed, 10 Feb 2021 01:11:05 +0530 Subject: [PATCH 99/99] Removed unused/commented code. --- .../keymaster/KMAttestationCertImpl.java | 21 ---------------- .../android/javacard/keymaster/KMUtils.java | 23 ------------------ .../keymaster/KMAttestationCertImpl.java | 20 ---------------- .../android/javacard/keymaster/KMCipher.java | 24 ------------------- .../javacard/keymaster/KMCipherImpl.java | 2 -- .../javacard/keymaster/KMJCardSimulator.java | 5 ---- .../android/javacard/keymaster/KMUtils.java | 23 ------------------ .../javacard/keymaster/KMKeymasterApplet.java | 16 ------------- 8 files changed, 134 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java index 6025feef..637a2fba 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -127,7 +127,6 @@ public static KMAttestationCert instance(boolean rsaCert) { } private static void init() { - // if (repo == null) repo = KMRepository.instance(); stack = null; stackPtr = 0; certStart = 0; @@ -283,7 +282,6 @@ private static void pushTbsCert(boolean rsaCert) { 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(), @@ -304,23 +302,6 @@ private static void pushTbsCert(boolean rsaCert) { private static void pushExtensions() { short last = stackPtr; - // byte keyusage = 0; - // byte unusedBits = 8; - /* - 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)); @@ -565,7 +546,6 @@ private static void pushTag(short tag) { private static void pushRoT() { short last = stackPtr; // verified boot hash - // pushOctetString(repo.verifiedBootHash, (short) 0, (short) repo.verifiedBootHash.length); pushOctetString( KMByteBlob.cast(verifiedHash).getBuffer(), KMByteBlob.cast(verifiedHash).getStartOff(), @@ -670,7 +650,6 @@ private static void pushEnumTag(short tagId, byte val) { 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 diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java index 7b4352f8..65e83415 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java @@ -347,29 +347,6 @@ public static void shiftRight(byte[] buf, short start) { } } - - // 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; diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java index 5be20599..18e67e72 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -121,7 +121,6 @@ public static KMAttestationCert instance(boolean rsaCert) { } private static void init() { - // if (repo == null) repo = KMRepository.instance(); stack = null; stackPtr = 0; certStart = 0; @@ -277,7 +276,6 @@ private static void pushTbsCert(boolean rsaCert) { 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(), @@ -298,23 +296,6 @@ private static void pushTbsCert(boolean rsaCert) { private static void pushExtensions() { short last = stackPtr; - // byte keyusage = 0; - // byte unusedBits = 8; - /* - 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)); @@ -559,7 +540,6 @@ private static void pushTag(short tag) { private static void pushRoT() { short last = stackPtr; // verified boot hash - // pushOctetString(repo.verifiedBootHash, (short) 0, (short) repo.verifiedBootHash.length); pushOctetString( KMByteBlob.cast(verifiedHash).getBuffer(), KMByteBlob.cast(verifiedHash).getStartOff(), diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipher.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipher.java index 017a8398..3e67ed5e 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipher.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipher.java @@ -16,30 +16,6 @@ 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); diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipherImpl.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipherImpl.java index 7a1df761..bc07be8d 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipherImpl.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipherImpl.java @@ -30,7 +30,6 @@ public class KMCipherImpl extends KMCipher{ private short cipherAlg; private short padding; private short mode; - private boolean verificationFlag; private short blockMode; KMCipherImpl(Cipher c){ cipher = c; @@ -59,7 +58,6 @@ public short doFinal(byte[] buffer, short startOff, short length, byte[] scratch 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(); diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java index d97acc6d..664ade77 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java @@ -156,7 +156,6 @@ public AESKey createAESKey(short keysize) { return createAESKey(rndNum, (short)0, (short)rndNum.length); } - // @Override public AESKey createAESKey(byte[] buf, short startOff, short length) { AESKey key = null; short keysize = (short)(length * 8); @@ -359,7 +358,6 @@ public short aesGCMEncrypt( // Create auth data byte[] aad = new byte[authDataLen]; Util.arrayCopyNonAtomic(authData,authDataStart,aad,(short)0,authDataLen); - // print("AAD", aad); cipher.updateAAD(aad); // Encrypt secret short len = 0; @@ -982,8 +980,6 @@ public KMCipher createAesGcmCipher(short mode, short tagLen, byte[] secret, shor //Create the sun jce compliant aes key byte[] keyMaterial = new byte[secretLength]; Util.arrayCopyNonAtomic(secret,secretStart,keyMaterial,(short)0,secretLength); - //print("KeyMaterial Enc", keyMaterial); - //print("Authdata Enc", authData, authDataStart, authDataLen); java.security.Key aesKey = new SecretKeySpec(keyMaterial,(short)0,keyMaterial.length, "AES"); // Create the cipher javax.crypto.Cipher cipher = null; @@ -1162,7 +1158,6 @@ public Signature createEcVerifier(short digest, byte[] pubKey, short pubKeyStart @Override public KMAttestationCert getAttestationCert(boolean rsaCert) { - //certBuilder.reset(); return KMAttestationCertImpl.instance(rsaCert); } diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java index 7b4352f8..65e83415 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java @@ -347,29 +347,6 @@ public static void shiftRight(byte[] buf, short start) { } } - - // 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; diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 61bcf931..abf6e670 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -520,7 +520,6 @@ private void processDeviceLockedCmd(APDU apdu) { data[VERIFICATION_TOKEN] = KMArray.cast(tmpVariables[0]).get((short) 1); validateVerificationToken(data[VERIFICATION_TOKEN], scratchPad); short verTime = KMVerificationToken.cast(data[VERIFICATION_TOKEN]).getTimestamp(); - // short lastDeviceLockedTime = KMInteger.uint_64(repository.deviceLockedTimestamp, (short)0); short lastDeviceLockedTime = repository.getDeviceTimeStamp(); if (KMInteger.compare(verTime, lastDeviceLockedTime) > 0) { Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 8, (byte) 0); @@ -3006,7 +3005,6 @@ private void importAESKey(byte[] scratchPad) { KMException.throwIt(KMError.IMPORT_PARAMETER_MISMATCH); } } else { - // add the key size to scratch pad // add the key size to scratchPad tmpVariables[5] = KMInteger.uint_16(KMByteBlob.cast(data[SECRET]).length()); tmpVariables[6] = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, tmpVariables[5]); @@ -3135,26 +3133,20 @@ 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(); // Argument 2 OS Patch level - // short osPatchExp = KMIntegerTag.exp(KMType.UINT_TAG); tmpVariables[1] = KMInteger.exp(); // 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[4] = KMByteBlob.exp(); // Argument 6 Verified Boot Hash - // short bootHashExp = KMByteBlob.exp(); tmpVariables[5] = KMByteBlob.exp(); // Argument 7 Verified Boot State - // short bootStateExp = KMEnum.instance(KMType.VERIFIED_BOOT_STATE); tmpVariables[6] = KMEnum.instance(KMType.VERIFIED_BOOT_STATE); // Argument 8 Device Locked - // short deviceLockedExp = KMEnum.instance(KMType.DEVICE_LOCKED); tmpVariables[7] = KMEnum.instance(KMType.DEVICE_LOCKED); // Array of expected arguments short argsProto = KMArray.instance((short) 8); @@ -3171,21 +3163,13 @@ private void processSetBootParamsCmd(APDU apdu) { //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); tmpVariables[1] = KMArray.cast(args).get((short) 1); - // short vendorPatchTagPtr = KMArray.cast(args).get((short) 2); tmpVariables[2] = KMArray.cast(args).get((short) 2); - // short BootPatchTagPtr = KMArray.cast(args).get((short) 3); tmpVariables[3] = KMArray.cast(args).get((short) 3); - // short verifiedBootKeyPtr = KMArray.cast(args).get((short) 4); tmpVariables[4] = KMArray.cast(args).get((short) 4); - // short verifiedBootHashPtr = KMArray.cast(args).get((short) 5); tmpVariables[5] = KMArray.cast(args).get((short) 5); - // 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);