diff --git a/Applet/AndroidSEProvider/build.xml b/Applet/AndroidSEProvider/build.xml index 04b1dee6..137c169a 100644 --- a/Applet/AndroidSEProvider/build.xml +++ b/Applet/AndroidSEProvider/build.xml @@ -1,58 +1,60 @@ - - + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - + - + - + - + @@ -60,18 +62,20 @@ + to="AndroidSE.\2" + casesensitive="yes"/> - - + + - - + + \ No newline at end of file diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAESKey.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAESKey.java index afdfb08e..cec6388e 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAESKey.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAESKey.java @@ -22,6 +22,7 @@ import javacard.security.AESKey; public class KMAESKey implements KMMasterKey { + private AESKey aesKey; public KMAESKey(AESKey key) { @@ -35,7 +36,7 @@ public void setKey(byte[] keyData, short kOff) { public AESKey getKey() { return aesKey; } - + public short getKeySizeBits() { return aesKey.getSize(); } diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java index bb6a2e86..7c6f31fe 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java @@ -21,19 +21,20 @@ public class KMAndroidSEApplet extends KMKeymasterApplet implements OnUpgradeListener { - KMAndroidSEApplet(){ - super(new KMAndroidSEProvider()); - } - /** - * 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]); - } + KMAndroidSEApplet() { + super(new KMAndroidSEProvider()); + } + + /** + * 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() { @@ -66,7 +67,7 @@ public Element onSave() { // Create element. Element element = UpgradeManager.createElement(Element.TYPE_SIMPLE, - primitiveCount, objectCount); + primitiveCount, objectCount); element.write(provisionStatus); element.write(keymasterState); repository.onSave(element); diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java index 78b90b57..369276c7 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java @@ -40,71 +40,74 @@ import com.android.javacard.keymaster.KMAESKey; import com.android.javacard.keymaster.KMAttestationKey; import com.android.javacard.keymaster.KMECPrivateKey; +import com.android.javacard.keymaster.KMError; +import com.android.javacard.keymaster.KMException; 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 // -------------------------------------------------------------- // 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 }; + (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 }; + (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 }; + (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 }; + (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 }; + (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 }; + (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 = 16; @@ -116,24 +119,24 @@ public class KMAndroidSEProvider implements KMSEProvider { 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, - 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, - KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA1, - Cipher.ALG_RSA_NOPAD, - AEADCipher.ALG_AES_GCM }; + 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, + KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA1, + Cipher.ALG_RSA_NOPAD, + AEADCipher.ALG_AES_GCM}; final byte[] SIG_ALGS = { - 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}; + 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}; // AESKey private AESKey aesKeys[]; @@ -213,8 +216,9 @@ public KMAndroidSEProvider() { // 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; } @@ -303,7 +307,7 @@ private Cipher getCipherInstance(byte alg) { } private byte getCipherAlgorithm(Cipher c) { - return c.getAlgorithm(); + return c.getAlgorithm(); } // Create a cipher instance of each algorithm once. @@ -511,18 +515,18 @@ public ECPrivateKey createEcKey(byte[] privBuffer, short privOff, 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; + 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; } @@ -532,42 +536,44 @@ public void createAsymmetricKey(byte alg, byte[] privKeyBuf, short privKeyStart, short privKeyLength, 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(); - //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(); - 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; + 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(); + //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(); + 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; } } @@ -575,18 +581,18 @@ public void createAsymmetricKey(byte alg, byte[] privKeyBuf, 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; + 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; } @@ -596,16 +602,16 @@ 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; + 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; } @@ -626,10 +632,10 @@ public void addRngEntropy(byte[] num, short offset, short length) { } 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) { + 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); } @@ -657,21 +663,21 @@ public short aesGCMEncrypt(byte[] aesKey, short aesKeyStart, short aesKeyLen, AESKey key = createAESKey(aesKey, aesKeyStart, aesKeyLen); return aesGCMEncrypt( - key, - secret, - secretStart, - secretLen, - encSecret, - encSecretStart, - nonce, - nonceStart, - nonceLen, - authData, - authDataStart, - authDataLen, - authTag, - authTagStart, - authTagLen); + key, + secret, + secretStart, + secretLen, + encSecret, + encSecretStart, + nonce, + nonceStart, + nonceLen, + authData, + authDataStart, + authDataLen, + authTag, + authTagStart, + authTagLen); } @Override @@ -696,7 +702,8 @@ public boolean aesGCMDecrypt(byte[] aesKey, short aesKeyStart, return verification; } - public HMACKey cmacKdf(KMPreSharedKey preSharedKey, 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 @@ -709,7 +716,7 @@ public HMACKey cmacKdf(KMPreSharedKey preSharedKey, byte[] label, short labelSta }; // byte final byte[] zero = { - 0 + 0 }; // [i] counter - 32 bits short iBufLen = 4; @@ -768,14 +775,14 @@ public short hmacSign(byte[] keyBuf, short keyStart, short keyLength, @Override public short hmacKDF(KMMasterKey masterkey, byte[] data, short dataStart, - short dataLength, byte[] signature, short signatureStart) { + 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)); + (short) (aesKey.getSize() / 8)); return hmacSign(key, data, dataStart, dataLength, signature, - signatureStart); + signatureStart); } finally { clean(); } @@ -796,107 +803,111 @@ public short rsaDecipherOAEP256(byte[] secret, short secretStart, byte[] inputDataBuf, short inputDataStart, short inputDataLength, byte[] outputDataBuf, short outputDataStart) { RSAPrivateKey key = (RSAPrivateKey) rsaKeyPair.getPrivate(); - key.setExponent(secret, (short)secretStart, (short)secretLength); - key.setModulus(modBuffer, (short)modOff, (short)modLength); + 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, + return rsaOaepDecipher.doFinal(inputDataBuf, (short) inputDataStart, (short) inputDataLength, outputDataBuf, (short) outputDataStart); } public short ecSign256(KMAttestationKey attestationKey, - byte[] inputDataBuf, short inputDataStart, short inputDataLength, - byte[] outputDataBuf, short outputDataStart) { + byte[] inputDataBuf, short inputDataStart, short inputDataLength, + byte[] outputDataBuf, short outputDataStart) { Signature.OneShot signer = null; try { signer = Signature.OneShot.open(MessageDigest.ALG_SHA_256, Signature.SIG_CIPHER_ECDSA, Cipher.PAD_NULL); - signer.init(((KMECPrivateKey)attestationKey).getPrivateKey(), Signature.MODE_SIGN); + signer.init(((KMECPrivateKey) attestationKey).getPrivateKey(), Signature.MODE_SIGN); return signer.sign(inputDataBuf, inputDataStart, inputDataLength, outputDataBuf, outputDataStart); } finally { - if (signer != null) + if (signer != null) { 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; + 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: - 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; + 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: + 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; } return -1; } private byte mapCipherAlg(byte alg, byte padding, byte blockmode, byte digest) { 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: { - if (digest == KMType.SHA2_256) - return KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA1; - else - KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM); - } - } - break; + 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: { + if (digest == KMType.SHA2_256) { + return KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA1; + } else { + KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM); + } + } + } + break; } return -1; } @@ -907,45 +918,45 @@ public Cipher createSymmetricCipher(short alg, short purpose, Key key = null; Cipher symmCipher = null; 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); - break; + 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); + break; } - short cipherAlg = mapCipherAlg((byte) alg, (byte) padding, (byte) blockMode, (byte)0); + 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: - 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: - // 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; + 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: + // 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; } @@ -953,8 +964,9 @@ public Cipher createSymmetricCipher(short alg, short purpose, 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) + 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)); @@ -968,33 +980,33 @@ public KMOperation initSymmetricOperation(byte purpose, byte alg, 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; + 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; } @@ -1018,55 +1030,10 @@ public Signature createRsaSigner(short digest, short padding, byte[] secret, return rsaSigner; } - public Signature createRsaVerifier(short digest, short padding, - 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) { - try { - byte cipherAlg = mapCipherAlg(KMType.RSA, (byte) padding, (byte) 0, (byte)digest); - // 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) { - byte cipherAlg = mapCipherAlg(KMType.RSA, (byte) padding, (byte) 0, (byte)digest); + 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); @@ -1086,17 +1053,6 @@ public Signature createEcSigner(short digest, byte[] secret, 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; - 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, @@ -1105,71 +1061,45 @@ public KMOperation initAsymmetricOperation(byte purpose, byte alg, 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; + 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.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: + KMException.throwIt(KMError.UNSUPPORTED_PURPOSE); + 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; + case KMType.SIGN: + Signature signer = createEcSigner(digest, privKeyBuf, privKeyStart, + privKeyLength); + opr = getOperationInstanceFromPool(); + JCSystem.beginTransaction(); + opr.setSignature(signer); + JCSystem.commitTransaction(); + break; + default: + KMException.throwIt(KMError.UNSUPPORTED_PURPOSE); + break; } } else { CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); @@ -1185,17 +1115,17 @@ public KMAttestationCert getAttestationCert(boolean rsaCert) { @Override public short cmacKDF(KMPreSharedKey pSharedKey, byte[] label, - short labelStart, short labelLen, byte[] context, short contextStart, - short contextLength, byte[] keyBuf, short keyStart) { + short labelStart, short labelLen, byte[] context, short contextStart, + short contextLength, byte[] keyBuf, short keyStart) { HMACKey key = cmacKdf(pSharedKey, label, labelStart, labelLen, context, - contextStart, contextLength); + contextStart, contextLength); return key.getKey(keyBuf, keyStart); } @Override public void clearCertificateChain() { JCSystem.beginTransaction(); - Util.arrayFillNonAtomic(certificateChain, (short)0, CERT_CHAIN_MAX_SIZE, (byte) 0); + Util.arrayFillNonAtomic(certificateChain, (short) 0, CERT_CHAIN_MAX_SIZE, (byte) 0); JCSystem.commitTransaction(); } @@ -1220,20 +1150,20 @@ public void persistPartialCertificateChain(byte[] buf, short offset, short len, JCSystem.beginTransaction(); Util.setShort(certificateChain, (short) 0, (short) (len + persistedLen)); Util.arrayCopyNonAtomic(buf, offset, certificateChain, - (short) (persistedLen+2), len); + (short) (persistedLen + 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); + 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); + return Util.getShort(certificateChain, (short) 0); } @Override @@ -1242,7 +1172,7 @@ public boolean isBootSignalEventSupported() { } @Override - public boolean isDeviceRebooted() { + public boolean isDeviceRebooted() { return false; } @@ -1270,7 +1200,7 @@ public void onRestore(Element element) { @Override public short getBackupPrimitiveByteCount() { short count = - (short) (KMAESKey.getBackupPrimitiveByteCount() + + (short) (KMAESKey.getBackupPrimitiveByteCount() + KMECPrivateKey.getBackupPrimitiveByteCount() + KMHmacKey.getBackupPrimitiveByteCount()); return count; @@ -1279,7 +1209,7 @@ public short getBackupPrimitiveByteCount() { @Override public short getBackupObjectCount() { short count = - (short) (1 /*Certificate chain */ + + (short) (1 /*Certificate chain */ + KMAESKey.getBackupObjectCount() + KMECPrivateKey.getBackupObjectCount() + KMHmacKey.getBackupObjectCount()); @@ -1287,7 +1217,7 @@ public short getBackupObjectCount() { } @Override - public boolean isUpgrading() { + public boolean isUpgrading() { return UpgradeManager.isUpgrading(); } @@ -1296,7 +1226,7 @@ public KMMasterKey createMasterKey(short keySizeBits) { try { if (masterKey == null) { AESKey key = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, - keySizeBits, false); + keySizeBits, false); masterKey = new KMAESKey(key); short keyLen = (short) (keySizeBits / 8); getTrueRandomNumber(tmpArray, (short) 0, keyLen); @@ -1310,7 +1240,7 @@ public KMMasterKey createMasterKey(short keySizeBits) { @Override public KMAttestationKey createAttestationKey(byte[] keyData, short offset, - short length) { + 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); @@ -1323,13 +1253,13 @@ public KMAttestationKey createAttestationKey(byte[] keyData, short offset, @Override public KMPreSharedKey createPresharedKey(byte[] keyData, short offset, short length) { - short lengthInBits = (short)(length * 8); + 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); + false); preSharedKey = new KMHmacKey(key); } preSharedKey.setKey(keyData, offset, length); diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java index 637a2fba..1e3eae79 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -31,50 +31,53 @@ // 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 + 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 + 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 + 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 + 0x06, 0x0A, 0X2B, 0X06, 0X01, 0X04, 0X01, (byte) 0XD6, 0X79, 0X02, 0X01, 0X11 }; 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, - 0x0A, - 0x06, - 0x08, - 0x2A, - (byte) 0x86, - 0x48, - (byte) 0xCE, - (byte) 0x3D, - 0x04, - 0x03, - 0x02 + 0x30, + 0x0A, + 0x06, + 0x08, + 0x2A, + (byte) 0x86, + 0x48, + (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 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 + 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 @@ -117,10 +120,13 @@ public class KMAttestationCertImpl implements KMAttestationCert { private static short issuer; private static short signPriv; - private KMAttestationCertImpl() {} + private KMAttestationCertImpl() { + } public static KMAttestationCert instance(boolean rsaCert) { - if (inst == null) inst = new KMAttestationCertImpl(); + if (inst == null) { + inst = new KMAttestationCertImpl(); + } init(); KMAttestationCertImpl.rsaCert = rsaCert; return inst; @@ -190,18 +196,19 @@ public KMAttestationCert notBefore(short obj, byte[] scratchpad) { @Override public KMAttestationCert notAfter(short usageExpiryTimeObj, - short certExpirtyTimeObj, byte[] scratchPad, short tmpVar) { + 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) + if (KMInteger.compare(usageExpiryTimeObj, tmpVar) >= 0) { usageExpiryTimeObj = KMUtils.convertToDate(usageExpiryTimeObj, scratchPad, - false); - else + false); + } else { usageExpiryTimeObj = KMUtils - .convertToDate(usageExpiryTimeObj, scratchPad, true); + .convertToDate(usageExpiryTimeObj, scratchPad, true); + } notAfter = usageExpiryTimeObj; } else { notAfter = certExpirtyTimeObj; @@ -211,8 +218,11 @@ public KMAttestationCert notAfter(short usageExpiryTimeObj, @Override public KMAttestationCert deviceLocked(boolean val) { - if (val) deviceLocked = (byte) 0xFF; - else deviceLocked = 0; + if (val) { + deviceLocked = (byte) 0xFF; + } else { + deviceLocked = 0; + } return this; } @@ -302,7 +312,9 @@ private static void pushTbsCert(boolean rsaCert) { private static void pushExtensions() { short last = stackPtr; - if (keyUsage != 0) pushKeyUsage(keyUsage, unusedBits); + if (keyUsage != 0) { + pushKeyUsage(keyUsage, unusedBits); + } pushKeyDescription(); pushSequenceHeader((short) (last - stackPtr)); // Extensions have explicit tag of [3] @@ -366,6 +378,7 @@ private static void pushRsaSubjectKeyInfo() { pushRsaEncryption(); pushSequenceHeader((short) (last - stackPtr)); } + // SEQUENCE{SEQUENCE{ecPubKey, prime256v1}, bitString{pubKey}} private static void pushEccSubjectKeyInfo() { short last = stackPtr; @@ -391,6 +404,7 @@ private static void pushRsaEncryption() { pushBytes(rsaEncryption, (short) 0, (short) rsaEncryption.length); pushSequenceHeader((short) (last - stackPtr)); } + // KeyDescription ::= SEQUENCE { // attestationVersion INTEGER, # Value 3 // attestationSecurityLevel SecurityLevel, # See below @@ -433,9 +447,9 @@ private static void pushSWParams() { short last = stackPtr; // 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 }; + 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]); @@ -447,15 +461,15 @@ private static void pushHWParams() { short last = stackPtr; // 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, - 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 }; + 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 { @@ -463,7 +477,9 @@ private static void pushHWParams() { pushRoT(); continue; } - if (pushParams(hwParams, hwParamsIndex, tagIds[index])) continue; + if (pushParams(hwParams, hwParamsIndex, tagIds[index])) { + continue; + } } while (++index < tagIds.length); pushSequenceHeader((short) (last - stackPtr)); } @@ -531,6 +547,7 @@ private static void pushTag(short tag) { break; } } + // RootOfTrust ::= SEQUENCE { // verifiedBootKey OCTET_STRING, // deviceLocked BOOLEAN, @@ -594,6 +611,7 @@ private static void pushEnumArrayTag(short tagId, byte[] buf, short start, short 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) { @@ -652,13 +670,16 @@ private static void pushIntegerTag(short tagId, byte[] buf, short start, short l pushInteger(buf, start, len); 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; + if (buf[(short) (start + index)] != 0) { + break; + } index++; } if (index == (byte) len) { @@ -671,6 +692,7 @@ private static void pushInteger(byte[] buf, short start, short len) { } 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; @@ -696,6 +718,7 @@ private static void pushTagIdHeader(short tagId, short len) { pushByte((byte) (0xA0 | (byte) tagId)); } } + // SEQUENCE {ObjId, OCTET STRING{BIT STRING{keyUsage}}} private static void pushKeyUsage(byte keyUsage, byte unusedBits) { short last = stackPtr; @@ -762,7 +785,9 @@ private static void pushBytes(byte[] buf, short start, short len) { private static void decrementStackPtr(short cnt) { stackPtr = (short) (stackPtr - cnt); - if (start > stackPtr) KMException.throwIt(KMError.UNKNOWN_ERROR); + if (start > stackPtr) { + KMException.throwIt(KMError.UNKNOWN_ERROR); + } } @Override @@ -805,39 +830,39 @@ public void build() { KMAndroidSEProvider androidSeProvider = KMAndroidSEProvider.getInstance(); short sigLen = androidSeProvider .ecSign256( - androidSeProvider.getAttestationKey(), - stack, - tbsOffset, - tbsLength, - stack, - signatureOffset); - if(sigLen != ECDSA_MAX_SIG_LEN) { + androidSeProvider.getAttestationKey(), + stack, + tbsOffset, + tbsLength, + stack, + signatureOffset); + if (sigLen != ECDSA_MAX_SIG_LEN) { // Update the lengths appropriately. - stackPtr = (short)(signatureOffset - 1); - pushLength((short)(sigLen + 1)); + 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); + last -= (short) (ECDSA_MAX_SIG_LEN - sigLen); + pushLength((short) (last - stackPtr)); + length -= (short) (ECDSA_MAX_SIG_LEN - sigLen); } } @Override public KMAttestationCert makeUniqueId(byte[] scratchPad, short scratchPadOff, - byte[] creationTime, short timeOffset, short creationTimeLen, - byte[] attestAppId, short appIdOff, short attestAppIdLen, - byte resetSinceIdRotation, KMMasterKey masterKey) { + byte[] creationTime, short timeOffset, short creationTimeLen, + byte[] attestAppId, short appIdOff, short attestAppIdLen, + byte resetSinceIdRotation, KMMasterKey masterKey) { // Concatenate T||C||R // temporal count T short temp = KMUtils.countTemporalCount(creationTime, timeOffset, - creationTimeLen, scratchPad, scratchPadOff); + creationTimeLen, scratchPad, scratchPadOff); Util.setShort(scratchPad, (short) scratchPadOff, temp); temp = scratchPadOff; scratchPadOff += 2; // Application Id C Util.arrayCopyNonAtomic(attestAppId, appIdOff, scratchPad, scratchPadOff, - attestAppIdLen); + attestAppIdLen); scratchPadOff += attestAppIdLen; // Reset After Rotation R @@ -847,19 +872,19 @@ public KMAttestationCert makeUniqueId(byte[] scratchPad, short scratchPadOff, timeOffset = KMByteBlob.instance((short) 32); //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)); + short mKeyData = KMByteBlob.instance((short) (aesKey.getSize() / 8)); aesKey.getKey( - KMByteBlob.cast(mKeyData).getBuffer(), - KMByteBlob.cast(mKeyData).getStartOff()); + 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 */ - KMByteBlob.cast(timeOffset).getBuffer(), /* signature buffer */ - KMByteBlob.cast(timeOffset).getStartOff()); /* signature start */ + 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 */ + KMByteBlob.cast(timeOffset).getBuffer(), /* signature buffer */ + KMByteBlob.cast(timeOffset).getStartOff()); /* signature start */ if (appIdOff != 32) { KMException.throwIt(KMError.UNKNOWN_ERROR); } diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMECPrivateKey.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMECPrivateKey.java index fe6a636f..3188ad19 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMECPrivateKey.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMECPrivateKey.java @@ -42,7 +42,7 @@ public short getS(byte[] buffer, short offset) { ECPrivateKey ecPriv = (ECPrivateKey) ecKeyPair.getPrivate(); return ecPriv.getS(buffer, offset); } - + public ECPrivateKey getPrivateKey() { return (ECPrivateKey) ecKeyPair.getPrivate(); } diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java index 3f11a3b1..f90b834f 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java @@ -41,13 +41,13 @@ 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 { + 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 { + short i2, short i3) throws CryptoException { } @@ -78,7 +78,7 @@ public short getLength() throws CryptoException { @Override public void update(byte[] message, short msgStart, short messageLength) - throws CryptoException { + throws CryptoException { // HAL accumulates the data and send it at finish operation. } @@ -86,8 +86,9 @@ public void update(byte[] message, short msgStart, short messageLength) public short sign(byte[] bytes, short i, short i1, byte[] bytes1, short i2) throws CryptoException { try { - if (i1 > MAX_NO_DIGEST_MSG_LEN) + 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(KMAndroidSEProvider.getInstance().tmpArray, @@ -105,35 +106,21 @@ public short sign(byte[] bytes, short i, short i1, byte[] bytes1, short i2) @Override public short signPreComputedHash(byte[] bytes, short i, short i1, - byte[] bytes1, short i2) throws CryptoException { + 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 { - 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(KMAndroidSEProvider.getInstance().tmpArray, - (short) 0, (short) MAX_NO_DIGEST_MSG_LEN, (byte) 0); - } - Util.arrayCopyNonAtomic(bytes, i, - KMAndroidSEProvider.getInstance().tmpArray, - (short) (MAX_NO_DIGEST_MSG_LEN - i1), i1); - return inst.verifyPreComputedHash( - KMAndroidSEProvider.getInstance().tmpArray, (short) 0, - (short) MAX_NO_DIGEST_MSG_LEN, bytes1, i2, i3); - } finally { - KMAndroidSEProvider.getInstance().clean(); - } + //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 { - return inst.verify(bytes, i, i1, bytes1, i2, i3); + byte[] bytes1, short i2, short i3) throws CryptoException { + //Verification is handled inside HAL + return false; } } \ No newline at end of file diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMHmacKey.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMHmacKey.java index b4ca3af4..b2a38b24 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMHmacKey.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMHmacKey.java @@ -22,6 +22,7 @@ import javacard.security.HMACKey; public class KMHmacKey implements KMPreSharedKey { + private HMACKey hmacKey; public KMHmacKey(HMACKey key) { @@ -39,6 +40,7 @@ public byte getKey(byte[] keyData, short kOff) { public short getKeySizeBits() { return hmacKey.getSize(); } + public static void onSave(Element element, KMHmacKey kmKey) { element.write(kmKey.hmacKey); } diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMInstance.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMInstance.java index 12655bc4..5178d4e2 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMInstance.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMInstance.java @@ -16,6 +16,7 @@ package com.android.javacard.keymaster; public class KMInstance { + public byte reserved; public Object object; public byte instanceCount; diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMOperationImpl.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMOperationImpl.java index a38ee518..502f3fb5 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMOperationImpl.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMOperationImpl.java @@ -125,26 +125,14 @@ public short finish(byte[] inputDataBuf, short inputDataStart, 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 Java Card - if (inputDataLen > 256) - KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - // make input equal to 255 bytes - 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) + if (cipherAlg == KMType.DES) { blkSize = 8; + } // padding bytes if (inputlen % blkSize == 0) { paddingBytes = blkSize; @@ -168,20 +156,22 @@ public short finish(byte[] inputDataBuf, short inputDataStart, if ((cipherAlg == KMType.AES || cipherAlg == KMType.DES) && padding == KMType.PKCS7 && mode == KMType.DECRYPT) { byte blkSize = 16; - if (cipherAlg == KMType.DES) + 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) + if ((short) paddingByte > blkSize || (short) paddingByte <= 0) { KMException.throwIt(KMError.INVALID_ARGUMENT); + } - for(short j = 1; j <= paddingByte; ++j) { + 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) { @@ -191,8 +181,9 @@ public short finish(byte[] inputDataBuf, short inputDataStart, } else { boolean verified = ((AEADCipher) cipher).verifyTag(inputDataBuf, (short) (inputDataStart + inputDataLen), macLength, macLength); - if (!verified) + if (!verified) { KMException.throwIt(KMError.VERIFICATION_FAILED); + } } } } finally { diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java index 991072e2..08e11436 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java @@ -130,11 +130,13 @@ private void padData(byte[] buf, short start, short len, byte[] outBuf, private boolean isValidData(byte[] buf, short start, short len) { if (algorithm == ALG_RSA_SIGN_NOPAD) { - if (len > 256) + if (len > 256) { return false; + } } else { // ALG_RSA_PKCS1_NODIGEST - if (len > 245) + if (len > 245) { return false; + } } return true; } diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsaOAEPEncoding.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsaOAEPEncoding.java index 066d828f..ac099bc5 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsaOAEPEncoding.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMRsaOAEPEncoding.java @@ -38,40 +38,41 @@ public KMRsaOAEPEncoding(byte alg) { setDigests(alg); cipher = Cipher.getInstance(Cipher.ALG_RSA_NOPAD, false); algorithm = alg; - if (null == mgf1Buf) + if (null == mgf1Buf) { mgf1Buf = JCSystem.makeTransientByteArray(MGF1_BUF_SIZE, - JCSystem.MEMORY_TYPE_TRANSIENT_DESELECT); + 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); + 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); + 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; } @@ -84,7 +85,7 @@ public void init(Key theKey, byte theMode) throws CryptoException { @Override public void init(Key theKey, byte theMode, byte[] bArray, short bOff, - short bLen) throws CryptoException { + short bLen) throws CryptoException { cipher.init(theKey, theMode, bArray, bOff, bLen); } @@ -105,7 +106,7 @@ public byte getPaddingAlgorithm() { @Override public short doFinal(byte[] inBuff, short inOffset, short inLength, - byte[] outBuff, short outOffset) throws CryptoException { + byte[] outBuff, short outOffset) throws CryptoException { short len = cipher.doFinal(inBuff, inOffset, inLength, outBuff, outOffset); // https://tools.ietf.org/html/rfc8017#section-7.1 @@ -127,18 +128,18 @@ public short doFinal(byte[] inBuff, short inOffset, short inLength, inBuff = outBuff; inOffset = (short) (outOffset + 1); return rsaOAEPDecode(inBuff, inOffset, (short) (len - 1), outBuff, - outOffset); + outOffset); } @Override public short update(byte[] inBuff, short inOffset, short inLength, - byte[] outBuff, short outOffset) throws CryptoException { + 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 inputLen, short expectedOutLen, byte[] outBuf, short outOffset) { short counter = 0; MessageDigest.OneShot md = null; try { @@ -149,21 +150,22 @@ private void maskGenerationFunction1(byte[] input, short inputOffset, while (counter < (short) (expectedOutLen / digestLen)) { I2OS(counter, mgf1Buf, (short) inputLen); md.doFinal(mgf1Buf, (short) 0, (short) (4 + inputLen), outBuf, - (short) (outOffset + (counter * digestLen))); + (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))); + (short) (outOffset + (counter * digestLen))); } } finally { - if (md != null) + if (md != null) { md.close(); + } Util.arrayFillNonAtomic(mgf1Buf, (short) 0, (short) MGF1_BUF_SIZE, - (byte) 0); + (byte) 0); } } @@ -175,14 +177,14 @@ private void I2OS(short i, byte[] out, short offset) { } private short rsaOAEPDecode(byte[] encodedMsg, short encodedMsgOff, - short encodedMsgLen, byte[] msg, short offset) { + short encodedMsgLen, byte[] msg, short offset) { MessageDigest.OneShot md = null; byte[] tmpArray = KMAndroidSEProvider.getInstance().tmpArray; try { short hLen = getDigestLength(); - if (encodedMsgLen < (short)(2 * hLen + 1)) { + if (encodedMsgLen < (short) (2 * hLen + 1)) { CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } // encodedMsg will be in the format of maskedSeed||maskedDB. @@ -191,7 +193,7 @@ private short rsaOAEPDecode(byte[] encodedMsg, short encodedMsgOff, // of the seedMask is hLen. // seedMask = MGF(maskedDB, hLen) maskGenerationFunction1(encodedMsg, (short) (encodedMsgOff + hLen), - (short) (encodedMsgLen - hLen), hLen, tmpArray, (short) 0); + (short) (encodedMsgLen - hLen), hLen, tmpArray, (short) 0); // Get the seed by doing XOR of (maskedSeed ^ seedMask). // seed = (maskedSeed ^ seedMask) @@ -203,7 +205,7 @@ private short rsaOAEPDecode(byte[] encodedMsg, short encodedMsgOff, // 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); + (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) @@ -217,7 +219,7 @@ private short rsaOAEPDecode(byte[] encodedMsg, short encodedMsgOff, 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)) { + tmpArray, (short) 0, hLen)) { // Verification failed. CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } @@ -231,7 +233,8 @@ private short rsaOAEPDecode(byte[] encodedMsg, short encodedMsgOff, // 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++) { + 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); @@ -243,14 +246,15 @@ private short rsaOAEPDecode(byte[] encodedMsg, short encodedMsgOff, } // Copy the message Util.arrayCopyNonAtomic(encodedMsg, (short) (start + 1), msg, offset, - (short) (encodedMsgLen - ((start - encodedMsgOff) + 1))); + (short) (encodedMsgLen - ((start - encodedMsgOff) + 1))); return (short) (encodedMsgLen - ((start - encodedMsgOff) + 1)); } finally { - if (md != null) + if (md != null) { md.close(); + } Util.arrayFillNonAtomic(tmpArray, (short) 0, - KMAndroidSEProvider.TMP_ARRAY_SIZE, (byte) 0); + KMAndroidSEProvider.TMP_ARRAY_SIZE, (byte) 0); } } } \ No newline at end of file diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java index 65e83415..c2b5c7f3 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java @@ -18,43 +18,44 @@ 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 + 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 + 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 + 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 + 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[] leapYearMsec = { - 0, 0, 0, 0x07, (byte) 0x5C, (byte) 0xD7, (byte) 0x88, 0x00}; //31622400000; + 0, 0, 0, 0, (byte) 0x9C, (byte) 0xBE, (byte) 0xBD, 0x50}; // 2629746000 msec + 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 + 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) 0xEB, 0x0C, 0x00};//126230400000 + 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 + 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 + 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 + 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 + 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 + 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) { + boolean utcFlag) { short yrsCount = 0; short monthCount = 1; @@ -66,48 +67,48 @@ public static short convertToDate(short time, byte[] scratchPad, 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()); + 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 (unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2020, (short) 0, - (short) 8) < 0) { + if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2020, (short) 0, + (short) 8) < 0) { KMException.throwIt(KMError.INVALID_ARGUMENT); } if (utcFlag - && unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, - (short) 0, (short) 8) >= 0) { + && KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, + (short) 0, (short) 8) >= 0) { KMException.throwIt(KMError.INVALID_ARGUMENT); } - if (unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, (short) 0, - (short) 8) < 0) { + if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, (short) 0, + (short) 8) < 0) { Util.arrayCopyNonAtomic(firstJan2020, (short) 0, scratchPad, (short) 8, - (short) 8); + (short) 8); subtract(scratchPad, (short) 0, (short) 8, (short) 16); Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); + (short) 8); } else { from2020 = false; Util.arrayCopyNonAtomic(firstJan2051, (short) 0, scratchPad, (short) 8, - (short) 8); + (short) 8); subtract(scratchPad, (short) 0, (short) 8, (short) 16); Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); + (short) 8); } // divide the given time with four yrs msec count - if (unsignedByteArrayCompare(scratchPad, (short) 0, fourYrsMsec, (short) 0, - (short) 8) >= 0) { + if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, fourYrsMsec, (short) 0, + (short) 8) >= 0) { Util.arrayCopyNonAtomic(fourYrsMsec, (short) 0, scratchPad, (short) 8, - (short) 8); + (short) 8); yrsCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); // quotient - // is - // multiple - // of 4 + // 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); + (short) 8); } //Get the leap year index starting from the (base Year + yrsCount) Year. @@ -116,29 +117,33 @@ && unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, // 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))) { + (KMInteger + .unsignedByteArrayCompare(scratchPad, (short) 0, leapYearMsec, (short) 0, (short) 8) + >= 0)) || + ((leapYrIdx != 0) && + (KMInteger + .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); + (short) 8, (short) 8); } else { Util.arrayCopyNonAtomic(yearMsec, (short) 0, scratchPad, (short) 8, - (short) 8); + (short) 8); } subtract(scratchPad, (short) 0, (short) 8, (short) 16); Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); + (short) 8); if (((short) (i + 1) == leapYrIdx)) { - if (unsignedByteArrayCompare(scratchPad, (short) 0, leapYearMsec, - (short) 0, (short) 8) < 0) { + if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, leapYearMsec, + (short) 0, (short) 8) < 0) { break; } } else { - if (unsignedByteArrayCompare(scratchPad, (short) 0, yearMsec, - (short) 0, (short) 8) < 0) { + if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, yearMsec, + (short) 0, (short) 8) < 0) { break; } } @@ -146,40 +151,41 @@ && unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, } // total yrs from 1970 - if (from2020) + if (from2020) { yrsCount = (short) (year2020 + yrsCount); - else + } else { yrsCount = (short) (year2051 + yrsCount); + } // divide the given time with one month msec count - if (unsignedByteArrayCompare(scratchPad, (short) 0, oneMonthMsec, (short) 0, - (short) 8) >= 0) { + if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, oneMonthMsec, (short) 0, + (short) 8) >= 0) { 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); + (short) 8, (short) 8); } else { // 28 days Util.arrayCopyNonAtomic(febMonthMsec, (short) 0, scratchPad, - (short) 8, (short) 8); + (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); + scratchPad, (short) 8, (short) 8); } else { // 30 Days Util.arrayCopyNonAtomic(ThirtDaysMonthMsec, (short) 0, scratchPad, - (short) 8, (short) 8); + (short) 8, (short) 8); } - if (unsignedByteArrayCompare(scratchPad, (short) 0, scratchPad, (short) 8, - (short) 8) >= 0) { + if (KMInteger.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); + (short) 8); } else { break; } @@ -188,44 +194,44 @@ && unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, } // divide the given time with one day msec count - if (unsignedByteArrayCompare(scratchPad, (short) 0, oneDayMsec, (short) 0, - (short) 8) >= 0) { + if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, oneDayMsec, (short) 0, + (short) 8) >= 0) { Util.arrayCopyNonAtomic(oneDayMsec, (short) 0, scratchPad, (short) 8, - (short) 8); + (short) 8); dayCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); dayCount++; Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); + (short) 8); } // divide the given time with one hour msec count - if (unsignedByteArrayCompare(scratchPad, (short) 0, oneHourMsec, (short) 0, - (short) 8) >= 0) { + if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, oneHourMsec, (short) 0, + (short) 8) >= 0) { Util.arrayCopyNonAtomic(oneHourMsec, (short) 0, scratchPad, (short) 8, - (short) 8); + (short) 8); hhCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); + (short) 8); } // divide the given time with one minute msec count - if (unsignedByteArrayCompare(scratchPad, (short) 0, oneMinMsec, (short) 0, - (short) 8) >= 0) { + if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, oneMinMsec, (short) 0, + (short) 8) >= 0) { Util.arrayCopyNonAtomic(oneMinMsec, (short) 0, scratchPad, (short) 8, - (short) 8); + (short) 8); mmCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); + (short) 8); } // divide the given time with one second msec count - if (unsignedByteArrayCompare(scratchPad, (short) 0, oneSecMsec, (short) 0, - (short) 8) >= 0) { + if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, oneSecMsec, (short) 0, + (short) 8) >= 0) { Util.arrayCopyNonAtomic(oneSecMsec, (short) 0, scratchPad, (short) 8, - (short) 8); + (short) 8); ssCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); + (short) 8); } // Now convert to ascii string YYMMDDhhmmssZ or YYYYMMDDhhmmssZ @@ -238,38 +244,21 @@ && unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, len += numberToString(ssCount, scratchPad, len); scratchPad[len] = Z; len++; - if (utcFlag) + if (utcFlag) { return KMByteBlob.instance(scratchPad, (short) 2, (short) (len - 2)); // YY - else + } else { 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) { + short offset) { byte zero = 0x30; byte len = 2; byte digit; - if (number > 999) + if (number > 999) { len = 4; + } byte index = len; while (index > 0) { digit = (byte) (number % 10); @@ -284,7 +273,7 @@ public static short numberToString(short number, byte[] scratchPad, // 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 remainder) { short expCnt = 1; short q = 0; // first increase divisor so that it becomes greater then dividend. @@ -311,7 +300,7 @@ public static void copy(byte[] buf, short from, short to) { } public static byte compare(byte[] buf, short lhs, short rhs) { - return unsignedByteArrayCompare(buf, lhs, buf, rhs, (short) 8); + return KMInteger.unsignedByteArrayCompare(buf, lhs, buf, rhs, (short) 8); } public static void shiftLeft(byte[] buf, short start) { @@ -322,10 +311,11 @@ public static void shiftLeft(byte[] buf, short start) { 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) + if (tmp < 0) { carry = 1; - else + } else { carry = 0; + } index--; } } @@ -339,10 +329,11 @@ public static void shiftRight(byte[] buf, short start) { 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) + if (tmp == 1) { carry = (byte) 0x80; - else + } else { carry = 0; + } index++; } } @@ -354,8 +345,9 @@ public static 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) + if (tmp > 255) { carry = 1; // max unsigned byte value is 255 + } buf[(short) (result + index)] = (byte) (tmp & (byte) 0xFF); index--; } @@ -381,25 +373,25 @@ public static void subtract(byte[] buf, short op1, short op2, short result) { index--; } } - + public static short countTemporalCount(byte[] bufTime, short timeOff, - short timeLen, byte[] scratchPad, short offset) { + 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); + bufTime, + timeOff, + scratchPad, + (short) (offset + 8 - timeLen), + timeLen); Util.arrayCopyNonAtomic(oneMonthMsec, (short) 0, scratchPad, (short) (offset + 8), - (short) 8); + (short) 8); 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) { + if ((short) (year % 4) == (short) 0) { + if (((short) (year % 100) == (short) 0) && + ((short) (year % 400)) != (short) 0) { return false; } return true; @@ -409,8 +401,8 @@ public static boolean isLeapYear(short year) { 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))) { + for (short i = 0; i < 4; i++) { + if (isLeapYear((short) (newBaseYr + i))) { return i; } } diff --git a/Applet/JCardSimProvider/build.xml b/Applet/JCardSimProvider/build.xml index 58343402..3d06a8fd 100644 --- a/Applet/JCardSimProvider/build.xml +++ b/Applet/JCardSimProvider/build.xml @@ -1,21 +1,23 @@ - - + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + @@ -23,9 +25,10 @@ - + - + @@ -34,7 +37,8 @@ - + @@ -52,5 +56,5 @@ - + \ No newline at end of file diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAESKey.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAESKey.java index 489d4f77..258dc461 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAESKey.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAESKey.java @@ -18,6 +18,7 @@ import javacard.security.AESKey; public class KMAESKey implements KMMasterKey { + private AESKey aesKey; public KMAESKey(AESKey key) { @@ -31,7 +32,7 @@ public void setKey(byte[] keyData, short kOff) { public byte getKey(byte[] keyData, short kOff) { return aesKey.getKey(keyData, kOff); } - + public short getKeySizeBits() { return aesKey.getSize(); } diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java index 18e67e72..37e67d1c 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -25,50 +25,53 @@ // 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 + 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 + 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 + 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 + 0x06, 0x0A, 0X2B, 0X06, 0X01, 0X04, 0X01, (byte) 0XD6, 0X79, 0X02, 0X01, 0X11 }; 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, - 0x0A, - 0x06, - 0x08, - 0x2A, - (byte) 0x86, - 0x48, - (byte) 0xCE, - (byte) 0x3D, - 0x04, - 0x03, - 0x02 + 0x30, + 0x0A, + 0x06, + 0x08, + 0x2A, + (byte) 0x86, + 0x48, + (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 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 + 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 @@ -111,10 +114,13 @@ public class KMAttestationCertImpl implements KMAttestationCert { private static short issuer; private static short signPriv; - private KMAttestationCertImpl() {} + private KMAttestationCertImpl() { + } public static KMAttestationCert instance(boolean rsaCert) { - if (inst == null) inst = new KMAttestationCertImpl(); + if (inst == null) { + inst = new KMAttestationCertImpl(); + } init(); KMAttestationCertImpl.rsaCert = rsaCert; return inst; @@ -184,18 +190,19 @@ public KMAttestationCert notBefore(short obj, byte[] scratchpad) { @Override public KMAttestationCert notAfter(short usageExpiryTimeObj, - short certExpirtyTimeObj, byte[] scratchPad, short tmpVar) { + 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) + if (KMInteger.compare(usageExpiryTimeObj, tmpVar) >= 0) { usageExpiryTimeObj = KMUtils.convertToDate(usageExpiryTimeObj, scratchPad, - false); - else + false); + } else { usageExpiryTimeObj = KMUtils - .convertToDate(usageExpiryTimeObj, scratchPad, true); + .convertToDate(usageExpiryTimeObj, scratchPad, true); + } notAfter = usageExpiryTimeObj; } else { notAfter = certExpirtyTimeObj; @@ -205,8 +212,11 @@ public KMAttestationCert notAfter(short usageExpiryTimeObj, @Override public KMAttestationCert deviceLocked(boolean val) { - if (val) deviceLocked = (byte) 0xFF; - else deviceLocked = 0; + if (val) { + deviceLocked = (byte) 0xFF; + } else { + deviceLocked = 0; + } return this; } @@ -296,7 +306,9 @@ private static void pushTbsCert(boolean rsaCert) { private static void pushExtensions() { short last = stackPtr; - if (keyUsage != 0) pushKeyUsage(keyUsage, unusedBits); + if (keyUsage != 0) { + pushKeyUsage(keyUsage, unusedBits); + } pushKeyDescription(); pushSequenceHeader((short) (last - stackPtr)); // Extensions have explicit tag of [3] @@ -360,6 +372,7 @@ private static void pushRsaSubjectKeyInfo() { pushRsaEncryption(); pushSequenceHeader((short) (last - stackPtr)); } + // SEQUENCE{SEQUENCE{ecPubKey, prime256v1}, bitString{pubKey}} private static void pushEccSubjectKeyInfo() { short last = stackPtr; @@ -385,6 +398,7 @@ private static void pushRsaEncryption() { pushBytes(rsaEncryption, (short) 0, (short) rsaEncryption.length); pushSequenceHeader((short) (last - stackPtr)); } + // KeyDescription ::= SEQUENCE { // attestationVersion INTEGER, # Value 3 // attestationSecurityLevel SecurityLevel, # See below @@ -427,9 +441,9 @@ private static void pushSWParams() { short last = stackPtr; // 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 }; + 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]); @@ -441,15 +455,15 @@ private static void pushHWParams() { short last = stackPtr; // 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, - 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 }; + 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 { @@ -457,7 +471,9 @@ private static void pushHWParams() { pushRoT(); continue; } - if (pushParams(hwParams, hwParamsIndex, tagIds[index])) continue; + if (pushParams(hwParams, hwParamsIndex, tagIds[index])) { + continue; + } } while (++index < tagIds.length); pushSequenceHeader((short) (last - stackPtr)); } @@ -525,6 +541,7 @@ private static void pushTag(short tag) { break; } } + // RootOfTrust ::= SEQUENCE { // verifiedBootKey OCTET_STRING, // deviceLocked BOOLEAN, @@ -588,6 +605,7 @@ private static void pushEnumArrayTag(short tagId, byte[] buf, short start, short 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) { @@ -647,13 +665,16 @@ private static void pushIntegerTag(short tagId, byte[] buf, short start, short l // 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; + if (buf[(short) (start + index)] != 0) { + break; + } index++; } if (index == (byte) len) { @@ -666,6 +687,7 @@ private static void pushInteger(byte[] buf, short start, short len) { } 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; @@ -691,6 +713,7 @@ private static void pushTagIdHeader(short tagId, short len) { pushByte((byte) (0xA0 | (byte) tagId)); } } + // SEQUENCE {ObjId, OCTET STRING{BIT STRING{keyUsage}}} private static void pushKeyUsage(byte keyUsage, byte unusedBits) { short last = stackPtr; @@ -757,7 +780,9 @@ private static void pushBytes(byte[] buf, short start, short len) { private static void decrementStackPtr(short cnt) { stackPtr = (short) (stackPtr - cnt); - if (start > stackPtr) KMException.throwIt(KMError.UNKNOWN_ERROR); + if (start > stackPtr) { + KMException.throwIt(KMError.UNKNOWN_ERROR); + } } @Override @@ -800,39 +825,39 @@ public void build() { KMJCardSimulator provider = KMJCardSimulator.getInstance(); short sigLen = provider .ecSign256( - provider.getAttestationKey(), - stack, - tbsOffset, - tbsLength, - stack, - signatureOffset); - if(sigLen != ECDSA_MAX_SIG_LEN) { + provider.getAttestationKey(), + stack, + tbsOffset, + tbsLength, + stack, + signatureOffset); + if (sigLen != ECDSA_MAX_SIG_LEN) { // Update the lengths appropriately. - stackPtr = (short)(signatureOffset - 1); - pushLength((short)(sigLen + 1)); + 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); + last -= (short) (ECDSA_MAX_SIG_LEN - sigLen); + pushLength((short) (last - stackPtr)); + length -= (short) (ECDSA_MAX_SIG_LEN - sigLen); } } @Override public KMAttestationCert makeUniqueId(byte[] scratchPad, short scratchPadOff, - byte[] creationTime, short timeOffset, short creationTimeLen, - byte[] attestAppId, short appIdOff, short attestAppIdLen, - byte resetSinceIdRotation, KMMasterKey masterKey) { + byte[] creationTime, short timeOffset, short creationTimeLen, + byte[] attestAppId, short appIdOff, short attestAppIdLen, + byte resetSinceIdRotation, KMMasterKey masterKey) { // Concatenate T||C||R // temporal count T short temp = KMUtils.countTemporalCount(creationTime, timeOffset, - creationTimeLen, scratchPad, scratchPadOff); + creationTimeLen, scratchPad, scratchPadOff); Util.setShort(scratchPad, (short) scratchPadOff, temp); temp = scratchPadOff; scratchPadOff += 2; // Application Id C Util.arrayCopyNonAtomic(attestAppId, appIdOff, scratchPad, scratchPadOff, - attestAppIdLen); + attestAppIdLen); scratchPadOff += attestAppIdLen; // Reset After Rotation R @@ -841,20 +866,20 @@ public KMAttestationCert makeUniqueId(byte[] scratchPad, short scratchPadOff, //Get the key data from the master key KMAESKey aesKey = (KMAESKey) masterKey; - short mKeyData = KMByteBlob.instance((short) (aesKey.getKeySizeBits() / 8)); + short mKeyData = KMByteBlob.instance((short) (aesKey.getKeySizeBits() / 8)); aesKey.getKey( - KMByteBlob.cast(mKeyData).getBuffer(), /* Key */ - KMByteBlob.cast(mKeyData).getStartOff()); /* Key start*/ + KMByteBlob.cast(mKeyData).getBuffer(), /* Key */ + KMByteBlob.cast(mKeyData).getStartOff()); /* Key start*/ timeOffset = KMByteBlob.instance((short) 32); 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 */ - KMByteBlob.cast(timeOffset).getBuffer(), /* signature buffer */ - KMByteBlob.cast(timeOffset).getStartOff()); /* signature start */ + 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 */ + KMByteBlob.cast(timeOffset).getBuffer(), /* signature buffer */ + KMByteBlob.cast(timeOffset).getStartOff()); /* signature start */ if (appIdOff != 32) { KMException.throwIt(KMError.UNKNOWN_ERROR); } diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipher.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipher.java index 3e67ed5e..420a775c 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipher.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipher.java @@ -16,11 +16,14 @@ package com.android.javacard.keymaster; public abstract class KMCipher { + public static final short SUN_JCE = 0xE9; - public abstract short doFinal(byte[] buffer, short startOff, short length, byte[] scratchPad, short i); + 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 short update(byte[] buffer, short startOff, short length, byte[] scratchPad, + short i); public abstract void updateAAD(byte[] buffer, short startOff, short length); diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipherImpl.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipherImpl.java index bc07be8d..c4162b12 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipherImpl.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMCipherImpl.java @@ -24,25 +24,28 @@ import javax.crypto.ShortBufferException; -public class KMCipherImpl extends KMCipher{ +public class KMCipherImpl extends KMCipher { + private Cipher cipher; private javax.crypto.Cipher sunCipher; private short cipherAlg; private short padding; private short mode; private short blockMode; - KMCipherImpl(Cipher c){ + + KMCipherImpl(Cipher c) { cipher = c; } - KMCipherImpl(javax.crypto.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){ + 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); + return (short) sunCipher.doFinal(buffer, startOff, length, scratchPad, i); } catch (ShortBufferException e) { e.printStackTrace(); CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); @@ -53,9 +56,9 @@ public short doFinal(byte[] buffer, short startOff, short length, byte[] scratch e.printStackTrace(); CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } - }else if(cipherAlg == KMType.AES && blockMode == KMType.GCM){ + } else if (cipherAlg == KMType.AES && blockMode == KMType.GCM) { try { - return (short)sunCipher.doFinal(buffer,startOff,length,scratchPad,i); + return (short) sunCipher.doFinal(buffer, startOff, length, scratchPad, i); } catch (AEADBadTagException e) { e.printStackTrace(); KMException.throwIt(KMError.VERIFICATION_FAILED); @@ -67,9 +70,9 @@ public short doFinal(byte[] buffer, short startOff, short length, byte[] scratch } catch (BadPaddingException e) { CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } - } else if(cipherAlg == KMType.AES && blockMode == KMType.CTR){ + } else if (cipherAlg == KMType.AES && blockMode == KMType.CTR) { try { - return (short)sunCipher.doFinal(buffer,startOff,length,scratchPad,i); + return (short) sunCipher.doFinal(buffer, startOff, length, scratchPad, i); } catch (ShortBufferException e) { e.printStackTrace(); CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); @@ -80,67 +83,64 @@ public short doFinal(byte[] buffer, short startOff, short length, byte[] scratch 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; + } 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; - - }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; + 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) { + 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){ + } 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) { + if (cipherAlg == KMType.DES) { + blkSize = 8; + } + if (len > 0) { //verify if padding is corrupted. - byte paddingByte = scratchPad[i+len -1]; + 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); + 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) { + 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 + len = (short) (len - (short) paddingByte);// remove the padding bytes } } return len; @@ -160,17 +160,17 @@ public void setCipherAlgorithm(short 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)){ + if (cipherAlg == KMType.AES && (blockMode == KMType.GCM || blockMode == KMType.CTR)) { try { - return (short)sunCipher.update(buffer,startOff,length,scratchPad,i); + 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); + e.printStackTrace(); + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } - } else{ + } else { return cipher.update(buffer, startOff, length, scratchPad, i); } return KMType.INVALID_VALUE; @@ -178,16 +178,16 @@ public short update(byte[] buffer, short startOff, short length, byte[] scratchP @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); - } + 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 @@ -201,12 +201,12 @@ public void setPaddingAlgorithm(short alg) { } @Override - public void setBlockMode(short mode){ - blockMode = mode; + public void setBlockMode(short mode) { + blockMode = mode; } @Override - public short getBlockMode(){ + public short getBlockMode() { return blockMode; } @@ -220,7 +220,7 @@ public void setMode(short mode) { @Override public short getCipherProvider() { - return KMCipher.SUN_JCE; + return KMCipher.SUN_JCE; } @Override diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMECPrivateKey.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMECPrivateKey.java index 65c069d1..62b26cce 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMECPrivateKey.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMECPrivateKey.java @@ -30,7 +30,7 @@ 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/KMEcdsa256NoDigestSignature.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java index 42468363..c382f3cb 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMEcdsa256NoDigestSignature.java @@ -42,60 +42,61 @@ public class KMEcdsa256NoDigestSignature extends Signature { + private java.security.Signature sunSigner; - public KMEcdsa256NoDigestSignature(byte mode, byte[] key, short keyStart, short keyLength){ - KeyFactory kf; - try { - sunSigner = java.security.Signature.getInstance("NONEwithECDSA", "SunEC"); - kf = KeyFactory.getInstance("EC"); - AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC", "SunEC"); - //Supported curve secp256r1 - parameters.init(new ECGenParameterSpec("secp256r1")); - ECParameterSpec ecParameters = parameters.getParameterSpec(ECParameterSpec.class); - if(mode == Signature.MODE_SIGN) { - byte[] privKey = new byte[keyLength]; - for(short i =0; i< keyLength; i++) { - privKey[i] = key[keyStart+i]; - } - BigInteger bI = new BigInteger(privKey); - ECPrivateKeySpec prikeyspec = new ECPrivateKeySpec(bI, ecParameters); - ECPrivateKey privkey = (ECPrivateKey) kf.generatePrivate(prikeyspec); - sunSigner.initSign(privkey); - } else { - //Check if the first byte is 04 and remove it. - if(key[keyStart] == 0x04) { - //uncompressed format. - keyStart++; - keyLength--; - } - short i = 0; - byte[] pubx = new byte[keyLength/2]; - for(;i < keyLength/2; i++ ) { - pubx[i] = key[keyStart+i]; - } - byte[] puby = new byte[keyLength/2]; - for(i = 0;i < keyLength/2; i++ ) { - puby[i] = key[keyStart+keyLength/2+i]; - } - BigInteger bIX = new BigInteger(pubx); - BigInteger bIY = new BigInteger(puby); - ECPoint point = new ECPoint(bIX, bIY); - ECPublicKeySpec pubkeyspec = new ECPublicKeySpec(point, ecParameters); - ECPublicKey pubkey = (ECPublicKey) kf.generatePublic(pubkeyspec); - sunSigner.initVerify(pubkey); - } - } catch (NoSuchAlgorithmException e) { - CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - } catch (NoSuchProviderException e) { - CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - } catch(InvalidParameterSpecException e) { - CryptoException.throwIt(CryptoException.INVALID_INIT); - } catch(InvalidKeySpecException e) { - CryptoException.throwIt(CryptoException.INVALID_INIT); - } catch(InvalidKeyException e) { - CryptoException.throwIt(CryptoException.INVALID_INIT); - } + public KMEcdsa256NoDigestSignature(byte mode, byte[] key, short keyStart, short keyLength) { + KeyFactory kf; + try { + sunSigner = java.security.Signature.getInstance("NONEwithECDSA", "SunEC"); + kf = KeyFactory.getInstance("EC"); + AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC", "SunEC"); + //Supported curve secp256r1 + parameters.init(new ECGenParameterSpec("secp256r1")); + ECParameterSpec ecParameters = parameters.getParameterSpec(ECParameterSpec.class); + if (mode == Signature.MODE_SIGN) { + byte[] privKey = new byte[keyLength]; + for (short i = 0; i < keyLength; i++) { + privKey[i] = key[keyStart + i]; + } + BigInteger bI = new BigInteger(privKey); + ECPrivateKeySpec prikeyspec = new ECPrivateKeySpec(bI, ecParameters); + ECPrivateKey privkey = (ECPrivateKey) kf.generatePrivate(prikeyspec); + sunSigner.initSign(privkey); + } else { + //Check if the first byte is 04 and remove it. + if (key[keyStart] == 0x04) { + //uncompressed format. + keyStart++; + keyLength--; + } + short i = 0; + byte[] pubx = new byte[keyLength / 2]; + for (; i < keyLength / 2; i++) { + pubx[i] = key[keyStart + i]; + } + byte[] puby = new byte[keyLength / 2]; + for (i = 0; i < keyLength / 2; i++) { + puby[i] = key[keyStart + keyLength / 2 + i]; + } + BigInteger bIX = new BigInteger(pubx); + BigInteger bIY = new BigInteger(puby); + ECPoint point = new ECPoint(bIX, bIY); + ECPublicKeySpec pubkeyspec = new ECPublicKeySpec(point, ecParameters); + ECPublicKey pubkey = (ECPublicKey) kf.generatePublic(pubkeyspec); + sunSigner.initVerify(pubkey); + } + } catch (NoSuchAlgorithmException e) { + CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); + } catch (NoSuchProviderException e) { + CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); + } catch (InvalidParameterSpecException e) { + CryptoException.throwIt(CryptoException.INVALID_INIT); + } catch (InvalidKeySpecException e) { + CryptoException.throwIt(CryptoException.INVALID_INIT); + } catch (InvalidKeyException e) { + CryptoException.throwIt(CryptoException.INVALID_INIT); + } } @Override @@ -109,7 +110,8 @@ public void init(Key key, byte b, byte[] bytes, short i, short i1) throws Crypto } @Override - public void setInitialDigest(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) throws CryptoException { + public void setInitialDigest(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) + throws CryptoException { } @@ -140,52 +142,50 @@ public short getLength() throws CryptoException { @Override public void update(byte[] message, short msgStart, short messageLength) throws CryptoException { - byte[] msgBytes = new byte[messageLength]; - for(int i =0; i< messageLength; i++) { - msgBytes[i] = message[msgStart+i]; - } - try { - if(messageLength > 0) - sunSigner.update(msgBytes); - } catch (SignatureException e) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } + byte[] msgBytes = new byte[messageLength]; + for (int i = 0; i < messageLength; i++) { + msgBytes[i] = message[msgStart + i]; + } + try { + if (messageLength > 0) { + sunSigner.update(msgBytes); + } + } catch (SignatureException e) { + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } } @Override - public short sign(byte[] bytes, short i, short i1, byte[] bytes1, short i2) throws CryptoException { + public short sign(byte[] bytes, short i, short i1, byte[] bytes1, short i2) + throws CryptoException { short len = 0; try { - update(bytes, i , i1); - byte[] sig = sunSigner.sign(); - Util.arrayCopyNonAtomic(sig, (short)0, bytes1, i2, (short)sig.length); - return (short)sig.length; - } catch (SignatureException e) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } + update(bytes, i, i1); + byte[] sig = sunSigner.sign(); + Util.arrayCopyNonAtomic(sig, (short) 0, bytes1, i2, (short) sig.length); + return (short) sig.length; + } catch (SignatureException e) { + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } return len; } @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. - try { - update(bytes, i , i1); - return sunSigner.verify(bytes1, i2, i3); - } catch (SignatureException e) { - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } + public boolean verify(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) + throws CryptoException { + // Public key operations not handled here. 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 { return false; } } diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMHmacKey.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMHmacKey.java index 8b75827a..65f1d02a 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMHmacKey.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMHmacKey.java @@ -18,6 +18,7 @@ import javacard.security.HMACKey; public class KMHmacKey implements KMPreSharedKey { + private HMACKey hmacKey; public KMHmacKey(HMACKey key) { diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java index fd6dd910..a97377ea 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java @@ -17,9 +17,10 @@ public class KMJCardSimApplet extends KMKeymasterApplet { - KMJCardSimApplet(){ + KMJCardSimApplet() { super(new KMJCardSimulator()); } + /** * Installs this applet. * @@ -28,7 +29,7 @@ public class KMJCardSimApplet extends KMKeymasterApplet { * @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(); + new KMJCardSimApplet().register(); } } diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java index 664ade77..20de91c8 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java @@ -66,6 +66,7 @@ * creates its own RNG using PRNG. */ public class KMJCardSimulator implements KMSEProvider { + 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; @@ -117,16 +118,16 @@ public KMJCardSimulator() { jCardSimulator = this; } - + public KeyPair createRsaKeyPair() { KeyPair rsaKeyPair = new KeyPair(KeyPair.ALG_RSA, KeyBuilder.LENGTH_RSA_2048); rsaKeyPair.genKeyPair(); return rsaKeyPair; } - + public RSAPrivateKey createRsaKey(byte[] modBuffer, short modOff, short modLength, - byte[] privBuffer, short privOff, short privLength) { + byte[] privBuffer, short privOff, short privLength) { KeyPair rsaKeyPair = new KeyPair(KeyPair.ALG_RSA, KeyBuilder.LENGTH_RSA_2048); RSAPrivateKey privKey = (RSAPrivateKey) rsaKeyPair.getPrivate(); privKey.setExponent(privBuffer, privOff, privLength); @@ -135,88 +136,89 @@ public RSAPrivateKey createRsaKey(byte[] modBuffer, short modOff, short modLengt } - + public KeyPair createECKeyPair() { KeyPair ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256); ecKeyPair.genKeyPair(); return ecKeyPair; } - + public ECPrivateKey createEcKey(byte[] privBuffer, short privOff, short privLength) { KeyPair ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256); ECPrivateKey privKey = (ECPrivateKey) ecKeyPair.getPrivate(); - privKey.setS(privBuffer,privOff, privLength); + privKey.setS(privBuffer, privOff, privLength); return privKey; } - + public AESKey createAESKey(short keysize) { - byte[] rndNum = new byte[(short) (keysize/8)]; - return createAESKey(rndNum, (short)0, (short)rndNum.length); + byte[] rndNum = new byte[(short) (keysize / 8)]; + return createAESKey(rndNum, (short) 0, (short) rndNum.length); } public AESKey createAESKey(byte[] buf, short startOff, short length) { AESKey key = null; - short keysize = (short)(length * 8); + short keysize = (short) (length * 8); if (keysize == 128) { key = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false); key.setKey(buf, (short) startOff); - }else if (keysize == 256){ + } else if (keysize == 256) { key = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_256, false); key.setKey(buf, (short) startOff); } return key; } - + public DESKey createTDESKey() { byte[] rndNum = new byte[24]; - newRandomNumber(rndNum, (short) 0, (short)rndNum.length); - return createTDESKey(rndNum, (short)0, (short)rndNum.length); + newRandomNumber(rndNum, (short) 0, (short) rndNum.length); + return createTDESKey(rndNum, (short) 0, (short) rndNum.length); } - + public DESKey createTDESKey(byte[] secretBuffer, short secretOff, short secretLength) { DESKey triDesKey = - (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES, KeyBuilder.LENGTH_DES3_3KEY, false); + (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES, KeyBuilder.LENGTH_DES3_3KEY, false); triDesKey.setKey(secretBuffer, secretOff); return triDesKey; } - + public HMACKey createHMACKey(short keysize) { - if((keysize % 8 != 0) || !(keysize >= 64 && keysize <= 512)){ + if ((keysize % 8 != 0) || !(keysize >= 64 && keysize <= 512)) { CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } - byte[] rndNum = new byte[(short) (keysize/8)]; - newRandomNumber(rndNum, (short) 0, (short)(keysize/8)); - return createHMACKey(rndNum, (short)0, (short)rndNum.length); + byte[] rndNum = new byte[(short) (keysize / 8)]; + newRandomNumber(rndNum, (short) 0, (short) (keysize / 8)); + return createHMACKey(rndNum, (short) 0, (short) rndNum.length); } @Override public short createSymmetricKey(byte alg, short keysize, byte[] buf, short startOff) { - switch(alg){ + switch (alg) { case KMType.AES: AESKey aesKey = createAESKey(keysize); - return aesKey.getKey(buf,startOff); + return aesKey.getKey(buf, startOff); case KMType.DES: DESKey desKey = createTDESKey(); - return desKey.getKey(buf,startOff); + 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 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){ + public void createAsymmetricKey(byte alg, byte[] privKeyBuf, short privKeyStart, + short privKeyLength, + 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); @@ -225,48 +227,51 @@ public void createAsymmetricKey(byte alg, byte[] privKeyBuf, short privKeyStart, RSAPrivateKey privKey = (RSAPrivateKey) rsaKey.getPrivate(); //Copy exponent. byte[] exp = new byte[RSA_KEY_SIZE]; - lengths[0] = privKey.getExponent(exp, (short)0); - if (lengths[0] > privKeyLength) + 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]); + } + 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) + 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]); + } + 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(); 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){ + 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; + default: + CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); + break; } } @Override - public boolean importSymmetricKey(byte alg, short keysize, byte[] buf, short startOff, short length) { - switch(alg){ + public boolean importSymmetricKey(byte alg, short keysize, byte[] buf, short startOff, + short length) { + switch (alg) { case KMType.AES: - AESKey aesKey = createAESKey(buf,startOff,length); + AESKey aesKey = createAESKey(buf, startOff, length); break; case KMType.DES: - DESKey desKey = createTDESKey(buf,startOff,length); + DESKey desKey = createTDESKey(buf, startOff, length); break; case KMType.HMAC: - HMACKey hmacKey = createHMACKey(buf,startOff,length); + HMACKey hmacKey = createHMACKey(buf, startOff, length); break; default: CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); @@ -276,13 +281,15 @@ public boolean importSymmetricKey(byte alg, short keysize, byte[] buf, short sta } @Override - public boolean importAsymmetricKey(byte alg, byte[] privKeyBuf, short privKeyStart, short privKeyLength, byte[] pubModBuf, short pubModStart, short pubModLength) { - switch (alg){ + public boolean importAsymmetricKey(byte alg, byte[] privKeyBuf, short privKeyStart, + short privKeyLength, byte[] pubModBuf, short pubModStart, short pubModLength) { + switch (alg) { case KMType.RSA: - RSAPrivateKey rsaKey = createRsaKey(pubModBuf,pubModStart,pubModLength,privKeyBuf,privKeyStart,privKeyLength); + RSAPrivateKey rsaKey = createRsaKey(pubModBuf, pubModStart, pubModLength, privKeyBuf, + privKeyStart, privKeyLength); break; case KMType.EC: - ECPrivateKey ecPrivKey = createEcKey(privKeyBuf,privKeyStart,privKeyLength); + ECPrivateKey ecPrivKey = createEcKey(privKeyBuf, privKeyStart, privKeyLength); break; default: CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); @@ -291,12 +298,12 @@ public boolean importAsymmetricKey(byte alg, byte[] privKeyBuf, short privKeySta return true; } - + public HMACKey createHMACKey(byte[] secretBuffer, short secretOff, short secretLength) { HMACKey key = null; key = (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC, - KeyBuilder.LENGTH_HMAC_SHA_256_BLOCK_64, false); - key.setKey(secretBuffer,secretOff,secretLength); + KeyBuilder.LENGTH_HMAC_SHA_256_BLOCK_64, false); + key.setKey(secretBuffer, secretOff, secretLength); return key; } @@ -320,10 +327,10 @@ public short aesGCMEncrypt( short authTagStart, short authTagLen) { //Create the sun jce compliant aes key - if(keyLen != 32 && keyLen != 16){ + if (keyLen != 32 && keyLen != 16) { CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } - 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 { @@ -339,13 +346,14 @@ public short aesGCMEncrypt( CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } // Copy nonce - if(nonceLen != AES_GCM_NONCE_LENGTH){ + 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); + Util.arrayCopyNonAtomic(nonce, nonceStart, iv, (short) 0, AES_GCM_NONCE_LENGTH); // Init Cipher - GCMParameterSpec spec = new GCMParameterSpec(AES_GCM_TAG_LENGTH * 8, nonce,nonceStart,AES_GCM_NONCE_LENGTH); + GCMParameterSpec spec = new GCMParameterSpec(AES_GCM_TAG_LENGTH * 8, nonce, nonceStart, + AES_GCM_NONCE_LENGTH); try { cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, aesKey, spec); } catch (InvalidKeyException e) { @@ -357,13 +365,13 @@ public short aesGCMEncrypt( } // Create auth data byte[] aad = new byte[authDataLen]; - Util.arrayCopyNonAtomic(authData,authDataStart,aad,(short)0,authDataLen); + Util.arrayCopyNonAtomic(authData, authDataStart, aad, (short) 0, authDataLen); cipher.updateAAD(aad); // Encrypt secret short len = 0; byte[] outputBuf = new byte[cipher.getOutputSize(secretLen)]; try { - len = (short)(cipher.doFinal(secret,secretStart,secretLen,outputBuf,(short)0)); + len = (short) (cipher.doFinal(secret, secretStart, secretLen, outputBuf, (short) 0)); } catch (ShortBufferException e) { e.printStackTrace(); CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); @@ -375,10 +383,12 @@ public short aesGCMEncrypt( CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } // Extract Tag appended at the end. - Util.arrayCopyNonAtomic(outputBuf, (short)(len - AES_GCM_TAG_LENGTH),authTag,authTagStart,AES_GCM_TAG_LENGTH); + Util.arrayCopyNonAtomic(outputBuf, (short) (len - AES_GCM_TAG_LENGTH), authTag, authTagStart, + AES_GCM_TAG_LENGTH); //Copy the encrypted data - Util.arrayCopyNonAtomic(outputBuf, (short)0,encSecret,encSecretStart,(short)(len - AES_GCM_TAG_LENGTH)); - return (short)(len - AES_GCM_TAG_LENGTH); + Util.arrayCopyNonAtomic(outputBuf, (short) 0, encSecret, encSecretStart, + (short) (len - AES_GCM_TAG_LENGTH)); + return (short) (len - AES_GCM_TAG_LENGTH); } public boolean aesGCMDecrypt( @@ -398,13 +408,13 @@ public boolean aesGCMDecrypt( short authDataLen, byte[] authTag, short authTagStart, - short authTagLen) { + short authTagLen) { // Create the sun jce compliant aes key if (keyLen != 32 && keyLen != 16) { CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } java.security.Key aesKey = new SecretKeySpec(keyBuf, keyStart, keyLen, - "AES"); + "AES"); // Create the cipher javax.crypto.Cipher cipher = null; try { @@ -425,10 +435,10 @@ public boolean aesGCMDecrypt( } byte[] iv = new byte[AES_GCM_NONCE_LENGTH]; Util.arrayCopyNonAtomic(nonce, nonceStart, iv, (short) 0, - AES_GCM_NONCE_LENGTH); + AES_GCM_NONCE_LENGTH); // Init Cipher GCMParameterSpec spec = new GCMParameterSpec(authTagLen * 8, nonce, - nonceStart, AES_GCM_NONCE_LENGTH); + nonceStart, AES_GCM_NONCE_LENGTH); try { cipher.init(javax.crypto.Cipher.DECRYPT_MODE, aesKey, spec); } catch (InvalidKeyException e) { @@ -441,20 +451,20 @@ public boolean aesGCMDecrypt( // Create auth data byte[] aad = new byte[authDataLen]; Util.arrayCopyNonAtomic(authData, authDataStart, aad, (short) 0, - authDataLen); + 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); + encSecretLen); Util.arrayCopyNonAtomic(authTag, authTagStart, inputBuf, encSecretLen, - authTagLen); + authTagLen); // Decrypt short len = 0; byte[] outputBuf = new byte[cipher.getOutputSize((short) inputBuf.length)]; try { len = (short) (cipher.doFinal(inputBuf, (short) 0, - (short) inputBuf.length, outputBuf, (short) 0)); + (short) inputBuf.length, outputBuf, (short) 0)); } catch (AEADBadTagException e) { e.printStackTrace(); return false; @@ -475,22 +485,25 @@ public boolean aesGCMDecrypt( @Override public void getTrueRandomNumber(byte[] buf, short start, short length) { - Util.arrayCopy(entropyPool,(short)0,buf,start,length); + Util.arrayCopy(entropyPool, (short) 0, buf, start, length); } - - public HMACKey cmacKdf(byte[] keyMaterial, short keyMaterialStart, short keyMaterialLen, byte[] label, - short labelStart, short labelLen, byte[] context, short contextStart, short contextLength) { + + 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[] L = {0, 0, 1, + 0}; // [L] 256 bits - hardcoded 32 bits as per reference impl in keymaster. final byte[] zero = {0}; // byte - byte[] iBuf = new byte[]{0,0,0,0}; // [i] counter - 32 bits - byte[] keyOut = new byte[(short)(n*16)]; + byte[] iBuf = new byte[]{0, 0, 0, 0}; // [i] counter - 32 bits + byte[] keyOut = new byte[(short) (n * 16)]; Signature prf = Signature.getInstance(Signature.ALG_AES_CMAC_128, false); - AESKey key = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_256, false); + AESKey key = (AESKey) KeyBuilder + .buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_256, false); key.setKey(keyMaterial, keyMaterialStart); prf.init(key, Signature.MODE_SIGN); - byte i =1; + byte i = 1; short pos = 0; while (i <= n) { iBuf[3] = i; @@ -501,85 +514,95 @@ public HMACKey cmacKdf(byte[] keyMaterial, short keyMaterialStart, short keyMate pos = prf.sign(L, (short) 0, (short) 4, keyOut, pos); // 4 bytes of L - signature of 16 bytes i++; } - return createHMACKey(keyOut, (short)0, (short)keyOut.length); + return createHMACKey(keyOut, (short) 0, (short) keyOut.length); } @Override public short cmacKDF(KMPreSharedKey pSharedKey, byte[] label, - short labelStart, short labelLen, byte[] context, short contextStart, short contextLength, byte[] keyBuf, short keyStart) { + short labelStart, short labelLen, byte[] context, short contextStart, short contextLength, + byte[] keyBuf, short 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); + HMACKey hmacKey = cmacKdf(keyMaterial, keyMaterialStart, keyMaterialLen, label, labelStart, + labelLen, context, contextStart, contextLength); + return hmacKey.getKey(keyBuf, keyStart); } - - public short hmacSign(HMACKey key, byte[] data, short dataStart, short dataLength, byte[] mac, short macStart) { + + 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) { + byte[] mac, short macStart, short macLength) { hmacSignature.init(key, Signature.MODE_VERIFY); return hmacSignature.verify(data, dataStart, dataLength, mac, macStart, macLength); } @Override public short hmacKDF(KMMasterKey masterkey, byte[] data, short dataStart, - short dataLength, byte[] signature, short signatureStart) { + 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); + 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); - return hmacSign(key,data,dataStart,dataLength,mac,macStart); + 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); + 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) { + byte[] modBuffer, short modOff, short modLength, + byte[] inputDataBuf, short inputDataStart, short inputDataLength, + byte[] outputDataBuf, short outputDataStart) { KMCipher cipher = createRsaDecipher( - KMType.RSA_OAEP, KMType.SHA2_256, secret, secretStart, secretLength, modBuffer, modOff, modLength); + KMType.RSA_OAEP, KMType.SHA2_256, secret, secretStart, secretLength, modBuffer, modOff, + modLength); return cipher.doFinal( 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, - byte[] ivBuf, short ivStart, short ivLength, short macLength) { - switch (alg){ + 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) { + switch (alg) { case KMType.AES: case KMType.DES: - if(blockMode != KMType.GCM){ - KMCipher cipher = createSymmetricCipher(alg,purpose, blockMode, padding,keyBuf,keyStart,keyLength, - ivBuf,ivStart,ivLength); - return new KMOperationImpl(cipher); - }else { - KMCipher aesGcm = createAesGcmCipher(purpose,macLength,keyBuf,keyStart,keyLength,ivBuf,ivStart,ivLength); + if (blockMode != KMType.GCM) { + KMCipher cipher = createSymmetricCipher(alg, purpose, blockMode, padding, keyBuf, + keyStart, keyLength, + ivBuf, ivStart, ivLength); + return new KMOperationImpl(cipher); + } else { + KMCipher aesGcm = createAesGcmCipher(purpose, macLength, keyBuf, keyStart, keyLength, + ivBuf, ivStart, ivLength); return new KMOperationImpl(aesGcm); } case KMType.HMAC: - Signature signerVerifier = createHmacSignerVerifier(purpose,digest,keyBuf,keyStart,keyLength); + Signature signerVerifier = createHmacSignerVerifier(purpose, digest, keyBuf, keyStart, + keyLength); return new KMOperationImpl(signerVerifier); default: CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); @@ -589,8 +612,8 @@ public KMOperation initSymmetricOperation(byte purpose, byte alg, byte digest, b @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[] privKeyBuf, short privKeyStart, short privKeyLength, + byte[] pubModBuf, short pubModStart, short pubModLength) { if (alg == KMType.RSA) { switch (purpose) { case KMType.SIGN: @@ -605,27 +628,23 @@ public KMOperation initAsymmetricOperation(byte purpose, byte alg, byte padding, pubModStart, pubModLength); return new KMOperationImpl(signer); - case KMType.VERIFY: - Signature verifier = createRsaVerifier(digest, padding, pubModBuf, pubModStart, pubModLength); - return new KMOperationImpl(verifier); - case KMType.ENCRYPT: - KMCipher cipher = createRsaCipher(padding, digest, pubModBuf, pubModStart, pubModLength); - return new KMOperationImpl(cipher); case KMType.DECRYPT: KMCipher decipher = createRsaDecipher( - padding, digest, privKeyBuf, privKeyStart, privKeyLength, pubModBuf, pubModStart, pubModLength); + padding, digest, privKeyBuf, privKeyStart, privKeyLength, pubModBuf, pubModStart, + pubModLength); return new KMOperationImpl(decipher); + default: + KMException.throwIt(KMError.UNSUPPORTED_PURPOSE); } - }else if(alg == KMType.EC){ - switch(purpose){ + } else if (alg == KMType.EC) { + switch (purpose) { case KMType.SIGN: Signature signer = - createEcSigner(digest,privKeyBuf,privKeyStart,privKeyLength); + createEcSigner(digest, privKeyBuf, privKeyStart, privKeyLength); return new KMOperationImpl(signer); - case KMType.VERIFY: - Signature verifier = createEcVerifier(digest,pubModBuf,pubModStart,pubModLength); - return new KMOperationImpl(verifier); + default: + KMException.throwIt(KMError.UNSUPPORTED_PURPOSE); } } CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); @@ -633,16 +652,18 @@ public KMOperation initAsymmetricOperation(byte purpose, byte alg, byte padding, } 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); + short secretLength, byte[] modBuffer, short modOff, short modLength) { + byte cipherAlg = mapCipherAlg(KMType.RSA, (byte) padding, (byte) 0); if (cipherAlg == Cipher.ALG_RSA_PKCS1_OAEP) { - return createRsaOAEP256Cipher(KMType.DECRYPT,(byte)digest,secret,secretStart,secretLength,modBuffer,modOff,modLength); + return createRsaOAEP256Cipher(KMType.DECRYPT, (byte) digest, secret, secretStart, + secretLength, modBuffer, modOff, modLength); } - 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); + 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); key.setModulus(modBuffer, modOff, modLength); - rsaCipher.init(key,Cipher.MODE_DECRYPT); + rsaCipher.init(key, Cipher.MODE_DECRYPT); KMCipherImpl inst = new KMCipherImpl(rsaCipher); inst.setCipherAlgorithm(KMType.RSA); inst.setMode(KMType.DECRYPT); @@ -650,43 +671,45 @@ public KMCipher createRsaDecipher(short padding, short digest, byte[] secret, sh return inst; } - private KMCipher createRsaOAEP256Cipher(byte mode,byte digest, - byte[] secret, short secretStart, short secretLen, - byte[] modBuffer, short modOff, short modLength) { + private KMCipher createRsaOAEP256Cipher(byte mode, byte digest, + byte[] secret, short secretStart, short secretLen, + byte[] modBuffer, short modOff, short modLength) { // Convert byte arrays into keys byte[] exp = null; byte[] mod = new byte[modLength]; if (secret != null) { exp = new byte[secretLen]; Util.arrayCopyNonAtomic(secret, secretStart, exp, (short) 0, secretLen); - }else{ - exp = new byte[]{0x01,0x00,0x01}; + } else { + exp = new byte[]{0x01, 0x00, 0x01}; } - Util.arrayCopyNonAtomic(modBuffer,modOff,mod,(short)0,modLength); + Util.arrayCopyNonAtomic(modBuffer, modOff, mod, (short) 0, modLength); String modString = toHexString(mod); String expString = toHexString(exp); - BigInteger modInt = new BigInteger(modString,16); - BigInteger expInt = new BigInteger(expString,16); + BigInteger modInt = new BigInteger(modString, 16); + BigInteger expInt = new BigInteger(expString, 16); javax.crypto.Cipher rsaCipher = null; - try{ + try { KeyFactory kf = KeyFactory.getInstance("RSA"); // Create cipher with oaep padding OAEPParameterSpec oaepSpec = null; - if(digest == KMType.SHA2_256){ - oaepSpec= new OAEPParameterSpec("SHA-256", "MGF1", - MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT); - }else{ - oaepSpec= new OAEPParameterSpec("SHA1", "MGF1", - MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT); + if (digest == KMType.SHA2_256) { + oaepSpec = new OAEPParameterSpec("SHA-256", "MGF1", + MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT); + } else { + oaepSpec = new OAEPParameterSpec("SHA1", "MGF1", + MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT); } rsaCipher = javax.crypto.Cipher.getInstance("RSA/ECB/OAEPPadding", "SunJCE"); - if (mode == KMType.ENCRYPT){ + if (mode == KMType.ENCRYPT) { RSAPublicKeySpec pubSpec = new RSAPublicKeySpec(modInt, expInt); - java.security.interfaces.RSAPublicKey pubKey = (java.security.interfaces.RSAPublicKey) kf.generatePublic(pubSpec); + java.security.interfaces.RSAPublicKey pubKey = (java.security.interfaces.RSAPublicKey) kf + .generatePublic(pubSpec); rsaCipher.init(javax.crypto.Cipher.ENCRYPT_MODE, pubKey, oaepSpec); } else { RSAPrivateKeySpec privSpec = new RSAPrivateKeySpec(modInt, expInt); - java.security.interfaces.RSAPrivateKey privKey = (java.security.interfaces.RSAPrivateKey) kf.generatePrivate(privSpec); + java.security.interfaces.RSAPrivateKey privKey = (java.security.interfaces.RSAPrivateKey) kf + .generatePrivate(privSpec); rsaCipher.init(javax.crypto.Cipher.DECRYPT_MODE, privKey, oaepSpec); } } catch (NoSuchAlgorithmException e) { @@ -714,70 +737,78 @@ private KMCipher createRsaOAEP256Cipher(byte mode,byte digest, ret.setMode(mode); return ret; } - private String toHexString(byte[] num){ + + private String toHexString(byte[] num) { StringBuilder sb = new StringBuilder(); - for(int i = 0; i < num.length; i++){ - sb.append(String.format("%02X", num[i])) ; - } + for (int i = 0; i < num.length; i++) { + sb.append(String.format("%02X", num[i])); + } return sb.toString(); } - + public Signature createRsaSigner(short digest, short padding, byte[] secret, - short secretStart, short secretLength, byte[] modBuffer, - short modOff, short modLength) { - short alg = mapSignature256Alg(KMType.RSA, (byte)padding); + short secretStart, short secretLength, byte[] modBuffer, + short modOff, short modLength) { + short alg = mapSignature256Alg(KMType.RSA, (byte) padding); 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)) { + return createNoDigestSigner(padding, secret, secretStart, secretLength, + modBuffer, modOff, modLength); } - 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); + 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); key.setModulus(modBuffer, modOff, modLength); - rsaSigner.init(key,Signature.MODE_SIGN); + rsaSigner.init(key, Signature.MODE_SIGN); return rsaSigner; } private Signature createNoDigestSigner(short padding, - byte[] secret, short secretStart, short secretLength, - byte[] modBuffer, short modOff, short modLength) { - Cipher rsaCipher = Cipher.getInstance(Cipher.ALG_RSA_NOPAD,false); + byte[] secret, short secretStart, short secretLength, + byte[] modBuffer, short modOff, short modLength) { + Cipher rsaCipher = 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); + 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); + rsaCipher.init(key, Cipher.MODE_DECRYPT); + KMRsa2048NoDigestSignature inst = new KMRsa2048NoDigestSignature(rsaCipher, (byte) padding, + modBuffer, modOff, modLength); return inst; } - - public Signature createEcSigner(short digest, byte[] secret, short secretStart, short secretLength) { - short alg = mapSignature256Alg(KMType.EC,(byte)0); - Signature ecSigner; - if(digest == KMType.DIGEST_NONE) { - ecSigner = new KMEcdsa256NoDigestSignature(Signature.MODE_SIGN, secret, secretStart, secretLength); - } else { - ECPrivateKey key = (ECPrivateKey) KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PRIVATE, KeyBuilder.LENGTH_EC_FP_256, false); - key.setS(secret,secretStart,secretLength); - ecSigner = Signature.getInstance((byte)alg,false); - ecSigner.init(key,Signature.MODE_SIGN); - } + + public Signature createEcSigner(short digest, byte[] secret, short secretStart, + short secretLength) { + short alg = mapSignature256Alg(KMType.EC, (byte) 0); + Signature ecSigner; + if (digest == KMType.DIGEST_NONE) { + ecSigner = new KMEcdsa256NoDigestSignature(Signature.MODE_SIGN, secret, secretStart, + secretLength); + } else { + ECPrivateKey key = (ECPrivateKey) KeyBuilder + .buildKey(KeyBuilder.TYPE_EC_FP_PRIVATE, KeyBuilder.LENGTH_EC_FP_256, false); + key.setS(secret, secretStart, secretLength); + ecSigner = Signature.getInstance((byte) alg, false); + ecSigner.init(key, Signature.MODE_SIGN); + } return ecSigner; } - + public KMCipher createSymmetricCipher( - short cipherAlg, short mode, short blockMode, short padding, byte[] secret, short secretStart, short secretLength) { - return createSymmetricCipher(cipherAlg, mode, blockMode, padding, secret,secretStart,secretLength,null,(short)0,(short)0); + short cipherAlg, short mode, short blockMode, short padding, byte[] secret, short secretStart, + short secretLength) { + return createSymmetricCipher(cipherAlg, mode, blockMode, padding, secret, secretStart, + secretLength, null, (short) 0, (short) 0); } - - public KMCipher createSymmetricCipher(short alg, short purpose, short blockMode, short padding, byte[] secret, - short secretStart, short secretLength, - byte[] ivBuffer, short ivStart, short ivLength) { + + public KMCipher 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; @@ -795,35 +826,36 @@ public KMCipher createSymmetricCipher(short alg, short purpose, short blockMode, CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); break; } - short cipherAlg = mapCipherAlg((byte)alg,(byte)padding,(byte)blockMode); - switch(cipherAlg){ + short cipherAlg = mapCipherAlg((byte) alg, (byte) padding, (byte) blockMode); + switch (cipherAlg) { case Cipher.ALG_AES_BLOCK_128_CBC_NOPAD: - key = KeyBuilder.buildKey(KeyBuilder.TYPE_AES,len,false); - ((AESKey) key).setKey(secret,secretStart); - symmCipher = Cipher.getInstance((byte)cipherAlg, false); + key = KeyBuilder.buildKey(KeyBuilder.TYPE_AES, len, false); + ((AESKey) key).setKey(secret, secretStart); + symmCipher = Cipher.getInstance((byte) cipherAlg, false); symmCipher.init(key, mapPurpose(purpose), ivBuffer, ivStart, ivLength); break; case Cipher.ALG_AES_BLOCK_128_ECB_NOPAD: - key = KeyBuilder.buildKey(KeyBuilder.TYPE_AES,len,false); - ((AESKey) key).setKey(secret,secretStart); - symmCipher = Cipher.getInstance((byte)cipherAlg, false); + key = KeyBuilder.buildKey(KeyBuilder.TYPE_AES, len, false); + ((AESKey) key).setKey(secret, secretStart); + symmCipher = Cipher.getInstance((byte) cipherAlg, false); symmCipher.init(key, mapPurpose(purpose)); break; case Cipher.ALG_DES_CBC_NOPAD: - key = KeyBuilder.buildKey(KeyBuilder.TYPE_DES,len,false); - ((DESKey) key).setKey(secret,secretStart); - symmCipher = Cipher.getInstance((byte)cipherAlg, false); + key = KeyBuilder.buildKey(KeyBuilder.TYPE_DES, len, false); + ((DESKey) key).setKey(secret, secretStart); + symmCipher = Cipher.getInstance((byte) cipherAlg, false); //While sending back the iv send only 8 bytes. - symmCipher.init(key, mapPurpose(purpose), ivBuffer, ivStart, (short)8); + symmCipher.init(key, mapPurpose(purpose), ivBuffer, ivStart, (short) 8); break; case Cipher.ALG_DES_ECB_NOPAD: - key = KeyBuilder.buildKey(KeyBuilder.TYPE_DES,len,false); - ((DESKey) key).setKey(secret,secretStart); - symmCipher = Cipher.getInstance((byte)cipherAlg, false); + key = KeyBuilder.buildKey(KeyBuilder.TYPE_DES, len, false); + ((DESKey) key).setKey(secret, secretStart); + symmCipher = Cipher.getInstance((byte) cipherAlg, false); symmCipher.init(key, mapPurpose(purpose)); break; case Cipher.ALG_AES_CTR: // uses SUNJCE - return createAesCtrCipherNoPad(purpose, secret,secretStart,secretLength,ivBuffer,ivStart,ivLength); + return createAesCtrCipherNoPad(purpose, secret, secretStart, secretLength, ivBuffer, + ivStart, ivLength); default://This should never happen CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); break; @@ -835,26 +867,27 @@ public KMCipher createSymmetricCipher(short alg, short purpose, short blockMode, cipher.setBlockMode(blockMode); return cipher; } - private byte mapPurpose(short purpose){ - switch(purpose){ + + 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; + return Signature.MODE_SIGN; case KMType.VERIFY: return Signature.MODE_VERIFY; } return -1; } - private byte mapSignature256Alg(byte alg, byte padding){ - switch(alg){ + private byte mapSignature256Alg(byte alg, byte padding) { + switch (alg) { case KMType.RSA: - switch(padding){ + switch (padding) { case KMType.RSA_PKCS1_1_5_SIGN: - return Signature.ALG_RSA_SHA_256_PKCS1; + return Signature.ALG_RSA_SHA_256_PKCS1; case KMType.RSA_PSS: return Signature.ALG_RSA_SHA_256_PKCS1_PSS; } @@ -867,12 +900,12 @@ private byte mapSignature256Alg(byte alg, byte padding){ return -1; } - private byte mapCipherAlg(byte alg, byte padding, byte blockmode){ - switch(alg){ + private byte mapCipherAlg(byte alg, byte padding, byte blockmode) { + switch (alg) { case KMType.AES: - switch(blockmode){ + switch (blockmode) { case KMType.ECB: - return Cipher.ALG_AES_BLOCK_128_ECB_NOPAD; + return Cipher.ALG_AES_BLOCK_128_ECB_NOPAD; case KMType.CBC: return Cipher.ALG_AES_BLOCK_128_CBC_NOPAD; case KMType.CTR: @@ -882,7 +915,7 @@ private byte mapCipherAlg(byte alg, byte padding, byte blockmode){ } break; case KMType.DES: - switch(blockmode){ + switch (blockmode) { case KMType.ECB: return Cipher.ALG_DES_ECB_NOPAD; case KMType.CBC: @@ -890,7 +923,7 @@ private byte mapCipherAlg(byte alg, byte padding, byte blockmode){ } break; case KMType.RSA: - switch(padding){ + switch (padding) { case KMType.PADDING_NONE: return Cipher.ALG_RSA_NOPAD; case KMType.RSA_PKCS1_1_5_ENCRYPT: @@ -903,20 +936,21 @@ private byte mapCipherAlg(byte alg, byte padding, byte blockmode){ return -1; } - private KMCipher createAesCtrCipherNoPad(short mode, byte[] secret, short secretStart, short secretLength, byte[] ivBuffer, short ivStart, short ivLength) { - if(secretLength != 16 && secretLength != 32){ + private KMCipher createAesCtrCipherNoPad(short mode, byte[] secret, short secretStart, + short secretLength, byte[] ivBuffer, short ivStart, short ivLength) { + if (secretLength != 16 && secretLength != 32) { CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } - if(ivLength != 16){ + if (ivLength != 16) { CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } - if(mode != KMType.ENCRYPT && mode != KMType.DECRYPT){ + if (mode != KMType.ENCRYPT && mode != KMType.DECRYPT) { CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } //Create the sun jce compliant aes key byte[] keyMaterial = new byte[secretLength]; - Util.arrayCopyNonAtomic(secret,secretStart,keyMaterial,(short)0,secretLength); - java.security.Key aesKey = new SecretKeySpec(keyMaterial,(short)0,keyMaterial.length, "AES"); + Util.arrayCopyNonAtomic(secret, secretStart, keyMaterial, (short) 0, secretLength); + java.security.Key aesKey = new SecretKeySpec(keyMaterial, (short) 0, keyMaterial.length, "AES"); // Create the cipher javax.crypto.Cipher cipher = null; try { @@ -933,12 +967,15 @@ private KMCipher createAesCtrCipherNoPad(short mode, byte[] secret, short secret } // Copy nonce byte[] iv = new byte[ivLength]; - Util.arrayCopyNonAtomic(ivBuffer,ivStart,iv,(short)0,ivLength); + Util.arrayCopyNonAtomic(ivBuffer, ivStart, iv, (short) 0, ivLength); // Init Cipher IvParameterSpec ivSpec = new IvParameterSpec(iv); try { - if(mode == KMType.ENCRYPT) cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, aesKey, ivSpec); - else cipher.init(javax.crypto.Cipher.DECRYPT_MODE, aesKey, ivSpec); + if (mode == KMType.ENCRYPT) { + cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, aesKey, ivSpec); + } else { + cipher.init(javax.crypto.Cipher.DECRYPT_MODE, aesKey, ivSpec); + } } catch (InvalidKeyException e) { e.printStackTrace(); CryptoException.throwIt(CryptoException.INVALID_INIT); @@ -949,38 +986,43 @@ private KMCipher createAesCtrCipherNoPad(short mode, byte[] secret, short secret KMCipherImpl ret = new KMCipherImpl(cipher); ret.setCipherAlgorithm(KMType.AES); ret.setMode(mode); - ret.setPaddingAlgorithm((short)0); + ret.setPaddingAlgorithm((short) 0); ret.setBlockMode(KMType.CTR); return ret; } - - public Signature createHmacSignerVerifier(short purpose, short digest, byte[] secret, short secretStart, short secretLength) { + + public Signature createHmacSignerVerifier(short purpose, short digest, byte[] secret, + short secretStart, short secretLength) { short alg = Signature.ALG_HMAC_SHA_256; - if(digest != KMType.SHA2_256) CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - Signature hmacSignerVerifier = Signature.getInstance((byte)alg,false); - HMACKey key = (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC, (short)(secretLength*8), false); - key.setKey(secret,secretStart,secretLength); - hmacSignerVerifier.init(key,(byte)purpose); + if (digest != KMType.SHA2_256) { + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } + Signature hmacSignerVerifier = Signature.getInstance((byte) alg, false); + HMACKey key = (HMACKey) KeyBuilder + .buildKey(KeyBuilder.TYPE_HMAC, (short) (secretLength * 8), false); + key.setKey(secret, secretStart, secretLength); + hmacSignerVerifier.init(key, (byte) purpose); return hmacSignerVerifier; } - - public KMCipher createAesGcmCipher(short mode, short tagLen, byte[] secret, short secretStart, short secretLength, - byte[] ivBuffer, short ivStart, short ivLength) { - if(secretLength != 16 && secretLength != 32){ + + public KMCipher createAesGcmCipher(short mode, short tagLen, byte[] secret, short secretStart, + short secretLength, + byte[] ivBuffer, short ivStart, short ivLength) { + if (secretLength != 16 && secretLength != 32) { CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } - if(ivLength != AES_GCM_NONCE_LENGTH){ + if (ivLength != AES_GCM_NONCE_LENGTH) { CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } - if(mode != KMType.ENCRYPT && mode != KMType.DECRYPT){ + if (mode != KMType.ENCRYPT && mode != KMType.DECRYPT) { CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } //Create the sun jce compliant aes key byte[] keyMaterial = new byte[secretLength]; - Util.arrayCopyNonAtomic(secret,secretStart,keyMaterial,(short)0,secretLength); - java.security.Key aesKey = new SecretKeySpec(keyMaterial,(short)0,keyMaterial.length, "AES"); + Util.arrayCopyNonAtomic(secret, secretStart, keyMaterial, (short) 0, secretLength); + java.security.Key aesKey = new SecretKeySpec(keyMaterial, (short) 0, keyMaterial.length, "AES"); // Create the cipher javax.crypto.Cipher cipher = null; try { @@ -997,12 +1039,15 @@ public KMCipher createAesGcmCipher(short mode, short tagLen, byte[] secret, shor } // Copy nonce byte[] iv = new byte[AES_GCM_NONCE_LENGTH]; - Util.arrayCopyNonAtomic(ivBuffer,ivStart,iv,(short)0,AES_GCM_NONCE_LENGTH); + Util.arrayCopyNonAtomic(ivBuffer, ivStart, iv, (short) 0, AES_GCM_NONCE_LENGTH); // Init Cipher - GCMParameterSpec spec = new GCMParameterSpec(tagLen, iv,(short)0,AES_GCM_NONCE_LENGTH); + GCMParameterSpec spec = new GCMParameterSpec(tagLen, iv, (short) 0, AES_GCM_NONCE_LENGTH); try { - if(mode == KMType.ENCRYPT)mode = javax.crypto.Cipher.ENCRYPT_MODE; - else mode = javax.crypto.Cipher.DECRYPT_MODE; + if (mode == KMType.ENCRYPT) { + mode = javax.crypto.Cipher.ENCRYPT_MODE; + } else { + mode = javax.crypto.Cipher.DECRYPT_MODE; + } cipher.init(mode, aesKey, spec); } catch (InvalidKeyException e) { e.printStackTrace(); @@ -1014,7 +1059,7 @@ public KMCipher createAesGcmCipher(short mode, short tagLen, byte[] secret, shor KMCipherImpl ret = new KMCipherImpl(cipher); ret.setCipherAlgorithm(KMType.AES); ret.setMode(mode); - ret.setPaddingAlgorithm((short)0); + ret.setPaddingAlgorithm((short) 0); ret.setBlockMode(KMType.GCM); return ret; } @@ -1051,7 +1096,9 @@ public void newRandomNumber(byte[] num, short startOff, short length) { aesRngKey.setKey(entropyPool, (short) 0); aesRngCipher.init(aesRngKey, Cipher.MODE_ENCRYPT, aesICV, (short) 0, (short) 16); while (length > 0) { - if (length < len) len = length; + if (length < len) { + len = length; + } // increment rngCounter by one incrementCounter(); // copy the 8 byte rngCounter into the 16 byte rngCounter buffer. @@ -1076,8 +1123,11 @@ private void incrementCounter() { // 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 + 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]++; @@ -1090,7 +1140,9 @@ private void incrementCounter() { 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; + 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); @@ -1110,66 +1162,20 @@ public void addRngEntropy(byte[] num, short offset, short length) { } } - - public KMCipher createRsaCipher(short padding, short digest, byte[] modBuffer, short modOff, short modLength) { - byte cipherAlg = mapCipherAlg(KMType.RSA, (byte)padding, (byte)0); - if (cipherAlg == Cipher.ALG_RSA_PKCS1_OAEP) { - return createRsaOAEP256Cipher(KMType.ENCRYPT, (byte)digest, null,(short)0,(short)0,modBuffer,modOff,modLength); - } - 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}; - key.setExponent(exponent,(short)0,(short)3); - key.setModulus(modBuffer, modOff, modLength); - rsaCipher.init(key,Cipher.MODE_ENCRYPT); - KMCipherImpl inst = new KMCipherImpl(rsaCipher); - inst.setCipherAlgorithm(KMType.RSA); - inst.setMode(KMType.ENCRYPT); - inst.setPaddingAlgorithm(padding); - 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); - 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}; - key.setExponent(exponent,(short)0,(short)3); - key.setModulus(modBuffer, modOff, modLength); - rsaVerifier.init(key,Signature.MODE_VERIFY); - return rsaVerifier; - } - - public Signature createEcVerifier(short digest, byte[] pubKey, short pubKeyStart, short pubKeyLength) { - short alg = mapSignature256Alg(KMType.EC, (byte)0); - Signature ecVerifier; - //if(msgDigestAlg == MessageDigest.ALG_NULL) CryptoException.throwIt(CryptoException.NO_SUCH_ALGORITHM); - if(digest == KMType.DIGEST_NONE) { - ecVerifier = new KMEcdsa256NoDigestSignature(Signature.MODE_VERIFY, pubKey, pubKeyStart, pubKeyLength); - } else { - ECPublicKey key = (ECPublicKey) KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PUBLIC, KeyBuilder.LENGTH_EC_FP_256, false); - key.setW(pubKey,pubKeyStart,pubKeyLength); - ecVerifier = Signature.getInstance((byte)alg,false); - ecVerifier.init(key,Signature.MODE_VERIFY); - } - return ecVerifier; - } - @Override public KMAttestationCert getAttestationCert(boolean rsaCert) { return KMAttestationCertImpl.instance(rsaCert); } public short readCertificateChain(byte[] buf, short offset) { - short len = Util.getShort(certificateChain, (short)0); - Util.arrayCopyNonAtomic(certificateChain, (short)2, buf, offset, len); + 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); + return Util.getShort(certificateChain, (short) 0); } @Override @@ -1177,7 +1183,7 @@ public short ecSign256(KMAttestationKey attestationKey, byte[] inputDataBuf, short inputDataStart, short inputDataLength, byte[] outputDataBuf, short outputDataStart) { - ECPrivateKey key = ((KMECPrivateKey)attestationKey).getPrivateKey(); + ECPrivateKey key = ((KMECPrivateKey) attestationKey).getPrivateKey(); Signature signer = Signature .getInstance(Signature.ALG_ECDSA_SHA_256, false); @@ -1189,7 +1195,7 @@ public short ecSign256(KMAttestationKey attestationKey, @Override public void clearCertificateChain() { JCSystem.beginTransaction(); - Util.arrayFillNonAtomic(certificateChain, (short)0, CERT_CHAIN_MAX_SIZE, (byte) 0); + Util.arrayFillNonAtomic(certificateChain, (short) 0, CERT_CHAIN_MAX_SIZE, (byte) 0); JCSystem.commitTransaction(); } @@ -1214,7 +1220,7 @@ public void persistPartialCertificateChain(byte[] buf, short offset, JCSystem.beginTransaction(); Util.setShort(certificateChain, (short) 0, (short) (len + persistedLen)); Util.arrayCopyNonAtomic(buf, offset, certificateChain, - (short) (persistedLen+2), len); + (short) (persistedLen + 2), len); JCSystem.commitTransaction(); } @@ -1259,10 +1265,10 @@ public boolean isUpgrading() { public KMMasterKey createMasterKey(short keySizeBits) { if (masterKey == null) { AESKey key = (AESKey) KeyBuilder.buildKey( - KeyBuilder.TYPE_AES, keySizeBits, false); + KeyBuilder.TYPE_AES, keySizeBits, false); masterKey = new KMAESKey(key); short keyLen = (short) (keySizeBits / 8); - byte[] keyData = new byte[keyLen]; + byte[] keyData = new byte[keyLen]; getTrueRandomNumber(keyData, (short) 0, keyLen); masterKey.setKey(keyData, (short) 0); } @@ -1271,7 +1277,7 @@ public KMMasterKey createMasterKey(short keySizeBits) { @Override public KMAttestationKey createAttestationKey(byte[] keyData, short offset, - short length) { + 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); @@ -1283,13 +1289,13 @@ public KMAttestationKey createAttestationKey(byte[] keyData, short offset, @Override public KMPreSharedKey createPresharedKey(byte[] keyData, short offset, short length) { - short lengthInBits = (short)(length * 8); + 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); + false); preSharedKey = new KMHmacKey(key); } preSharedKey.setKey(keyData, offset, length); diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMOperationImpl.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMOperationImpl.java index 78c01302..761b388a 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMOperationImpl.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMOperationImpl.java @@ -18,43 +18,51 @@ import javacard.security.Signature; public class KMOperationImpl implements KMOperation { + private KMCipher cipher; private Signature signature; - public KMOperationImpl(KMCipher cipher){ + public KMOperationImpl(KMCipher cipher) { this.cipher = cipher; this.signature = null; } - public KMOperationImpl(Signature sign){ + public KMOperationImpl(Signature sign) { this.cipher = null; this.signature = sign; } @Override public short update(byte[] inputDataBuf, short inputDataStart, short inputDataLength, - byte[] outputDataBuf, short outputDataStart) { - return cipher.update(inputDataBuf,inputDataStart,inputDataLength,outputDataBuf,outputDataStart); + byte[] outputDataBuf, short outputDataStart) { + return cipher + .update(inputDataBuf, inputDataStart, inputDataLength, outputDataBuf, outputDataStart); } + @Override public short update(byte[] inputDataBuf, short inputDataStart, short inputDataLength) { - signature.update(inputDataBuf,inputDataStart,inputDataLength); - return 0; + signature.update(inputDataBuf, inputDataStart, inputDataLength); + return 0; } @Override - public short finish(byte[] inputDataBuf, short inputDataStart, short inputDataLength, byte[] outputDataBuf, short outputDataStart) { - return cipher.doFinal(inputDataBuf,inputDataStart,inputDataLength,outputDataBuf,outputDataStart); + public short finish(byte[] inputDataBuf, short inputDataStart, short inputDataLength, + byte[] outputDataBuf, short outputDataStart) { + return cipher + .doFinal(inputDataBuf, inputDataStart, inputDataLength, outputDataBuf, outputDataStart); } @Override - public short sign(byte[] inputDataBuf, short inputDataStart, short inputDataLength, byte[] signBuf, short signStart) { - return signature.sign(inputDataBuf,inputDataStart,inputDataLength,signBuf,signStart); + public short sign(byte[] inputDataBuf, short inputDataStart, short inputDataLength, + byte[] signBuf, short signStart) { + return signature.sign(inputDataBuf, inputDataStart, inputDataLength, signBuf, signStart); } @Override - public boolean verify(byte[] inputDataBuf, short inputDataStart, short inputDataLength, byte[] signBuf, short signStart, short signLength) { - return signature.verify(inputDataBuf,inputDataStart,inputDataLength,signBuf,signStart,signLength); + public boolean verify(byte[] inputDataBuf, short inputDataStart, short inputDataLength, + byte[] signBuf, short signStart, short signLength) { + return signature + .verify(inputDataBuf, inputDataStart, inputDataLength, signBuf, signStart, signLength); } @Override diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java index 855a3104..573be574 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java @@ -22,16 +22,19 @@ 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){ + 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); + if (len != 256) { + CryptoException.throwIt(CryptoException.INVALID_INIT); + } rsaModulus = new byte[256]; - Util.arrayCopyNonAtomic(mod,start,rsaModulus,(short)0,len); + Util.arrayCopyNonAtomic(mod, start, rsaModulus, (short) 0, len); } @Override @@ -44,7 +47,8 @@ public void init(Key key, byte b, byte[] bytes, short i, short i1) throws Crypto } @Override - public void setInitialDigest(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) throws CryptoException { + public void setInitialDigest(byte[] bytes, short i, short i1, byte[] bytes1, short i2, short i3) + throws CryptoException { } @Override @@ -77,31 +81,34 @@ 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); + 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 { + 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 { + // Public key operations not handled here. 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 { return false; } - private byte[] padData(byte[] buf, short start, short len){ + private byte[] padData(byte[] buf, short start, short len) { byte[] inputData = new byte[256]; - if(!isValidData(buf, start,len)){ + if (!isValidData(buf, start, len)) { CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } Util.arrayFillNonAtomic(inputData, (short) 0, (short) 256, (byte) 0x00); @@ -109,24 +116,27 @@ private byte[] padData(byte[] buf, short start, short len){ } 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{ + 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); + 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 = KMUtils.unsignedByteArrayCompare(buf, start, rsaModulus, (short) 0, len); - if (v > 0) return false; + if (len > 256) { + return false; + } else if (len == 256) { + short v = KMInteger.unsignedByteArrayCompare(buf, start, rsaModulus, (short) 0, len); + if (v > 0) { + return false; + } } } else {//pkcs1 no digest - if(len > 245){ + if (len > 245) { return false; } } diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java index 65e83415..c2b5c7f3 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java @@ -18,43 +18,44 @@ 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 + 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 + 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 + 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 + 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[] leapYearMsec = { - 0, 0, 0, 0x07, (byte) 0x5C, (byte) 0xD7, (byte) 0x88, 0x00}; //31622400000; + 0, 0, 0, 0, (byte) 0x9C, (byte) 0xBE, (byte) 0xBD, 0x50}; // 2629746000 msec + 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 + 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) 0xEB, 0x0C, 0x00};//126230400000 + 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 + 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 + 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 + 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 + 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 + 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) { + boolean utcFlag) { short yrsCount = 0; short monthCount = 1; @@ -66,48 +67,48 @@ public static short convertToDate(short time, byte[] scratchPad, 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()); + 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 (unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2020, (short) 0, - (short) 8) < 0) { + if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2020, (short) 0, + (short) 8) < 0) { KMException.throwIt(KMError.INVALID_ARGUMENT); } if (utcFlag - && unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, - (short) 0, (short) 8) >= 0) { + && KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, + (short) 0, (short) 8) >= 0) { KMException.throwIt(KMError.INVALID_ARGUMENT); } - if (unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, (short) 0, - (short) 8) < 0) { + if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, (short) 0, + (short) 8) < 0) { Util.arrayCopyNonAtomic(firstJan2020, (short) 0, scratchPad, (short) 8, - (short) 8); + (short) 8); subtract(scratchPad, (short) 0, (short) 8, (short) 16); Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); + (short) 8); } else { from2020 = false; Util.arrayCopyNonAtomic(firstJan2051, (short) 0, scratchPad, (short) 8, - (short) 8); + (short) 8); subtract(scratchPad, (short) 0, (short) 8, (short) 16); Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); + (short) 8); } // divide the given time with four yrs msec count - if (unsignedByteArrayCompare(scratchPad, (short) 0, fourYrsMsec, (short) 0, - (short) 8) >= 0) { + if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, fourYrsMsec, (short) 0, + (short) 8) >= 0) { Util.arrayCopyNonAtomic(fourYrsMsec, (short) 0, scratchPad, (short) 8, - (short) 8); + (short) 8); yrsCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); // quotient - // is - // multiple - // of 4 + // 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); + (short) 8); } //Get the leap year index starting from the (base Year + yrsCount) Year. @@ -116,29 +117,33 @@ && unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, // 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))) { + (KMInteger + .unsignedByteArrayCompare(scratchPad, (short) 0, leapYearMsec, (short) 0, (short) 8) + >= 0)) || + ((leapYrIdx != 0) && + (KMInteger + .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); + (short) 8, (short) 8); } else { Util.arrayCopyNonAtomic(yearMsec, (short) 0, scratchPad, (short) 8, - (short) 8); + (short) 8); } subtract(scratchPad, (short) 0, (short) 8, (short) 16); Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); + (short) 8); if (((short) (i + 1) == leapYrIdx)) { - if (unsignedByteArrayCompare(scratchPad, (short) 0, leapYearMsec, - (short) 0, (short) 8) < 0) { + if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, leapYearMsec, + (short) 0, (short) 8) < 0) { break; } } else { - if (unsignedByteArrayCompare(scratchPad, (short) 0, yearMsec, - (short) 0, (short) 8) < 0) { + if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, yearMsec, + (short) 0, (short) 8) < 0) { break; } } @@ -146,40 +151,41 @@ && unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, } // total yrs from 1970 - if (from2020) + if (from2020) { yrsCount = (short) (year2020 + yrsCount); - else + } else { yrsCount = (short) (year2051 + yrsCount); + } // divide the given time with one month msec count - if (unsignedByteArrayCompare(scratchPad, (short) 0, oneMonthMsec, (short) 0, - (short) 8) >= 0) { + if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, oneMonthMsec, (short) 0, + (short) 8) >= 0) { 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); + (short) 8, (short) 8); } else { // 28 days Util.arrayCopyNonAtomic(febMonthMsec, (short) 0, scratchPad, - (short) 8, (short) 8); + (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); + scratchPad, (short) 8, (short) 8); } else { // 30 Days Util.arrayCopyNonAtomic(ThirtDaysMonthMsec, (short) 0, scratchPad, - (short) 8, (short) 8); + (short) 8, (short) 8); } - if (unsignedByteArrayCompare(scratchPad, (short) 0, scratchPad, (short) 8, - (short) 8) >= 0) { + if (KMInteger.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); + (short) 8); } else { break; } @@ -188,44 +194,44 @@ && unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, } // divide the given time with one day msec count - if (unsignedByteArrayCompare(scratchPad, (short) 0, oneDayMsec, (short) 0, - (short) 8) >= 0) { + if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, oneDayMsec, (short) 0, + (short) 8) >= 0) { Util.arrayCopyNonAtomic(oneDayMsec, (short) 0, scratchPad, (short) 8, - (short) 8); + (short) 8); dayCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); dayCount++; Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); + (short) 8); } // divide the given time with one hour msec count - if (unsignedByteArrayCompare(scratchPad, (short) 0, oneHourMsec, (short) 0, - (short) 8) >= 0) { + if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, oneHourMsec, (short) 0, + (short) 8) >= 0) { Util.arrayCopyNonAtomic(oneHourMsec, (short) 0, scratchPad, (short) 8, - (short) 8); + (short) 8); hhCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); + (short) 8); } // divide the given time with one minute msec count - if (unsignedByteArrayCompare(scratchPad, (short) 0, oneMinMsec, (short) 0, - (short) 8) >= 0) { + if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, oneMinMsec, (short) 0, + (short) 8) >= 0) { Util.arrayCopyNonAtomic(oneMinMsec, (short) 0, scratchPad, (short) 8, - (short) 8); + (short) 8); mmCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); + (short) 8); } // divide the given time with one second msec count - if (unsignedByteArrayCompare(scratchPad, (short) 0, oneSecMsec, (short) 0, - (short) 8) >= 0) { + if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, oneSecMsec, (short) 0, + (short) 8) >= 0) { Util.arrayCopyNonAtomic(oneSecMsec, (short) 0, scratchPad, (short) 8, - (short) 8); + (short) 8); ssCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); + (short) 8); } // Now convert to ascii string YYMMDDhhmmssZ or YYYYMMDDhhmmssZ @@ -238,38 +244,21 @@ && unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, len += numberToString(ssCount, scratchPad, len); scratchPad[len] = Z; len++; - if (utcFlag) + if (utcFlag) { return KMByteBlob.instance(scratchPad, (short) 2, (short) (len - 2)); // YY - else + } else { 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) { + short offset) { byte zero = 0x30; byte len = 2; byte digit; - if (number > 999) + if (number > 999) { len = 4; + } byte index = len; while (index > 0) { digit = (byte) (number % 10); @@ -284,7 +273,7 @@ public static short numberToString(short number, byte[] scratchPad, // 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 remainder) { short expCnt = 1; short q = 0; // first increase divisor so that it becomes greater then dividend. @@ -311,7 +300,7 @@ public static void copy(byte[] buf, short from, short to) { } public static byte compare(byte[] buf, short lhs, short rhs) { - return unsignedByteArrayCompare(buf, lhs, buf, rhs, (short) 8); + return KMInteger.unsignedByteArrayCompare(buf, lhs, buf, rhs, (short) 8); } public static void shiftLeft(byte[] buf, short start) { @@ -322,10 +311,11 @@ public static void shiftLeft(byte[] buf, short start) { 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) + if (tmp < 0) { carry = 1; - else + } else { carry = 0; + } index--; } } @@ -339,10 +329,11 @@ public static void shiftRight(byte[] buf, short start) { 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) + if (tmp == 1) { carry = (byte) 0x80; - else + } else { carry = 0; + } index++; } } @@ -354,8 +345,9 @@ public static 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) + if (tmp > 255) { carry = 1; // max unsigned byte value is 255 + } buf[(short) (result + index)] = (byte) (tmp & (byte) 0xFF); index--; } @@ -381,25 +373,25 @@ public static void subtract(byte[] buf, short op1, short op2, short result) { index--; } } - + public static short countTemporalCount(byte[] bufTime, short timeOff, - short timeLen, byte[] scratchPad, short offset) { + 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); + bufTime, + timeOff, + scratchPad, + (short) (offset + 8 - timeLen), + timeLen); Util.arrayCopyNonAtomic(oneMonthMsec, (short) 0, scratchPad, (short) (offset + 8), - (short) 8); + (short) 8); 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) { + if ((short) (year % 4) == (short) 0) { + if (((short) (year % 100) == (short) 0) && + ((short) (year % 400)) != (short) 0) { return false; } return true; @@ -409,8 +401,8 @@ public static boolean isLeapYear(short year) { 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))) { + for (short i = 0; i < 4; i++) { + if (isLeapYear((short) (newBaseYr + i))) { return i; } } diff --git a/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java b/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java index a6308513..bc599510 100644 --- a/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java +++ b/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java @@ -1,2938 +1,3358 @@ -/* - * 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.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.util.Arrays; -import java.util.Random; - -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_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 - // 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) 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); - - 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_PRESHARED_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[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)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++){ - 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(); - } - - 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 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(); - 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); - - // PKCS1 v1.5 randomizes padding so every result should be different. - Assert.assertFalse(Arrays.equals(cipherText1, cipherText2)); - - 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); - - // 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); - - 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); - } - 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); - 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); - 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(); - } - - 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); - 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]; - 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); - } - 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( - 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)); - } - } - - opHandle = KMInteger.uint_64(opHandleBuf, (short) 0); - if (keyPurpose == KMType.VERIFY) { - 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, KMError.OK); - } - 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 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(); - } - 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); - 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); - 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) { - 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.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 javacard.security.ECPublicKey; +import javacard.security.KeyBuilder; +import javacard.security.KeyPair; +import javacard.security.RSAPublicKey; +import javacard.security.Signature; +import javacardx.crypto.Cipher; + +import java.math.BigInteger; +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SignatureException; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.ECPublicKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.InvalidParameterSpecException; +import java.security.spec.MGF1ParameterSpec; +import java.security.spec.RSAPublicKeySpec; +import java.util.Arrays; +import java.util.Random; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.OAEPParameterSpec; +import javax.crypto.spec.PSource; +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_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 + // 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) 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); + + 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_PRESHARED_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(); + 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(); + 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(byte[] buf, short off, short buflen) { + 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, + buf, off, buflen); + 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; + } + + private short extractKeyBlobArray(short keyBlob) { + return extractKeyBlobArray(KMByteBlob.cast(keyBlob).getBuffer(), KMByteBlob + .cast(keyBlob).getStartOff(), KMByteBlob.cast(keyBlob).length()); + } + + @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()); + + 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]; + byte[] transportKeyMaterial = new byte[32]; + cryptoProvider.newRandomNumber(transportKeyMaterial, (short) 0, (short) 32); + byte[] nonce = new byte[12]; + cryptoProvider.newRandomNumber(nonce, (short) 0, (short) 12); + byte[] authData = "Auth Data".getBytes(); + 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) 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++) { + 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); + + byte[] output = new byte[256]; + short outlen = rsaOaepEncryptMessage(wrappingKeyBlob, KMType.SHA2_256, + maskedTransportKey, (short) 0, (short) maskedTransportKey.length, + output, (short) 0); + Assert.assertTrue((outlen == 256)); + byte[] encTransportKey = new byte[outlen]; + Util.arrayCopyNonAtomic(output, (short) 0, encTransportKey, (short) 0, + outlen); + //Clean the heap. + KMRepository.instance().clean(); + 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); + 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(); + 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); + 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); + 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(); + } + + public short getPublicKey(byte[] keyBlob, short off, short len, + byte[] pubKey, short pubKeyOff) { + short keyBlobPtr = extractKeyBlobArray(keyBlob, off, len); + short arrayLen = KMArray.cast(keyBlobPtr).length(); + if (arrayLen < 5) { + return 0; + } + short pubKeyPtr = KMArray.cast(keyBlobPtr).get( + KMKeymasterApplet.KEY_BLOB_PUB_KEY); + Util.arrayCopy(KMByteBlob.cast(pubKeyPtr).getBuffer(), + KMByteBlob.cast(pubKeyPtr).getStartOff(), pubKey, pubKeyOff, + KMByteBlob.cast(pubKeyPtr).length()); + return KMByteBlob.cast(pubKeyPtr).length(); + } + + private String toHexString(byte[] num) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < num.length; i++) { + sb.append(String.format("%02X", num[i])); + } + return sb.toString(); + } + + public short rsaEncryptMessage(byte[] keyBlob, short padding, short digest, byte[] input, + short inputOff, short inputlen, + byte[] output, short outputOff) { + byte alg = Cipher.ALG_RSA_PKCS1; + byte[] tmp = null; + short inLen = inputlen; + if (padding == KMType.PADDING_NONE) { + alg = Cipher.ALG_RSA_NOPAD; + // Length cannot be greater then key size according to JcardSim + if (inLen >= 256) { + return 0; + } + // make input equal to 255 bytes + tmp = new byte[255]; + Util.arrayFillNonAtomic(tmp, (short) 0, (short) 255, (byte) 0); + Util.arrayCopyNonAtomic( + input, + inputOff, + tmp, (short) (255 - inLen), inLen); + inLen = 255; + inputOff = 0; + } else if (padding == KMType.RSA_PKCS1_1_5_ENCRYPT) { + tmp = input; + } else { + /*Fail */ + Assert.assertTrue(false); + } + byte[] pubKey = new byte[256]; + KeyPair rsaKeyPair = new KeyPair(KeyPair.ALG_RSA, KeyBuilder.LENGTH_RSA_2048); + RSAPublicKey rsaPubKey = (RSAPublicKey) rsaKeyPair.getPublic(); + if (0 == getPublicKey(keyBlob, (short) 0, (short) keyBlob.length, pubKey, (short) 0)) { + return 0; + } + + byte[] exponent = new byte[]{0x01, 0x00, 0x01}; + rsaPubKey.setModulus(pubKey, (short) 0, (short) pubKey.length); + rsaPubKey.setExponent(exponent, (short) 0, (short) exponent.length); + + Cipher rsaCipher = Cipher.getInstance(alg, false); + rsaCipher.init(rsaPubKey, Cipher.MODE_ENCRYPT); + return rsaCipher.doFinal(tmp, inputOff, inLen, output, outputOff); + } + + public short rsaOaepEncryptMessage(byte[] keyBlob, short digest, byte[] input, short inputOff, + short inputlen, + byte[] output, short outputOff) { + byte[] mod = new byte[256]; + if (0 == getPublicKey(keyBlob, (short) 0, (short) keyBlob.length, mod, (short) 0)) { + return 0; + } + byte[] exponent = new byte[]{0x01, 0x00, 0x01}; + + // Convert byte arrays into keys + String modString = toHexString(mod); + String expString = toHexString(exponent); + BigInteger modInt = new BigInteger(modString, 16); + BigInteger expInt = new BigInteger(expString, 16); + javax.crypto.Cipher rsaCipher = null; + try { + KeyFactory kf = KeyFactory.getInstance("RSA"); + // Create cipher with oaep padding + OAEPParameterSpec oaepSpec = null; + if (digest == KMType.SHA2_256) { + oaepSpec = new OAEPParameterSpec("SHA-256", "MGF1", + MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT); + } else { + oaepSpec = new OAEPParameterSpec("SHA1", "MGF1", + MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT); + } + rsaCipher = javax.crypto.Cipher.getInstance("RSA/ECB/OAEPPadding", "SunJCE"); + + RSAPublicKeySpec pubSpec = new RSAPublicKeySpec(modInt, expInt); + java.security.interfaces.RSAPublicKey pubKey = (java.security.interfaces.RSAPublicKey) kf + .generatePublic(pubSpec); + rsaCipher.init(javax.crypto.Cipher.ENCRYPT_MODE, pubKey, oaepSpec); + byte[] cipherOut = rsaCipher.doFinal(input, inputOff, inputlen); + + if (cipherOut != null) { + Util.arrayCopyNonAtomic(cipherOut, (short) 0, output, outputOff, (short) cipherOut.length); + } + return (short) cipherOut.length; + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (InvalidKeySpecException e) { + e.printStackTrace(); + } catch (InvalidKeyException e) { + e.printStackTrace(); + } catch (InvalidAlgorithmParameterException e) { + e.printStackTrace(); + } catch (NoSuchPaddingException e) { + e.printStackTrace(); + } catch (NoSuchProviderException e) { + e.printStackTrace(); + } catch (IllegalBlockSizeException e) { + e.printStackTrace(); + } catch (BadPaddingException e) { + e.printStackTrace(); + } + return 0; + } + + public boolean ecNoDigestVerifyMessage(byte[] input, short inputOff, + short inputlen, byte[] sign, short signOff, short signLen, + byte[] keyBlob) { + KeyFactory kf; + byte[] pubKey = new byte[128]; + short keyStart = 0; + short keyLength = getPublicKey(keyBlob, (short) 0, (short) keyBlob.length, + pubKey, (short) 0); + if (keyLength == 0) { + return false; + } + try { + java.security.Signature sunSigner = java.security.Signature.getInstance( + "NONEwithECDSA", "SunEC"); + kf = KeyFactory.getInstance("EC"); + AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC", + "SunEC"); + // Supported curve secp256r1 + parameters.init(new ECGenParameterSpec("secp256r1")); + ECParameterSpec ecParameters = parameters + .getParameterSpec(ECParameterSpec.class); + + // Check if the first byte is 04 and remove it. + if (pubKey[keyStart] == 0x04) { + // uncompressed format. + keyStart++; + keyLength--; + } + short i = 0; + byte[] pubx = new byte[keyLength / 2]; + for (; i < keyLength / 2; i++) { + pubx[i] = pubKey[keyStart + i]; + } + byte[] puby = new byte[keyLength / 2]; + for (i = 0; i < keyLength / 2; i++) { + puby[i] = pubKey[keyStart + keyLength / 2 + i]; + } + BigInteger bIX = new BigInteger(pubx); + BigInteger bIY = new BigInteger(puby); + ECPoint point = new ECPoint(bIX, bIY); + ECPublicKeySpec pubkeyspec = new ECPublicKeySpec(point, ecParameters); + java.security.interfaces.ECPublicKey ecPubkey = (java.security.interfaces.ECPublicKey) kf + .generatePublic(pubkeyspec); + sunSigner.initVerify(ecPubkey); + sunSigner.update(input, inputOff, inputlen); + return sunSigner.verify(sign, signOff, signLen); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (NoSuchProviderException e) { + e.printStackTrace(); + } catch (InvalidParameterSpecException e) { + e.printStackTrace(); + } catch (InvalidKeySpecException e) { + e.printStackTrace(); + } catch (InvalidKeyException e) { + e.printStackTrace(); + } catch (SignatureException e) { + e.printStackTrace(); + } + return false; + } + + public boolean ecVerifyMessage(byte[] input, short inputOff, short inputlen, + byte[] sign, short signOff, short signLen, byte[] keyBlob) { + Signature ecVerifier; + byte[] pubKey = new byte[128]; + short len = getPublicKey(keyBlob, (short) 0, (short) keyBlob.length, + pubKey, (short) 0); + if (len == 0) { + return false; + } + ECPublicKey key = (ECPublicKey) KeyBuilder.buildKey( + KeyBuilder.TYPE_EC_FP_PUBLIC, KeyBuilder.LENGTH_EC_FP_256, false); + key.setW(pubKey, (short) 0, len); + ecVerifier = Signature.getInstance(Signature.ALG_ECDSA_SHA_256, false); + ecVerifier.init(key, Signature.MODE_VERIFY); + return ecVerifier.verify(input, inputOff, inputlen, sign, signOff, signLen); + } + + public boolean rsaVerifyMessage(byte[] input, short inputOff, short inputlen, byte[] sign, + short signOff, short signLen, + short digest, short padding, byte[] keyBlob) { + if (digest == KMType.DIGEST_NONE || padding == KMType.PADDING_NONE) { + return false; + } + byte[] pubKey = new byte[256]; + if (0 == getPublicKey(keyBlob, (short) 0, (short) keyBlob.length, pubKey, (short) 0)) { + return false; + } + short alg = Signature.ALG_RSA_SHA_256_PKCS1_PSS; + + if (padding == KMType.RSA_PKCS1_1_5_SIGN) { + alg = Signature.ALG_RSA_SHA_256_PKCS1; + } + + 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}; + key.setExponent(exponent, (short) 0, (short) exponent.length); + key.setModulus(pubKey, (short) 0, (short) pubKey.length); + rsaVerifier.init(key, Signature.MODE_VERIFY); + return rsaVerifier.verify(input, inputOff, inputlen, sign, signOff, signLen); + } + + 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 testUnsupportedBlockMode() { + 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); + short desPkcs7Params = getAesDesParams(KMType.DES, (byte) KMType.CTR, + KMType.PKCS7, new byte[12]); + short ret = begin(KMType.ENCRYPT, + KMByteBlob.instance(keyBlob, (short) 0, (short) keyBlob.length), + KMKeyParameters.instance(desPkcs7Params), (short) 0); + Assert.assertTrue(ret == KMError.UNSUPPORTED_BLOCK_MODE); + cleanUp(); + } + + @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(); + 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 = new byte[256]; + short cipherText1Len = rsaEncryptMessage(keyBlob, KMType.RSA_PKCS1_1_5_ENCRYPT, + KMType.DIGEST_NONE, + message, (short) 0, (short) message.length, + cipherText1, (short) 0); + Assert.assertEquals((2048 / 8), cipherText1Len); + + pkcs1Params = getRsaParams(KMType.DIGEST_NONE, + KMType.RSA_PKCS1_1_5_ENCRYPT); + byte[] cipherText2 = new byte[256]; + short cipherText2Len = rsaEncryptMessage(keyBlob, KMType.RSA_PKCS1_1_5_ENCRYPT, + KMType.DIGEST_NONE, + message, (short) 0, (short) message.length, + cipherText2, (short) 0); + Assert.assertEquals((2048 / 8), cipherText2Len); + + // PKCS1 v1.5 randomizes padding so every result should be different. + Assert.assertFalse(Arrays.equals(cipherText1, cipherText2)); + + 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); + + // 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); + + 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); + } + 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 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); + 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); + 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(); + } + + 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(); + byte[] cipherData = new byte[256]; + short cipherDataLen = 0; + //Encrypt + if (padding == KMType.RSA_OAEP) { + cipherDataLen = rsaOaepEncryptMessage(keyBlob, digest, plainData, + (short) 0, (short) plainData.length, cipherData, (short) 0); + } else { + cipherDataLen = rsaEncryptMessage(keyBlob, padding, digest, plainData, + (short) 0, (short) plainData.length, cipherData, (short) 0); + } + Assert.assertTrue((cipherDataLen == 256)); + inParams = getRsaParams(digest, padding); + short 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; + } + boolean verify = rsaVerifyMessage(plainData, (short) 0, (short) plainData.length, + signatureData, (short) 0, (short) signatureData.length, + digest, padding, keyBlob); + Assert.assertTrue(verify); + } + + 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); + boolean verify = false; + if (digest == KMType.DIGEST_NONE) { + verify = ecNoDigestVerifyMessage(plainData, (short) 0, (short) plainData.length, + signatureData, (short) 0, (short) signatureData.length, + keyBlob); + } else { + verify = ecVerifyMessage(plainData, (short) 0, (short) plainData.length, + signatureData, (short) 0, (short) signatureData.length, + keyBlob); + } + Assert.assertTrue(verify); + } + + 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); + 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]; + 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); + } + 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( + 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)); + } + } + + opHandle = KMInteger.uint_64(opHandleBuf, (short) 0); + if (keyPurpose == KMType.VERIFY) { + 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, KMError.OK); + } + 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 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(); + } + 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); + 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); + 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) { + 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/build.xml b/Applet/build.xml index c08e095f..4a14664e 100644 --- a/Applet/build.xml +++ b/Applet/build.xml @@ -1,26 +1,26 @@ - + - - - - - - - + + + + + + + - + - + - + - + - + \ No newline at end of file diff --git a/Applet/src/com/android/javacard/keymaster/KMArray.java b/Applet/src/com/android/javacard/keymaster/KMArray.java index 61139e23..f2206474 100644 --- a/Applet/src/com/android/javacard/keymaster/KMArray.java +++ b/Applet/src/com/android/javacard/keymaster/KMArray.java @@ -22,24 +22,29 @@ /** * KMArray represents an array of KMTypes. Array is the sequence of elements of one or more sub - * types of KMType. It also acts as a vector of one subtype of KMTypes on the lines of class KMArray + * types of KMType. It also acts as a vector of one subtype of KMTypes on the lines of class + * KMArray * , where subType is subclass of KMType. Vector is the sequence of elements of one sub * type e.g. KMType.BYTE_BLOB_TYPE. The KMArray instance maps to the CBOR type array. KMArray is a * KMType and it further extends the value field in TLV_HEADER as ARRAY_HEADER struct{short subType; - * short length;} followed by sequence of short pointers to KMType instances. The subType can be - * 0 if this is an array or subType is short KMType value e.g. KMType.BYTE_BLOB_TYPE if this is a + * short length;} followed by sequence of short pointers to KMType instances. The subType can be 0 + * if this is an array or subType is short KMType value e.g. KMType.BYTE_BLOB_TYPE if this is a * vector of that sub type. */ public class KMArray extends KMType { + public static final short ANY_ARRAY_LENGTH = 0x1000; private static final short ARRAY_HEADER_SIZE = 4; private static KMArray prototype; private static short instPtr; - private KMArray() {} + private KMArray() { + } private static KMArray proto(short ptr) { - if (prototype == null) prototype = new KMArray(); + if (prototype == null) { + prototype = new KMArray(); + } instPtr = ptr; return prototype; } @@ -72,13 +77,17 @@ public static short instance(short length, byte type) { } public static KMArray cast(short ptr) { - if (heap[ptr] != ARRAY_TYPE) ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + if (heap[ptr] != ARRAY_TYPE) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } return proto(ptr); } public void add(short index, short objPtr) { short len = length(); - if (index >= len) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + if (index >= len) { + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + } Util.setShort( heap, (short) (instPtr + TLV_HEADER_SIZE + ARRAY_HEADER_SIZE + (short) (index * 2)), @@ -87,7 +96,9 @@ public void add(short index, short objPtr) { public short get(short index) { short len = length(); - if (index >= len) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + if (index >= len) { + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + } return Util.getShort( heap, (short) (instPtr + TLV_HEADER_SIZE + ARRAY_HEADER_SIZE + (short) (index * 2))); } diff --git a/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java b/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java index a472ff27..487dccc7 100644 --- a/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java +++ b/Applet/src/com/android/javacard/keymaster/KMAttestationCert.java @@ -23,6 +23,7 @@ * instance of cert. */ public interface KMAttestationCert { + /** * Set verified boot hash. * @@ -63,12 +64,13 @@ public interface KMAttestationCert { * @return instance of KMAttestationCert. */ KMAttestationCert makeUniqueId(byte[] scratchpad, short scratchPadOff, byte[] creationTime, - short creationTimeOff, short creationTimeLen, byte[] attestAppId, - short attestAppIdOff, short attestAppIdLen, byte resetSinceIdRotation, - KMMasterKey masterKey); + short creationTimeOff, short creationTimeLen, byte[] attestAppId, + short attestAppIdOff, short attestAppIdLen, byte resetSinceIdRotation, + KMMasterKey masterKey); /** - * Set start time received from creation/activation time tag. Used for certificate's valid period. + * Set start time received from creation/activation time tag. Used for certificate's valid + * period. * * @param obj This is a KMByteBlob object containing start time. * @param scratchpad Buffer to store intermediate results. @@ -78,17 +80,18 @@ KMAttestationCert makeUniqueId(byte[] scratchpad, short scratchPadOff, byte[] cr /** - * Set expiry time received from expiry time tag or ca certificates expiry time. - * Used for certificate's valid period. + * Set expiry time received from expiry time tag or ca certificates expiry time. Used for + * certificate's valid period. * * @param usageExpiryTimeObj This is a KMByteBlob containing expiry time. - * @param certExpirtyTimeObj This is a KMByteblob containing expirty time extracted from certificate. + * @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 usageExpiryTimeObj, - short certExpirtyTimeObj, byte[] scratchPad, short offset); + short certExpirtyTimeObj, byte[] scratchPad, short offset); /** * Set device lock status received during booting time or due to device lock command. @@ -115,12 +118,12 @@ KMAttestationCert notAfter(short usageExpiryTimeObj, KMAttestationCert attestationChallenge(short obj); /** - * Set extension tag received from key characteristics which needs to be added to android extension. - * This method will called once for each tag. + * Set extension tag received from key characteristics which needs to be added to android + * extension. This method will called once for each tag. * * @param tag is the KMByteBlob containing KMTag. - * @param hwEnforced is true if the tag has to be added to hw enforced list or - * else added to sw enforced list. + * @param hwEnforced is true if the tag has to be added to hw enforced list or else added to sw + * enforced list. * @return instance of KMAttestationCert */ KMAttestationCert extensionTag(short tag, boolean hwEnforced); @@ -166,7 +169,6 @@ KMAttestationCert notAfter(short usageExpiryTimeObj, /** * Build the certificate. After this method the certificate is ready. - * */ void build(); } diff --git a/Applet/src/com/android/javacard/keymaster/KMAttestationKey.java b/Applet/src/com/android/javacard/keymaster/KMAttestationKey.java index 8582d2b2..3d626bbf 100644 --- a/Applet/src/com/android/javacard/keymaster/KMAttestationKey.java +++ b/Applet/src/com/android/javacard/keymaster/KMAttestationKey.java @@ -16,10 +16,9 @@ package com.android.javacard.keymaster; /** - * KMAttestationKey is a marker interface and the SE Provider has to implement - * 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. + * KMAttestationKey is a marker interface and the SE Provider has to implement 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/KMBoolTag.java b/Applet/src/com/android/javacard/keymaster/KMBoolTag.java index 4396470b..173e6269 100644 --- a/Applet/src/com/android/javacard/keymaster/KMBoolTag.java +++ b/Applet/src/com/android/javacard/keymaster/KMBoolTag.java @@ -21,43 +21,48 @@ import javacard.framework.Util; /** - * KMBoolTag represents BOOL TAG type from the android keymaster hal specifications. If it is present in the key parameter list then its value is always true. A KMTag always requires - * a value because it is a key value pair. The bool tag always has 0x01 as its value. - * struct{byte TAG_TYPE; short length; struct{short BOOL_TAG; short tagKey; byte value 1}} + * KMBoolTag represents BOOL TAG type from the android keymaster hal specifications. If it is + * present in the key parameter list then its value is always true. A KMTag always requires a value + * because it is a key value pair. The bool tag always has 0x01 as its value. struct{byte TAG_TYPE; + * short length; struct{short BOOL_TAG; short tagKey; byte value 1}} */ public class KMBoolTag extends KMTag { + private static KMBoolTag prototype; private static short instPtr; // The allowed tag keys of type bool tag. private static final short[] tags = { - CALLER_NONCE, - INCLUDE_UNIQUE_ID, - BOOTLOADER_ONLY, - ROLLBACK_RESISTANCE, - NO_AUTH_REQUIRED, - ALLOW_WHILE_ON_BODY, - TRUSTED_USER_PRESENCE_REQUIRED, - TRUSTED_CONFIRMATION_REQUIRED, - UNLOCKED_DEVICE_REQUIRED, - RESET_SINCE_ID_ROTATION, - EARLY_BOOT_ONLY, - DEVICE_UNIQUE_ATTESTATION + CALLER_NONCE, + INCLUDE_UNIQUE_ID, + BOOTLOADER_ONLY, + ROLLBACK_RESISTANCE, + NO_AUTH_REQUIRED, + ALLOW_WHILE_ON_BODY, + TRUSTED_USER_PRESENCE_REQUIRED, + TRUSTED_CONFIRMATION_REQUIRED, + UNLOCKED_DEVICE_REQUIRED, + RESET_SINCE_ID_ROTATION, + EARLY_BOOT_ONLY, + DEVICE_UNIQUE_ATTESTATION }; - private KMBoolTag() {} + private KMBoolTag() { + } private static KMBoolTag proto(short ptr) { - if (prototype == null) prototype = new KMBoolTag(); + if (prototype == null) { + prototype = new KMBoolTag(); + } instPtr = ptr; return prototype; } // pointer to an empty instance used as expression public static short exp() { - short ptr = instance(TAG_TYPE, (short)2); - Util.setShort(heap, (short)(ptr+TLV_HEADER_SIZE), BOOL_TAG); + short ptr = instance(TAG_TYPE, (short) 2); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE), BOOL_TAG); return ptr; } @@ -65,16 +70,18 @@ public static short instance(short key) { if (!validateKey(key)) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } - short ptr = KMType.instance(TAG_TYPE, (short)5); - Util.setShort(heap, (short)(ptr+TLV_HEADER_SIZE), BOOL_TAG); - Util.setShort(heap, (short)(ptr+TLV_HEADER_SIZE+2), key); + short ptr = KMType.instance(TAG_TYPE, (short) 5); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE), BOOL_TAG); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE + 2), key); // Value is always 1. - heap[(short)(ptr+TLV_HEADER_SIZE+4)] = 0x01; + heap[(short) (ptr + TLV_HEADER_SIZE + 4)] = 0x01; return ptr; } public static KMBoolTag cast(short ptr) { - if (heap[ptr] != TAG_TYPE) ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + if (heap[ptr] != TAG_TYPE) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } if (Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE)) != BOOL_TAG) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -82,7 +89,7 @@ public static KMBoolTag cast(short ptr) { } public short getKey() { - return Util.getShort(heap, (short)(instPtr+TLV_HEADER_SIZE+2)); + return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE + 2)); } public short getTagType() { @@ -90,7 +97,7 @@ public short getTagType() { } public byte getVal() { - return heap[(short)(instPtr+TLV_HEADER_SIZE+4)]; + return heap[(short) (instPtr + TLV_HEADER_SIZE + 4)]; } // validate the tag key. @@ -104,7 +111,7 @@ private static boolean validateKey(short key) { return false; } - public static short[] getTags(){ + public static short[] getTags() { return tags; } } diff --git a/Applet/src/com/android/javacard/keymaster/KMByteBlob.java b/Applet/src/com/android/javacard/keymaster/KMByteBlob.java index 28b916db..001bab01 100644 --- a/Applet/src/com/android/javacard/keymaster/KMByteBlob.java +++ b/Applet/src/com/android/javacard/keymaster/KMByteBlob.java @@ -22,17 +22,21 @@ /** * KMByteBlob represents contiguous block of bytes. It corresponds to CBOR type of Byte String. It - * extends KMType by specifying value field as zero or more sequence of bytes. - * struct{byte BYTE_BLOB_TYPE; short length; sequence of bytes} + * extends KMType by specifying value field as zero or more sequence of bytes. struct{byte + * BYTE_BLOB_TYPE; short length; sequence of bytes} */ public class KMByteBlob extends KMType { + private static KMByteBlob prototype; private static short instPtr; - private KMByteBlob() {} + private KMByteBlob() { + } private static KMByteBlob proto(short ptr) { - if (prototype == null) prototype = new KMByteBlob(); + if (prototype == null) { + prototype = new KMByteBlob(); + } instPtr = ptr; return prototype; } @@ -56,7 +60,9 @@ public static short instance(byte[] buf, short startOff, short length) { // cast the ptr to KMByteBlob public static KMByteBlob cast(short ptr) { - if (heap[ptr] != BYTE_BLOB_TYPE) ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + if (heap[ptr] != BYTE_BLOB_TYPE) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } if (Util.getShort(heap, (short) (ptr + 1)) == INVALID_VALUE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -66,14 +72,18 @@ public static KMByteBlob cast(short ptr) { // Add the byte public void add(short index, byte val) { short len = length(); - if (index >= len) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + if (index >= len) { + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + } heap[(short) (instPtr + TLV_HEADER_SIZE + index)] = val; } // Get the byte public byte get(short index) { short len = length(); - if (index >= len) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + if (index >= len) { + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + } return heap[(short) (instPtr + TLV_HEADER_SIZE + index)]; } diff --git a/Applet/src/com/android/javacard/keymaster/KMByteTag.java b/Applet/src/com/android/javacard/keymaster/KMByteTag.java index 7310bb8a..4384891d 100644 --- a/Applet/src/com/android/javacard/keymaster/KMByteTag.java +++ b/Applet/src/com/android/javacard/keymaster/KMByteTag.java @@ -21,42 +21,46 @@ import javacard.framework.Util; /** - * KMByteTag represents BYTES Tag Type from android keymaster hal specifications. The tag value of this tag - * is the KMByteBlob pointer i.e. offset of KMByteBlob in memory heap. - * struct{byte TAG_TYPE; short length; struct{short BYTES_TAG; short tagKey; short blobPtr}} + * KMByteTag represents BYTES Tag Type from android keymaster hal specifications. The tag value of + * this tag is the KMByteBlob pointer i.e. offset of KMByteBlob in memory heap. struct{byte + * TAG_TYPE; short length; struct{short BYTES_TAG; short tagKey; short blobPtr}} */ public class KMByteTag extends KMTag { + private static KMByteTag prototype; private static short instPtr; // The allowed tag keys of type bool tag private static final short[] tags = { - APPLICATION_ID, - APPLICATION_DATA, - ROOT_OF_TRUST, - UNIQUE_ID, - ATTESTATION_CHALLENGE, - ATTESTATION_APPLICATION_ID, - ATTESTATION_ID_BRAND, - ATTESTATION_ID_DEVICE, - ATTESTATION_ID_PRODUCT, - ATTESTATION_ID_SERIAL, - ATTESTATION_ID_IMEI, - ATTESTATION_ID_MEID, - ATTESTATION_ID_MANUFACTURER, - ATTESTATION_ID_MODEL, - ASSOCIATED_DATA, - NONCE, - CONFIRMATION_TOKEN, - VERIFIED_BOOT_KEY, - VERIFIED_BOOT_HASH + APPLICATION_ID, + APPLICATION_DATA, + ROOT_OF_TRUST, + UNIQUE_ID, + ATTESTATION_CHALLENGE, + ATTESTATION_APPLICATION_ID, + ATTESTATION_ID_BRAND, + ATTESTATION_ID_DEVICE, + ATTESTATION_ID_PRODUCT, + ATTESTATION_ID_SERIAL, + ATTESTATION_ID_IMEI, + ATTESTATION_ID_MEID, + ATTESTATION_ID_MANUFACTURER, + ATTESTATION_ID_MODEL, + ASSOCIATED_DATA, + NONCE, + CONFIRMATION_TOKEN, + VERIFIED_BOOT_KEY, + VERIFIED_BOOT_HASH }; - private KMByteTag() {} + private KMByteTag() { + } private static KMByteTag proto(short ptr) { - if (prototype == null) prototype = new KMByteTag(); + if (prototype == null) { + prototype = new KMByteTag(); + } instPtr = ptr; return prototype; } @@ -64,10 +68,10 @@ private static KMByteTag proto(short ptr) { // pointer to an empty instance used as expression public static short exp() { short blobPtr = KMByteBlob.exp(); - short ptr = instance(TAG_TYPE, (short)6); - Util.setShort(heap, (short)(ptr+TLV_HEADER_SIZE), BYTES_TAG); - Util.setShort(heap, (short)(ptr+TLV_HEADER_SIZE+2), INVALID_TAG); - Util.setShort(heap, (short)(ptr+TLV_HEADER_SIZE+4), blobPtr); + short ptr = instance(TAG_TYPE, (short) 6); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE), BYTES_TAG); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE + 2), INVALID_TAG); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE + 4), blobPtr); return ptr; } @@ -82,18 +86,20 @@ public static short instance(short key, short byteBlob) { if (!validateKey(key)) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } - if(heap[byteBlob] != BYTE_BLOB_TYPE) { + if (heap[byteBlob] != BYTE_BLOB_TYPE) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } - short ptr = instance(TAG_TYPE, (short)6); - Util.setShort(heap, (short)(ptr+TLV_HEADER_SIZE), BYTES_TAG); - Util.setShort(heap, (short)(ptr+TLV_HEADER_SIZE+2), key); - Util.setShort(heap, (short)(ptr+TLV_HEADER_SIZE+4), byteBlob); + short ptr = instance(TAG_TYPE, (short) 6); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE), BYTES_TAG); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE + 2), key); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE + 4), byteBlob); return ptr; } public static KMByteTag cast(short ptr) { - if (heap[ptr] != TAG_TYPE) ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + if (heap[ptr] != TAG_TYPE) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } if (Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE)) != BYTES_TAG) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -101,7 +107,7 @@ public static KMByteTag cast(short ptr) { } public short getKey() { - return Util.getShort(heap, (short)(instPtr+TLV_HEADER_SIZE+2)); + return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE + 2)); } public short getTagType() { @@ -109,11 +115,11 @@ public short getTagType() { } public short getValue() { - return Util.getShort(heap, (short)(instPtr+TLV_HEADER_SIZE+4)); + return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE + 4)); } public short length() { - short blobPtr = Util.getShort(heap, (short)(instPtr+TLV_HEADER_SIZE+4)); + short blobPtr = Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE + 4)); return KMByteBlob.cast(blobPtr).length(); } diff --git a/Applet/src/com/android/javacard/keymaster/KMDecoder.java b/Applet/src/com/android/javacard/keymaster/KMDecoder.java index d74e35d0..520ffb7c 100644 --- a/Applet/src/com/android/javacard/keymaster/KMDecoder.java +++ b/Applet/src/com/android/javacard/keymaster/KMDecoder.java @@ -21,21 +21,22 @@ import javacard.framework.Util; public class KMDecoder { + // major types private static final short UINT_TYPE = 0x00; private static final short BYTES_TYPE = 0x40; private static final short ARRAY_TYPE = 0x80; - private static final short MAP_TYPE = 0xA0; + private static final short MAP_TYPE = 0xA0; // masks private static final short ADDITIONAL_MASK = 0x1F; private static final short MAJOR_TYPE_MASK = 0xE0; // value length - private static final short UINT8_LENGTH = 0x18; - private static final short UINT16_LENGTH = 0x19; + private static final short UINT8_LENGTH = 0x18; + private static final short UINT16_LENGTH = 0x19; private static final short UINT32_LENGTH = 0x1A; - private static final short UINT64_LENGTH = 0x1B; + private static final short UINT64_LENGTH = 0x1B; private byte[] buffer; private short startOff; @@ -52,16 +53,17 @@ public KMDecoder() { public short decode(short expression, byte[] buffer, short startOff, short length) { this.buffer = buffer; this.startOff = startOff; - this.length = (short)(startOff+length); + this.length = (short) (startOff + length); return decode(expression); } - public short decodeArray(short exp, byte[] buffer, short startOff, short length){ + + public short decodeArray(short exp, byte[] buffer, short startOff, short length) { this.buffer = buffer; this.startOff = startOff; - this.length = (short)(startOff+length); + this.length = (short) (startOff + length); short payloadLength = readMajorTypeWithPayloadLength(ARRAY_TYPE); short expLength = KMArray.cast(exp).length(); - if(payloadLength > expLength){ + if (payloadLength > expLength) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } short index = 0; @@ -76,9 +78,10 @@ public short decodeArray(short exp, byte[] buffer, short startOff, short length) } return arrPtr; } - private short decode(short exp){ + + private short decode(short exp) { byte type = KMType.getType(exp); - switch(type){ + switch (type) { case KMType.BYTE_BLOB_TYPE: return decodeByteBlob(exp); case KMType.INTEGER_TYPE: @@ -105,8 +108,9 @@ private short decode(short exp){ return 0; } } - private short decodeTag(short tagType, short exp){ - switch(tagType){ + + private short decodeTag(short tagType, short exp) { + switch (tagType) { case KMType.BYTES_TAG: return decodeBytesTag(exp); case KMType.BOOL_TAG: @@ -174,16 +178,15 @@ private short decodeKeyParam(short exp) { if (tagType == allowedType) { // then decodeByteBlob and add that to the array. obj = decode(tagClass); - KMArray.cast(vals).add(index,obj); + KMArray.cast(vals).add(index, obj); tagFound = true; break; } tagInd++; } - if(!tagFound){ + if (!tagFound) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); - } - else { + } else { index++; } } @@ -199,14 +202,14 @@ private short decodeIntegerArrayTag(short exp) { readTagKey(KMIntegerArrayTag.cast(exp).getTagType()); // the values are array of integers. return KMIntegerArrayTag.instance(KMIntegerArrayTag.cast(exp).getTagType(), - this.tagKey, decode(KMIntegerArrayTag.cast(exp).getValues())); + this.tagKey, decode(KMIntegerArrayTag.cast(exp).getValues())); } private short decodeIntegerTag(short exp) { readTagKey(KMIntegerTag.cast(exp).getTagType()); // the value is an integer return KMIntegerTag.instance(KMIntegerTag.cast(exp).getTagType(), - this.tagKey, decode(KMIntegerTag.cast(exp).getValue())); + this.tagKey, decode(KMIntegerTag.cast(exp).getValue())); } private short decodeBytesTag(short exp) { @@ -222,7 +225,7 @@ private short decodeArray(short exp) { short type; short obj; // check whether array contains one type of objects or multiple types - if( KMArray.cast(exp).containedType() == 0){// multiple types specified by expression. + if (KMArray.cast(exp).containedType() == 0) {// multiple types specified by expression. if (KMArray.cast(exp).length() != KMArray.ANY_ARRAY_LENGTH) { if (KMArray.cast(exp).length() != payloadLength) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); @@ -234,9 +237,9 @@ private short decodeArray(short exp) { KMArray.cast(arrPtr).add(index, obj); index++; } - }else{ // Array is a Vector containing objects of one type + } else { // Array is a Vector containing objects of one type type = KMArray.cast(exp).containedType(); - while(index < payloadLength){ + while (index < payloadLength) { obj = decode(type); KMArray.cast(arrPtr).add(index, obj); index++; @@ -257,7 +260,7 @@ private short decodeEnumTag(short exp) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } if (len < UINT8_LENGTH) { - enumVal = (byte)(len & ADDITIONAL_MASK); + enumVal = (byte) (len & ADDITIONAL_MASK); incrementStartOff((short) 1); } else if (len == UINT8_LENGTH) { incrementStartOff((short) 1); @@ -291,7 +294,7 @@ private short decodeEnum(short exp) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } if (len < UINT8_LENGTH) { - enumVal = (byte)(len & ADDITIONAL_MASK); + enumVal = (byte) (len & ADDITIONAL_MASK); incrementStartOff((short) 1); } else { incrementStartOff((short) 1); @@ -307,12 +310,12 @@ private short decodeInteger(short exp) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } short len = (short) (buffer[startOff] & ADDITIONAL_MASK); - if(len > UINT64_LENGTH){ + if (len > UINT64_LENGTH) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } incrementStartOff((short) 1); if (len < UINT8_LENGTH) { - inst = KMInteger.uint_8((byte)(len & ADDITIONAL_MASK)); + inst = KMInteger.uint_8((byte) (len & ADDITIONAL_MASK)); } else if (len == UINT8_LENGTH) { inst = KMInteger.instance(buffer, startOff, (short) 1); incrementStartOff((short) 1); @@ -377,8 +380,8 @@ private short readMajorTypeWithPayloadLength(short majorType) { } if (lenType < UINT8_LENGTH) { payloadLength = lenType; - }else if (lenType == UINT8_LENGTH) { - payloadLength = (short)(readByte() & 0xFF); + } else if (lenType == UINT8_LENGTH) { + payloadLength = (short) (readByte() & 0xFF); } else { payloadLength = readShort(); } @@ -405,12 +408,12 @@ private void incrementStartOff(short inc) { } public short readCertificateChainLengthAndHeaderLen(byte[] buf, short bufOffset, - short bufLen) { + short bufLen) { this.buffer = buf; this.startOff = bufOffset; this.length = (short) (bufOffset + bufLen); short totalLen = readMajorTypeWithPayloadLength(BYTES_TYPE); - totalLen += (short)( startOff - bufOffset); + totalLen += (short) (startOff - bufOffset); return totalLen; } } diff --git a/Applet/src/com/android/javacard/keymaster/KMEncoder.java b/Applet/src/com/android/javacard/keymaster/KMEncoder.java index 685ba468..61163c00 100644 --- a/Applet/src/com/android/javacard/keymaster/KMEncoder.java +++ b/Applet/src/com/android/javacard/keymaster/KMEncoder.java @@ -22,6 +22,7 @@ import javacard.framework.Util; public class KMEncoder { + // major types private static final byte UINT_TYPE = 0x00; private static final byte BYTES_TYPE = 0x40; @@ -37,8 +38,7 @@ public class KMEncoder { private static final byte UINT32_LENGTH = (byte) 0x1A; private static final byte UINT64_LENGTH = (byte) 0x1B; private static final short TINY_PAYLOAD = 0x17; - private static final short SHORT_PAYLOAD = 0x100; - //TODO make this static. + private static final short SHORT_PAYLOAD = 0x100; private byte[] buffer; private short startOff; private short length; @@ -49,41 +49,44 @@ public KMEncoder() { buffer = null; startOff = 0; length = 0; - stack = JCSystem.makeTransientShortArray((short)50, JCSystem.CLEAR_ON_RESET); + stack = JCSystem.makeTransientShortArray((short) 50, JCSystem.CLEAR_ON_RESET); } - private static void push (short objPtr){ + private static void push(short objPtr) { stack[stackPtr] = objPtr; stackPtr++; } - private static short pop(){ + + private static short pop() { stackPtr--; return stack[stackPtr]; } - private void encode(short obj){ + + private void encode(short obj) { push(obj); } + public short encode(short object, byte[] buffer, short startOff) { stackPtr = 0; this.buffer = buffer; this.startOff = startOff; short len = (short) buffer.length; - if((len <0) || (len > KMKeymasterApplet.MAX_LENGTH)){ + if ((len < 0) || (len > KMKeymasterApplet.MAX_LENGTH)) { this.length = KMKeymasterApplet.MAX_LENGTH; - }else{ - this.length = (short)buffer.length; + } else { + this.length = (short) buffer.length; } //this.length = (short)(startOff + length); push(object); encode(); - return (short)(this.startOff - 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 = (short)(offset+3); + this.length = (short) (offset + 3); writeMajorTypeWithLength(ARRAY_TYPE, (short) 2); // Array of 2 elements writeByte(UINT_TYPE); // Error.OK @@ -93,7 +96,7 @@ public void encodeCertChain(byte[] buffer, short offset, short length) { public short encodeCert(byte[] certBuffer, short bufferStart, short certStart, short certLength) { this.buffer = certBuffer; this.startOff = certStart; - this.length = (short)(certStart+1); + this.length = (short) (certStart + 1); //Array header - 2 elements i.e. 1 byte this.startOff--; // Error.Ok - 1 byte @@ -102,14 +105,16 @@ public short encodeCert(byte[] certBuffer, short bufferStart, short certStart, s this.startOff--; // Cert Byte blob - typically 2 bytes length i.e. 3 bytes header this.startOff -= 2; - if(certLength >= SHORT_PAYLOAD) { - this.startOff--; + if (certLength >= SHORT_PAYLOAD) { + this.startOff--; } bufferStart = startOff; - if(this.startOff < bufferStart) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); - writeMajorTypeWithLength(ARRAY_TYPE,(short)2); // Array of 2 elements + if (this.startOff < bufferStart) { + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + } + writeMajorTypeWithLength(ARRAY_TYPE, (short) 2); // Array of 2 elements writeByte(UINT_TYPE); // Error.OK - writeMajorTypeWithLength(ARRAY_TYPE,(short)1); // Array of 1 element + writeMajorTypeWithLength(ARRAY_TYPE, (short) 1); // Array of 1 element writeMajorTypeWithLength(BYTES_TYPE, certLength); // Cert Byte Blob of length return bufferStart; } @@ -117,21 +122,21 @@ public short encodeCert(byte[] certBuffer, short bufferStart, short certStart, s public short encodeError(short err, byte[] buffer, short startOff, short length) { this.buffer = buffer; this.startOff = startOff; - this.length = (short)(startOff + length); + this.length = (short) (startOff + length); // encode the err as UINT with value in err - should not be greater then 5 bytes. - if(err < UINT8_LENGTH){ - writeByte((byte)(UINT_TYPE | err )); - }else if(err < 0x100){ - writeByte((byte)(UINT_TYPE | UINT8_LENGTH)); - writeByte((byte)err); - }else { - writeByte((byte)(UINT_TYPE | UINT16_LENGTH)); + if (err < UINT8_LENGTH) { + writeByte((byte) (UINT_TYPE | err)); + } else if (err < 0x100) { + writeByte((byte) (UINT_TYPE | UINT8_LENGTH)); + writeByte((byte) err); + } else { + writeByte((byte) (UINT_TYPE | UINT16_LENGTH)); writeShort(err); } - return (short)(this.startOff - startOff); + return (short) (this.startOff - startOff); } - private void encode(){ + private void encode() { while (stackPtr > 0) { short exp = pop(); byte type = KMType.getType(exp); @@ -172,8 +177,9 @@ private void encode(){ } } } - private void encodeTag(short tagType, short exp){ - switch(tagType){ + + private void encodeTag(short tagType, short exp) { + switch (tagType) { case KMType.BYTES_TAG: encodeBytesTag(exp); return; @@ -203,6 +209,7 @@ private void encodeTag(short tagType, short exp){ private void encodeKeyParam(short obj) { encodeAsMap(KMKeyParameters.cast(obj).getVals()); } + private void encodeKeyChar(short obj) { encode(KMKeyCharacteristics.cast(obj).getVals()); } @@ -222,19 +229,19 @@ private void encodeHmacSharingParam(short obj) { private void encodeArray(short obj) { writeMajorTypeWithLength(ARRAY_TYPE, KMArray.cast(obj).length()); short len = KMArray.cast(obj).length(); - short index = (short)(len-1); - while(index >= 0){ + short index = (short) (len - 1); + while (index >= 0) { encode(KMArray.cast(obj).get(index)); index--; } } - private void encodeAsMap(short obj){ + private void encodeAsMap(short obj) { writeMajorTypeWithLength(MAP_TYPE, KMArray.cast(obj).length()); short len = KMArray.cast(obj).length(); - short index = (short)(len-1); + short index = (short) (len - 1); short inst; - while(index >= 0){ + while (index >= 0) { inst = KMArray.cast(obj).get(index); encode(inst); index--; @@ -252,8 +259,8 @@ private void encodeEnumArrayTag(short obj) { } private void encodeIntegerTag(short obj) { - writeTag(KMIntegerTag .cast(obj).getTagType(), KMIntegerTag .cast(obj).getKey()); - encode(KMIntegerTag .cast(obj).getValue()); + writeTag(KMIntegerTag.cast(obj).getTagType(), KMIntegerTag.cast(obj).getKey()); + encode(KMIntegerTag.cast(obj).getValue()); } private void encodeBytesTag(short obj) { @@ -270,6 +277,7 @@ private void encodeEnumTag(short obj) { writeTag(KMEnumTag.cast(obj).getTagType(), KMEnumTag.cast(obj).getKey()); writeByteValue(KMEnumTag.cast(obj).getValue()); } + private void encodeEnum(short obj) { writeByteValue(KMEnum.cast(obj).getVal()); } @@ -278,86 +286,89 @@ private void encodeInteger(short obj) { byte[] val = KMInteger.cast(obj).getBuffer(); short len = KMInteger.cast(obj).length(); short startOff = KMInteger.cast(obj).getStartOff(); - byte index =0; + byte index = 0; // find out the most significant byte - while(index < len){ - if(val[(short)(startOff + index)] > 0){ + while (index < len) { + if (val[(short) (startOff + index)] > 0) { break; - }else if(val[(short)(startOff + index)] < 0){ + } else if (val[(short) (startOff + index)] < 0) { break; } index++; // index will be equal to len if value is 0. } // find the difference between most significant byte and len - short diff = (short)(len - index); - if(diff == 0){ - writeByte((byte)(UINT_TYPE | 0)); - }else if((diff == 1) && (val[(short)(startOff + index)] < UINT8_LENGTH) - &&(val[(short)(startOff + index)] >= 0)){ - writeByte((byte)(UINT_TYPE | val[(short)(startOff + index)])); - }else if (diff == 1){ - writeByte((byte)(UINT_TYPE | UINT8_LENGTH)); - writeByte(val[(short)(startOff + index)]); - }else if(diff == 2){ - writeByte((byte)(UINT_TYPE | UINT16_LENGTH)); - writeBytes(val, (short)(startOff + index), (short)2); - }else if(diff <= 4){ - writeByte((byte)(UINT_TYPE | UINT32_LENGTH)); - writeBytes(val, (short)(startOff + len - 4), (short)4); - }else { - writeByte((byte)(UINT_TYPE | UINT64_LENGTH)); - writeBytes(val, startOff, (short)8); + short diff = (short) (len - index); + if (diff == 0) { + writeByte((byte) (UINT_TYPE | 0)); + } else if ((diff == 1) && (val[(short) (startOff + index)] < UINT8_LENGTH) + && (val[(short) (startOff + index)] >= 0)) { + writeByte((byte) (UINT_TYPE | val[(short) (startOff + index)])); + } else if (diff == 1) { + writeByte((byte) (UINT_TYPE | UINT8_LENGTH)); + writeByte(val[(short) (startOff + index)]); + } else if (diff == 2) { + writeByte((byte) (UINT_TYPE | UINT16_LENGTH)); + writeBytes(val, (short) (startOff + index), (short) 2); + } else if (diff <= 4) { + writeByte((byte) (UINT_TYPE | UINT32_LENGTH)); + writeBytes(val, (short) (startOff + len - 4), (short) 4); + } else { + writeByte((byte) (UINT_TYPE | UINT64_LENGTH)); + writeBytes(val, startOff, (short) 8); } } private void encodeByteBlob(short obj) { writeMajorTypeWithLength(BYTES_TYPE, KMByteBlob.cast(obj).length()); writeBytes(KMByteBlob.cast(obj).getBuffer(), KMByteBlob.cast(obj).getStartOff(), - KMByteBlob.cast(obj).length()); + KMByteBlob.cast(obj).length()); } - private void writeByteValue(byte val){ - if((val < UINT8_LENGTH) && (val >=0)){ - writeByte((byte)(UINT_TYPE | val)); - }else{ - writeByte((byte)(UINT_TYPE | UINT8_LENGTH)); - writeByte((byte)val); + private void writeByteValue(byte val) { + if ((val < UINT8_LENGTH) && (val >= 0)) { + writeByte((byte) (UINT_TYPE | val)); + } else { + writeByte((byte) (UINT_TYPE | UINT8_LENGTH)); + writeByte((byte) val); } } - private void writeTag(short tagType, short tagKey){ - writeByte((byte)(UINT_TYPE | UINT32_LENGTH)); + private void writeTag(short tagType, short tagKey) { + writeByte((byte) (UINT_TYPE | UINT32_LENGTH)); writeShort(tagType); writeShort(tagKey); } + private void writeMajorTypeWithLength(byte majorType, short len) { - if(len <= TINY_PAYLOAD){ - writeByte((byte)(majorType | (byte) (len & ADDITIONAL_MASK))); - }else if(len < SHORT_PAYLOAD){ - writeByte((byte)(majorType | UINT8_LENGTH )); - writeByte((byte)(len & 0xFF)); - }else { - writeByte((byte)(majorType | UINT16_LENGTH )); + if (len <= TINY_PAYLOAD) { + writeByte((byte) (majorType | (byte) (len & ADDITIONAL_MASK))); + } else if (len < SHORT_PAYLOAD) { + writeByte((byte) (majorType | UINT8_LENGTH)); + writeByte((byte) (len & 0xFF)); + } else { + writeByte((byte) (majorType | UINT16_LENGTH)); writeShort(len); } } - private void writeBytes(byte[] buf, short start, short len){ + private void writeBytes(byte[] buf, short start, short len) { Util.arrayCopyNonAtomic(buf, start, buffer, startOff, len); incrementStartOff(len); } - private void writeShort(short val){ - buffer[startOff] = (byte)((val >> 8) & 0xFF); - incrementStartOff((short)1); - buffer[startOff] = (byte)((val & 0xFF)); - incrementStartOff((short)1); + + private void writeShort(short val) { + buffer[startOff] = (byte) ((val >> 8) & 0xFF); + incrementStartOff((short) 1); + buffer[startOff] = (byte) ((val & 0xFF)); + incrementStartOff((short) 1); } - private void writeByte(byte val){ + + private void writeByte(byte val) { buffer[startOff] = val; - incrementStartOff((short)1); + incrementStartOff((short) 1); } - private void incrementStartOff(short inc){ + private void incrementStartOff(short inc) { startOff += inc; if (startOff >= this.length) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); diff --git a/Applet/src/com/android/javacard/keymaster/KMEnum.java b/Applet/src/com/android/javacard/keymaster/KMEnum.java index d25c5f8e..6dbdf7ce 100644 --- a/Applet/src/com/android/javacard/keymaster/KMEnum.java +++ b/Applet/src/com/android/javacard/keymaster/KMEnum.java @@ -26,27 +26,31 @@ * struct{short enumType; byte val}} */ public class KMEnum extends KMType { + private static KMEnum prototype; private static short instPtr; // The allowed enum types. private static short[] types = { - HARDWARE_TYPE, - KEY_FORMAT, - KEY_DERIVATION_FUNCTION, - VERIFIED_BOOT_STATE, - DEVICE_LOCKED, - USER_AUTH_TYPE, - PURPOSE, - ECCURVE + HARDWARE_TYPE, + KEY_FORMAT, + KEY_DERIVATION_FUNCTION, + VERIFIED_BOOT_STATE, + DEVICE_LOCKED, + USER_AUTH_TYPE, + PURPOSE, + ECCURVE }; private static Object[] enums = null; - private KMEnum() {} + private KMEnum() { + } private static KMEnum proto(short ptr) { - if (prototype == null) prototype = new KMEnum(); + if (prototype == null) { + prototype = new KMEnum(); + } instPtr = ptr; return prototype; } @@ -61,7 +65,9 @@ public short length() { } public static KMEnum cast(short ptr) { - if (heap[ptr] != ENUM_TYPE) ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + if (heap[ptr] != ENUM_TYPE) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } if (Util.getShort(heap, (short) (ptr + 1)) == INVALID_VALUE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -91,22 +97,22 @@ private static void create() { // The allowed enum values to corresponding enum types in the types array. if (enums == null) { enums = - new Object[] { - new byte[] {SOFTWARE, TRUSTED_ENVIRONMENT, STRONGBOX}, - new byte[] {X509, PKCS8, RAW}, - new byte[] { - DERIVATION_NONE, - RFC5869_SHA256, - ISO18033_2_KDF1_SHA1, - ISO18033_2_KDF1_SHA256, - ISO18033_2_KDF2_SHA1, - ISO18033_2_KDF2_SHA256 - }, - new byte[] {SELF_SIGNED_BOOT, VERIFIED_BOOT, UNVERIFIED_BOOT, FAILED_BOOT}, - new byte[] {DEVICE_LOCKED_TRUE, DEVICE_LOCKED_FALSE}, - new byte[] {USER_AUTH_NONE, PASSWORD, FINGERPRINT, BOTH}, - new byte[] {ENCRYPT, DECRYPT, SIGN, VERIFY, WRAP_KEY, ATTEST_KEY}, - new byte[] {P_224, P_256, P_384, P_521} + new Object[]{ + new byte[]{SOFTWARE, TRUSTED_ENVIRONMENT, STRONGBOX}, + new byte[]{X509, PKCS8, RAW}, + new byte[]{ + DERIVATION_NONE, + RFC5869_SHA256, + ISO18033_2_KDF1_SHA1, + ISO18033_2_KDF1_SHA256, + ISO18033_2_KDF2_SHA1, + ISO18033_2_KDF2_SHA256 + }, + new byte[]{SELF_SIGNED_BOOT, VERIFIED_BOOT, UNVERIFIED_BOOT, FAILED_BOOT}, + new byte[]{DEVICE_LOCKED_TRUE, DEVICE_LOCKED_FALSE}, + new byte[]{USER_AUTH_NONE, PASSWORD, FINGERPRINT, BOTH}, + new byte[]{ENCRYPT, DECRYPT, SIGN, VERIFY, WRAP_KEY, ATTEST_KEY}, + new byte[]{P_224, P_256, P_384, P_521} }; } } diff --git a/Applet/src/com/android/javacard/keymaster/KMEnumArrayTag.java b/Applet/src/com/android/javacard/keymaster/KMEnumArrayTag.java index 37e23286..1cc5730d 100644 --- a/Applet/src/com/android/javacard/keymaster/KMEnumArrayTag.java +++ b/Applet/src/com/android/javacard/keymaster/KMEnumArrayTag.java @@ -35,10 +35,13 @@ public class KMEnumArrayTag extends KMTag { // Tag Values. private static Object[] enums = null; - private KMEnumArrayTag() {} + private KMEnumArrayTag() { + } private static KMEnumArrayTag proto(short ptr) { - if (prototype == null) prototype = new KMEnumArrayTag(); + if (prototype == null) { + prototype = new KMEnumArrayTag(); + } instPtr = ptr; return prototype; } @@ -94,7 +97,9 @@ public static short instance(short key, short byteBlob) { } public static KMEnumArrayTag cast(short ptr) { - if (heap[ptr] != TAG_TYPE) ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + if (heap[ptr] != TAG_TYPE) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } if (Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE)) != ENUM_ARRAY_TAG) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -122,13 +127,13 @@ public static void create() { if (enums == null) { // allowed tag values. enums = - new Object[] { - new byte[] {ENCRYPT, DECRYPT, SIGN, VERIFY, WRAP_KEY, ATTEST_KEY}, - new byte[] {ECB, CBC, CTR, GCM}, - new byte[] {DIGEST_NONE, MD5, SHA1, SHA2_224, SHA2_256, SHA2_384, SHA2_512}, - new byte[] { - PADDING_NONE, RSA_OAEP, RSA_PSS, RSA_PKCS1_1_5_ENCRYPT, RSA_PKCS1_1_5_SIGN, PKCS7 - } + new Object[]{ + new byte[]{ENCRYPT, DECRYPT, SIGN, VERIFY, WRAP_KEY, ATTEST_KEY}, + new byte[]{ECB, CBC, CTR, GCM}, + new byte[]{DIGEST_NONE, MD5, SHA1, SHA2_224, SHA2_256, SHA2_384, SHA2_512}, + new byte[]{ + PADDING_NONE, RSA_OAEP, RSA_PSS, RSA_PKCS1_1_5_ENCRYPT, RSA_PKCS1_1_5_SIGN, PKCS7 + } }; } } @@ -198,15 +203,20 @@ public boolean isValidDigests(byte alg) { switch (alg) { case KMType.EC: case KMType.RSA: - if (digest != KMType.DIGEST_NONE && digest != KMType.SHA2_256 && digest != KMType.SHA1) + if (digest != KMType.DIGEST_NONE && digest != KMType.SHA2_256 && digest != KMType.SHA1) { return false; + } break; case KMType.HMAC: - if (digest != KMType.SHA2_256) return false; + if (digest != KMType.SHA2_256) { + return false; + } break; case KMType.AES: case KMType.DES: - if (digest != KMType.DIGEST_NONE) return false; + if (digest != KMType.DIGEST_NONE) { + return false; + } break; default: return false; @@ -270,7 +280,9 @@ public boolean isValidPurpose(byte alg) { } break; case KMType.WRAP_KEY: - if (alg != KMType.RSA) return false; + if (alg != KMType.RSA) { + return false; + } break; default: return false; diff --git a/Applet/src/com/android/javacard/keymaster/KMEnumTag.java b/Applet/src/com/android/javacard/keymaster/KMEnumTag.java index 2c87bb96..485572ed 100644 --- a/Applet/src/com/android/javacard/keymaster/KMEnumTag.java +++ b/Applet/src/com/android/javacard/keymaster/KMEnumTag.java @@ -19,61 +19,68 @@ import javacard.framework.ISO7816; import javacard.framework.ISOException; import javacard.framework.Util; + /** - * KMEnumTag represents ENUM Tag type specified in android keymaster hal specifications. - * struct{byte TAG_TYPE; short length; struct{short ENUM_TAG; short tagKey; byte value}} + * KMEnumTag represents ENUM Tag type specified in android keymaster hal specifications. struct{byte + * TAG_TYPE; short length; struct{short ENUM_TAG; short tagKey; byte value}} */ public class KMEnumTag extends KMTag { + private static KMEnumTag prototype; private static short instPtr; // The allowed tag keys of type enum tag. private static short[] tags = { - ALGORITHM, ECCURVE, BLOB_USAGE_REQ, USER_AUTH_TYPE, ORIGIN, HARDWARE_TYPE + ALGORITHM, ECCURVE, BLOB_USAGE_REQ, USER_AUTH_TYPE, ORIGIN, HARDWARE_TYPE }; private static Object[] enums = null; - private KMEnumTag() {} + private KMEnumTag() { + } private static KMEnumTag proto(short ptr) { - if (prototype == null) prototype = new KMEnumTag(); + if (prototype == null) { + prototype = new KMEnumTag(); + } instPtr = ptr; return prototype; } // pointer to an empty instance used as expression public static short exp() { - short ptr = instance(TAG_TYPE, (short)2); - Util.setShort(heap, (short)(ptr+TLV_HEADER_SIZE), ENUM_TAG); + short ptr = instance(TAG_TYPE, (short) 2); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE), ENUM_TAG); return ptr; } public static short instance(short key) { - if(!validateEnum(key, NO_VALUE)){ + if (!validateEnum(key, NO_VALUE)) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } - short ptr = KMType.instance(TAG_TYPE, (short)4); - Util.setShort(heap, (short)(ptr+TLV_HEADER_SIZE), ENUM_TAG); - Util.setShort(heap, (short)(ptr+TLV_HEADER_SIZE+2), key); + short ptr = KMType.instance(TAG_TYPE, (short) 4); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE), ENUM_TAG); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE + 2), key); return ptr; } public static short instance(short key, byte val) { - if(!validateEnum(key, val)){ + if (!validateEnum(key, val)) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } - short ptr = instance(TAG_TYPE, (short)5); - Util.setShort(heap, (short)(ptr+TLV_HEADER_SIZE), ENUM_TAG); - Util.setShort(heap, (short)(ptr+TLV_HEADER_SIZE+2), key); - heap[(short)(ptr+TLV_HEADER_SIZE+4)]= val; + short ptr = instance(TAG_TYPE, (short) 5); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE), ENUM_TAG); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE + 2), key); + heap[(short) (ptr + TLV_HEADER_SIZE + 4)] = val; return ptr; } public static KMEnumTag cast(short ptr) { - if (heap[ptr] != TAG_TYPE) ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + if (heap[ptr] != TAG_TYPE) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } if (Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE)) != ENUM_TAG) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -81,7 +88,7 @@ public static KMEnumTag cast(short ptr) { } public short getKey() { - return Util.getShort(heap, (short)(instPtr+TLV_HEADER_SIZE+2)); + return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE + 2)); } public short getTagType() { @@ -89,20 +96,21 @@ public short getTagType() { } public byte getValue() { - return heap[(short)(instPtr+TLV_HEADER_SIZE+4)]; + return heap[(short) (instPtr + TLV_HEADER_SIZE + 4)]; } public static void create() { if (enums == null) { // enum tag values. enums = - new Object[] { - new byte[] {RSA, DES, EC, AES, HMAC}, - new byte[] {P_224, P_256, P_384, P_521}, - new byte[] {STANDALONE, REQUIRES_FILE_SYSTEM}, - new byte[] {USER_AUTH_NONE, PASSWORD, FINGERPRINT, (byte)(PASSWORD & FINGERPRINT),ANY}, - new byte[] {GENERATED, DERIVED, IMPORTED, UNKNOWN, SECURELY_IMPORTED}, - new byte[] {SOFTWARE, TRUSTED_ENVIRONMENT, STRONGBOX} + new Object[]{ + new byte[]{RSA, DES, EC, AES, HMAC}, + new byte[]{P_224, P_256, P_384, P_521}, + new byte[]{STANDALONE, REQUIRES_FILE_SYSTEM}, + new byte[]{USER_AUTH_NONE, PASSWORD, FINGERPRINT, (byte) (PASSWORD & FINGERPRINT), + ANY}, + new byte[]{GENERATED, DERIVED, IMPORTED, UNKNOWN, SECURELY_IMPORTED}, + new byte[]{SOFTWARE, TRUSTED_ENVIRONMENT, STRONGBOX} }; } } @@ -138,10 +146,10 @@ private static boolean validateEnum(short key, byte value) { return false; } - public static short getValue(short tagType, short keyParameters){ + public static short getValue(short tagType, short keyParameters) { short tagPtr = KMKeyParameters.findTag(KMType.ENUM_TAG, tagType, keyParameters); - if(tagPtr != KMType.INVALID_VALUE){ - return heap[(short)(tagPtr+TLV_HEADER_SIZE+4)]; + if (tagPtr != KMType.INVALID_VALUE) { + return heap[(short) (tagPtr + TLV_HEADER_SIZE + 4)]; } return KMType.INVALID_VALUE; } diff --git a/Applet/src/com/android/javacard/keymaster/KMError.java b/Applet/src/com/android/javacard/keymaster/KMError.java index 83eb8c7c..bac8cf20 100644 --- a/Applet/src/com/android/javacard/keymaster/KMError.java +++ b/Applet/src/com/android/javacard/keymaster/KMError.java @@ -20,8 +20,8 @@ * positive unlike negative values in keymaster hal. */ public class KMError { + 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; @@ -34,69 +34,43 @@ public class KMError { 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 final short UNSUPPORTED_KEY_VERIFICATION_ALGORITHM = 20; - /** For PKCS8 & PKCS12 */ + + /** + * For PKCS8 & PKCS12 + */ public static final short INVALID_INPUT_LENGTH = 21; - 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 @@ -115,5 +89,5 @@ public class KMError { public static final short CRYPTO_UNINITIALIZED_KEY = 10012; //Generic Unknown error. public static final short GENERIC_UNKNOWN_ERROR = 10013; - + } diff --git a/Applet/src/com/android/javacard/keymaster/KMException.java b/Applet/src/com/android/javacard/keymaster/KMException.java index 08bbd6ed..0f4f6740 100644 --- a/Applet/src/com/android/javacard/keymaster/KMException.java +++ b/Applet/src/com/android/javacard/keymaster/KMException.java @@ -21,20 +21,26 @@ * throw EMError errors. */ public class KMException extends RuntimeException { + public static short reason; public static KMException exception; - private KMException(){ + + private KMException() { } - public static void throwIt(short reason){ + + public static void throwIt(short reason) { KMException.reason = reason; throw instance(); } - public static KMException instance(){ - if(exception == null ) exception = new KMException(); + + public static KMException instance() { + if (exception == null) { + exception = new KMException(); + } return exception; } - public void clear(){ + public void clear() { reason = KMError.UNKNOWN_ERROR; } } diff --git a/Applet/src/com/android/javacard/keymaster/KMHardwareAuthToken.java b/Applet/src/com/android/javacard/keymaster/KMHardwareAuthToken.java index 6136563b..71e2e8bb 100644 --- a/Applet/src/com/android/javacard/keymaster/KMHardwareAuthToken.java +++ b/Applet/src/com/android/javacard/keymaster/KMHardwareAuthToken.java @@ -21,14 +21,14 @@ import javacard.framework.Util; /** - * KMHardwareAuthToken represents HardwareAuthToken structure from android keymaster hal specifications. - * It corresponds to CBOR array type. - * struct{byte HW_AUTH_TOKEN_TYPE; short length=2; short arrayPtr} where arrayPtr is a pointer to - * ordered array with following elements: - * {KMInteger Challenge; KMInteger UserId; KMInteger AuthenticatorId; UserAuthType HwAuthenticatorId; - * KMInteger TimeStamp; KMByteBlob Mac} + * KMHardwareAuthToken represents HardwareAuthToken structure from android keymaster hal + * specifications. It corresponds to CBOR array type. struct{byte HW_AUTH_TOKEN_TYPE; short + * length=2; short arrayPtr} where arrayPtr is a pointer to ordered array with following elements: + * {KMInteger Challenge; KMInteger UserId; KMInteger AuthenticatorId; UserAuthType + * HwAuthenticatorId; KMInteger TimeStamp; KMByteBlob Mac} */ public class KMHardwareAuthToken extends KMType { + public static final byte CHALLENGE = 0x00; public static final byte USER_ID = 0x01; public static final byte AUTHENTICATOR_ID = 0x02; @@ -39,10 +39,11 @@ public class KMHardwareAuthToken extends KMType { private static KMHardwareAuthToken prototype; private static short instPtr; - private KMHardwareAuthToken() {} + private KMHardwareAuthToken() { + } public static short exp() { - short arrPtr = KMArray.instance((short)6); + short arrPtr = KMArray.instance((short) 6); KMArray arr = KMArray.cast(arrPtr); arr.add(CHALLENGE, KMInteger.exp()); arr.add(USER_ID, KMInteger.exp()); @@ -54,35 +55,43 @@ public static short exp() { } private static KMHardwareAuthToken proto(short ptr) { - if (prototype == null) prototype = new KMHardwareAuthToken(); + if (prototype == null) { + prototype = new KMHardwareAuthToken(); + } instPtr = ptr; return prototype; } public static short instance() { - short arrPtr = KMArray.instance((short)6); + short arrPtr = KMArray.instance((short) 6); KMArray arr = KMArray.cast(arrPtr); - arr.add(CHALLENGE, KMInteger.uint_16((short)0)); - arr.add(USER_ID, KMInteger.uint_16((short)0)); - arr.add(AUTHENTICATOR_ID, KMInteger.uint_16((short)0)); + arr.add(CHALLENGE, KMInteger.uint_16((short) 0)); + arr.add(USER_ID, KMInteger.uint_16((short) 0)); + arr.add(AUTHENTICATOR_ID, KMInteger.uint_16((short) 0)); arr.add(HW_AUTHENTICATOR_TYPE, KMEnum.instance(KMType.USER_AUTH_TYPE, KMType.USER_AUTH_NONE)); - arr.add(TIMESTAMP, KMInteger.uint_16((short)0)); - arr.add(MAC, KMByteBlob.instance((short)0)); + arr.add(TIMESTAMP, KMInteger.uint_16((short) 0)); + arr.add(MAC, KMByteBlob.instance((short) 0)); return instance(arrPtr); } public static short instance(short vals) { KMArray arr = KMArray.cast(vals); - if(arr.length() != 6)ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); - short ptr = KMType.instance(HW_AUTH_TOKEN_TYPE, (short)2); - Util.setShort(heap, (short)(ptr + TLV_HEADER_SIZE), vals); + if (arr.length() != 6) { + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + } + short ptr = KMType.instance(HW_AUTH_TOKEN_TYPE, (short) 2); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE), vals); return ptr; } public static KMHardwareAuthToken cast(short ptr) { - if (heap[ptr] != HW_AUTH_TOKEN_TYPE) ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + if (heap[ptr] != HW_AUTH_TOKEN_TYPE) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } short arrPtr = Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE)); - if(heap[arrPtr] != ARRAY_TYPE) ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + if (heap[arrPtr] != ARRAY_TYPE) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } return proto(ptr); } diff --git a/Applet/src/com/android/javacard/keymaster/KMHmacSharingParameters.java b/Applet/src/com/android/javacard/keymaster/KMHmacSharingParameters.java index c05ee29f..81a19bd3 100644 --- a/Applet/src/com/android/javacard/keymaster/KMHmacSharingParameters.java +++ b/Applet/src/com/android/javacard/keymaster/KMHmacSharingParameters.java @@ -19,24 +19,26 @@ import javacard.framework.ISO7816; import javacard.framework.ISOException; import javacard.framework.Util; + /** - * KMHmacSharingParameters represents HmacSharingParameters structure from android keymaster hal specifications. - * It corresponds to CBOR array type. - * struct{byte HMAC_SHARING_PARAM_TYPE; short length=2; short arrayPtr} where arrayPtr is a pointer to - * ordered array with following elements: + * KMHmacSharingParameters represents HmacSharingParameters structure from android keymaster hal + * specifications. It corresponds to CBOR array type. struct{byte HMAC_SHARING_PARAM_TYPE; short + * length=2; short arrayPtr} where arrayPtr is a pointer to ordered array with following elements: * {KMByteBlob Seed; KMByteBlob Nonce} */ public class KMHmacSharingParameters extends KMType { + public static final byte SEED = 0x00; public static final byte NONCE = 0x01; private static KMHmacSharingParameters prototype; private static short instPtr; - private KMHmacSharingParameters() {} + private KMHmacSharingParameters() { + } public static short exp() { - short arrPtr = KMArray.instance((short)2); + short arrPtr = KMArray.instance((short) 2); KMArray arr = KMArray.cast(arrPtr); arr.add(SEED, KMByteBlob.exp()); arr.add(NONCE, KMByteBlob.exp()); @@ -44,27 +46,35 @@ public static short exp() { } private static KMHmacSharingParameters proto(short ptr) { - if (prototype == null) prototype = new KMHmacSharingParameters(); + if (prototype == null) { + prototype = new KMHmacSharingParameters(); + } instPtr = ptr; return prototype; } public static short instance() { - short arrPtr = KMArray.instance((short)2); + short arrPtr = KMArray.instance((short) 2); return instance(arrPtr); } public static short instance(short vals) { - short ptr = KMType.instance(HMAC_SHARING_PARAM_TYPE, (short)2); - if(KMArray.cast(vals).length() != 2) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); - Util.setShort(heap, (short)(ptr + TLV_HEADER_SIZE), vals); + short ptr = KMType.instance(HMAC_SHARING_PARAM_TYPE, (short) 2); + if (KMArray.cast(vals).length() != 2) { + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + } + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE), vals); return ptr; } public static KMHmacSharingParameters cast(short ptr) { - if (heap[ptr] != HMAC_SHARING_PARAM_TYPE) ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + if (heap[ptr] != HMAC_SHARING_PARAM_TYPE) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } short arrPtr = Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE)); - if(heap[arrPtr] != ARRAY_TYPE) ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + if (heap[arrPtr] != ARRAY_TYPE) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } return proto(ptr); } diff --git a/Applet/src/com/android/javacard/keymaster/KMInteger.java b/Applet/src/com/android/javacard/keymaster/KMInteger.java index 18944e4d..1330f85f 100644 --- a/Applet/src/com/android/javacard/keymaster/KMInteger.java +++ b/Applet/src/com/android/javacard/keymaster/KMInteger.java @@ -25,15 +25,19 @@ * struct{byte INTEGER_TYPE; short length; 4 or 8 bytes of value} */ public class KMInteger extends KMType { + public static final short UINT_32 = 4; public static final short UINT_64 = 8; private static KMInteger prototype; private static short instPtr; - private KMInteger() {} + private KMInteger() { + } private static KMInteger proto(short ptr) { - if (prototype == null) prototype = new KMInteger(); + if (prototype == null) { + prototype = new KMInteger(); + } instPtr = ptr; return prototype; } @@ -44,7 +48,9 @@ public static short exp() { // return an empty integer instance public static short instance(short length) { - if ((length <= 0) || (length > 8)) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + if ((length <= 0) || (length > 8)) { + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + } if (length > 4) { length = UINT_64; } else { @@ -70,7 +76,9 @@ public static short instance(byte[] num, short srcOff, short length) { public static KMInteger cast(short ptr) { byte[] heap = repository.getHeap(); - if (heap[ptr] != INTEGER_TYPE) ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + if (heap[ptr] != INTEGER_TYPE) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } if (Util.getShort(heap, (short) (ptr + 1)) == INVALID_VALUE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -120,52 +128,77 @@ public short getStartOff() { return (short) (instPtr + TLV_HEADER_SIZE); } - public void getValue(byte[] dest, short destOff, short length){ - if(length < length()) KMException.throwIt(KMError.UNKNOWN_ERROR); - if(length > length()) { + public void getValue(byte[] dest, short destOff, short length) { + if (length < length()) { + KMException.throwIt(KMError.UNKNOWN_ERROR); + } + if (length > length()) { length = length(); - destOff +=length; + destOff += length; } - Util.arrayCopyNonAtomic(heap, (short)(instPtr+TLV_HEADER_SIZE), dest, destOff, length); + Util.arrayCopyNonAtomic(heap, (short) (instPtr + TLV_HEADER_SIZE), dest, destOff, length); } - public void setValue(byte[] src, short srcOff){ - Util.arrayCopyNonAtomic(src, srcOff, heap, (short)(instPtr+TLV_HEADER_SIZE), length()); + + public void setValue(byte[] src, short srcOff) { + Util.arrayCopyNonAtomic(src, srcOff, heap, (short) (instPtr + TLV_HEADER_SIZE), length()); } - public short value(byte[] dest, short destOff){ - Util.arrayCopyNonAtomic(heap, (short)(instPtr+TLV_HEADER_SIZE), dest, destOff, length()); + + public short value(byte[] dest, short destOff) { + Util.arrayCopyNonAtomic(heap, (short) (instPtr + TLV_HEADER_SIZE), dest, destOff, length()); return length(); } public short getShort() { return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE + 2)); } - public short getSignificantShort(){ + + public short getSignificantShort() { return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE)); } + public byte getByte() { return heap[(short) (instPtr + TLV_HEADER_SIZE + 3)]; } public boolean isZero() { - if(getShort() == 0 && getSignificantShort() == 0){ + if (getShort() == 0 && getSignificantShort() == 0) { return true; } return false; } - public static short compare(short num1, short num2){ - short num1Buf = repository.alloc((short)8); - short num2Buf = repository.alloc((short)8); - Util.arrayFillNonAtomic(repository.getHeap(),num1Buf,(short)8,(byte)0); - Util.arrayFillNonAtomic(repository.getHeap(),num2Buf,(short)8,(byte)0); + public static short compare(short num1, short num2) { + short num1Buf = repository.alloc((short) 8); + 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 len = KMInteger.cast(num1).length(); - KMInteger.cast(num1).getValue(repository.getHeap(),(short)(num1Buf+(short)(8-len)),len); + 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 KMUtils.unsignedByteArrayCompare( - repository.getHeap(), num1Buf, - repository.getHeap(), num2Buf, - (short)8); + KMInteger.cast(num2).getValue(repository.getHeap(), (short) (num2Buf + (short) (8 - len)), len); + return KMInteger.unsignedByteArrayCompare( + repository.getHeap(), num1Buf, + repository.getHeap(), num2Buf, + (short) 8); + } + + 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; } - } diff --git a/Applet/src/com/android/javacard/keymaster/KMIntegerArrayTag.java b/Applet/src/com/android/javacard/keymaster/KMIntegerArrayTag.java index 7faa4c00..b97f5fa6 100644 --- a/Applet/src/com/android/javacard/keymaster/KMIntegerArrayTag.java +++ b/Applet/src/com/android/javacard/keymaster/KMIntegerArrayTag.java @@ -21,20 +21,24 @@ import javacard.framework.Util; /** - * KMIntegerArrayTag represents UINT_REP and ULONG_REP tags specified in keymaster hal specs. struct{byte - * TAG_TYPE; short length; struct{short UINT_TAG/ULONG_TAG; short tagKey; short arrPtr}, where arrPtr - * is the pointer to KMArray of KMInteger instances. + * KMIntegerArrayTag represents UINT_REP and ULONG_REP tags specified in keymaster hal specs. + * struct{byte TAG_TYPE; short length; struct{short UINT_TAG/ULONG_TAG; short tagKey; short arrPtr}, + * where arrPtr is the pointer to KMArray of KMInteger instances. */ public class KMIntegerArrayTag extends KMTag { + private static KMIntegerArrayTag prototype; private static short instPtr; private static final short[] tags = {USER_SECURE_ID}; - private KMIntegerArrayTag() {} + private KMIntegerArrayTag() { + } private static KMIntegerArrayTag proto(short ptr) { - if (prototype == null) prototype = new KMIntegerArrayTag(); + if (prototype == null) { + prototype = new KMIntegerArrayTag(); + } instPtr = ptr; return prototype; } @@ -44,10 +48,10 @@ public static short exp(short tagType) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } short arrPtr = KMArray.exp(KMType.INTEGER_TYPE); - short ptr = instance(TAG_TYPE, (short)6); - Util.setShort(heap, (short)(ptr+TLV_HEADER_SIZE), tagType); - Util.setShort(heap, (short)(ptr+TLV_HEADER_SIZE+2), INVALID_TAG); - Util.setShort(heap, (short)(ptr+TLV_HEADER_SIZE+4), arrPtr); + short ptr = instance(TAG_TYPE, (short) 6); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE), tagType); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE + 2), INVALID_TAG); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE + 4), arrPtr); return ptr; } @@ -69,18 +73,20 @@ public static short instance(short tagType, short key, short arrObj) { if (!validateKey(key)) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } - if(heap[arrObj] != ARRAY_TYPE) { + if (heap[arrObj] != ARRAY_TYPE) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } - short ptr = instance(TAG_TYPE, (short)6); - Util.setShort(heap, (short)(ptr+TLV_HEADER_SIZE), tagType); - Util.setShort(heap, (short)(ptr+TLV_HEADER_SIZE+2), key); - Util.setShort(heap, (short)(ptr+TLV_HEADER_SIZE+4), arrObj); + short ptr = instance(TAG_TYPE, (short) 6); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE), tagType); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE + 2), key); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE + 4), arrObj); return ptr; } public static KMIntegerArrayTag cast(short ptr) { - if (heap[ptr] != TAG_TYPE) ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + if (heap[ptr] != TAG_TYPE) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } short tagType = Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE)); if (!validateTagType(tagType)) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); @@ -89,15 +95,15 @@ public static KMIntegerArrayTag cast(short ptr) { } public short getTagType() { - return Util.getShort(heap, (short)(instPtr+TLV_HEADER_SIZE)); + return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE)); } public short getKey() { - return Util.getShort(heap, (short)(instPtr+TLV_HEADER_SIZE+2)); + return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE + 2)); } public short getValues() { - return Util.getShort(heap, (short)(instPtr+TLV_HEADER_SIZE+4)); + return Util.getShort(heap, (short) (instPtr + TLV_HEADER_SIZE + 4)); } public short length() { @@ -131,7 +137,7 @@ private static boolean validateTagType(short tagType) { public static boolean contains(short tagId, short tagValue, short params) { short tag = - KMKeyParameters.findTag(KMType.UINT_ARRAY_TAG, tagId, params); + KMKeyParameters.findTag(KMType.UINT_ARRAY_TAG, tagId, params); if (tag != KMType.INVALID_VALUE) { short index = 0; tag = KMIntegerArrayTag.cast(tag).getValues(); diff --git a/Applet/src/com/android/javacard/keymaster/KMIntegerTag.java b/Applet/src/com/android/javacard/keymaster/KMIntegerTag.java index 2700580f..44136ec4 100644 --- a/Applet/src/com/android/javacard/keymaster/KMIntegerTag.java +++ b/Applet/src/com/android/javacard/keymaster/KMIntegerTag.java @@ -19,40 +19,46 @@ import javacard.framework.ISO7816; import javacard.framework.ISOException; import javacard.framework.Util; + /** * KMIntegerTag represents UINT, ULONG and DATE tags specified in keymaster hal specs. struct{byte - * TAG_TYPE; short length; struct{short UINT_TAG/ULONG_TAG/DATE_TAG; short tagKey; 4 or 8 byte value}} + * TAG_TYPE; short length; struct{short UINT_TAG/ULONG_TAG/DATE_TAG; short tagKey; 4 or 8 byte + * value}} */ public class KMIntegerTag extends KMTag { + private static KMIntegerTag prototype; private static short instPtr; // Allowed tag keys. private static final short[] tags = { - // UINT - KEYSIZE, - MIN_MAC_LENGTH, - MIN_SEC_BETWEEN_OPS, - MAX_USES_PER_BOOT, - USERID, - AUTH_TIMEOUT, - OS_VERSION, - OS_PATCH_LEVEL, - VENDOR_PATCH_LEVEL, - BOOT_PATCH_LEVEL, - MAC_LENGTH, - // ULONG - RSA_PUBLIC_EXPONENT, - // DATE - ACTIVE_DATETIME, - ORIGINATION_EXPIRE_DATETIME, - USAGE_EXPIRE_DATETIME, - CREATION_DATETIME + // UINT + KEYSIZE, + MIN_MAC_LENGTH, + MIN_SEC_BETWEEN_OPS, + MAX_USES_PER_BOOT, + USERID, + AUTH_TIMEOUT, + OS_VERSION, + OS_PATCH_LEVEL, + VENDOR_PATCH_LEVEL, + BOOT_PATCH_LEVEL, + MAC_LENGTH, + // ULONG + RSA_PUBLIC_EXPONENT, + // DATE + ACTIVE_DATETIME, + ORIGINATION_EXPIRE_DATETIME, + USAGE_EXPIRE_DATETIME, + CREATION_DATETIME }; - private KMIntegerTag() {} + private KMIntegerTag() { + } private static KMIntegerTag proto(short ptr) { - if (prototype == null) prototype = new KMIntegerTag(); + if (prototype == null) { + prototype = new KMIntegerTag(); + } instPtr = ptr; return prototype; } @@ -98,7 +104,9 @@ public static short instance(short tagType, short key, short intObj) { } public static KMIntegerTag cast(short ptr) { - if (heap[ptr] != TAG_TYPE) ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + if (heap[ptr] != TAG_TYPE) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } short tagType = Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE)); if (!validateTagType(tagType)) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); @@ -172,19 +180,29 @@ public boolean isValidKeySize(byte alg) { val = KMInteger.cast(val).getShort(); switch (alg) { case KMType.RSA: - if (val == 2048) return true; + if (val == 2048) { + return true; + } break; case KMType.AES: - if (val == 128 || val == 256) return true; + if (val == 128 || val == 256) { + return true; + } break; case KMType.DES: - if (val == 192 || val == 168) return true; + if (val == 192 || val == 168) { + return true; + } break; case KMType.EC: - if (val == 256) return true; + if (val == 256) { + return true; + } break; case KMType.HMAC: - if (val % 8 == 0 && val >= 64 && val <= 512) return true; + if (val % 8 == 0 && val >= 64 && val <= 512) { + return true; + } break; default: break; diff --git a/Applet/src/com/android/javacard/keymaster/KMKeyCharacteristics.java b/Applet/src/com/android/javacard/keymaster/KMKeyCharacteristics.java index 2b482b01..2ad16117 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeyCharacteristics.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeyCharacteristics.java @@ -19,25 +19,27 @@ import javacard.framework.ISO7816; import javacard.framework.ISOException; import javacard.framework.Util; + /** - * KMKeyCharacteristics represents KeyCharacteristics structure from android keymaster hal specifications. - * It corresponds to CBOR array type. - * struct{byte KEY_CHAR_TYPE; short length=2; short arrayPtr} where arrayPtr is a pointer to - * ordered array with following elements: + * KMKeyCharacteristics represents KeyCharacteristics structure from android keymaster hal + * specifications. It corresponds to CBOR array type. struct{byte KEY_CHAR_TYPE; short length=2; + * short arrayPtr} where arrayPtr is a pointer to ordered array with following elements: * {KMKeyParameters sofEnf; KMKeyParameters hwEnf} */ public class KMKeyCharacteristics extends KMType { + public static final byte SOFTWARE_ENFORCED = 0x00; public static final byte HARDWARE_ENFORCED = 0x01; private static KMKeyCharacteristics prototype; private static short instPtr; - private KMKeyCharacteristics() {} + private KMKeyCharacteristics() { + } public static short exp() { short softEnf = KMKeyParameters.exp(); short hwEnf = KMKeyParameters.exp(); - short arrPtr = KMArray.instance((short)2); + short arrPtr = KMArray.instance((short) 2); KMArray arr = KMArray.cast(arrPtr); arr.add(SOFTWARE_ENFORCED, softEnf); arr.add(HARDWARE_ENFORCED, hwEnf); @@ -45,27 +47,35 @@ public static short exp() { } private static KMKeyCharacteristics proto(short ptr) { - if (prototype == null) prototype = new KMKeyCharacteristics(); + if (prototype == null) { + prototype = new KMKeyCharacteristics(); + } instPtr = ptr; return prototype; } public static short instance() { - short arrPtr = KMArray.instance((short)2); + short arrPtr = KMArray.instance((short) 2); return instance(arrPtr); } public static short instance(short vals) { - short ptr = KMType.instance(KEY_CHAR_TYPE, (short)2); - if(KMArray.cast(vals).length() != 2) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); - Util.setShort(heap, (short)(ptr + TLV_HEADER_SIZE), vals); + short ptr = KMType.instance(KEY_CHAR_TYPE, (short) 2); + if (KMArray.cast(vals).length() != 2) { + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + } + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE), vals); return ptr; } public static KMKeyCharacteristics cast(short ptr) { - if (heap[ptr] != KEY_CHAR_TYPE) ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + if (heap[ptr] != KEY_CHAR_TYPE) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } short arrPtr = Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE)); - if(heap[arrPtr] != ARRAY_TYPE) ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + if (heap[arrPtr] != ARRAY_TYPE) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } return proto(ptr); } @@ -80,7 +90,7 @@ public short length() { public short getSoftwareEnforced() { short arrPtr = getVals(); - return KMArray.cast(arrPtr).get(SOFTWARE_ENFORCED); + return KMArray.cast(arrPtr).get(SOFTWARE_ENFORCED); } public short getHardwareEnforced() { diff --git a/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java b/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java index f08ee388..cfdd9c30 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java @@ -21,19 +21,22 @@ import javacard.framework.Util; /** - * KMKeyParameters represents KeyParameters structure from android keymaster hal specifications. - * It corresponds to CBOR map type. - * struct{byte KEY_PARAM_TYPE; short length=2; short arrayPtr} where arrayPtr is a pointer to - * array with any KMTag subtype instances. + * KMKeyParameters represents KeyParameters structure from android keymaster hal specifications. It + * corresponds to CBOR map type. struct{byte KEY_PARAM_TYPE; short length=2; short arrayPtr} where + * arrayPtr is a pointer to array with any KMTag subtype instances. */ public class KMKeyParameters extends KMType { + private static KMKeyParameters prototype; private static short instPtr; - private KMKeyParameters() {} + private KMKeyParameters() { + } private static KMKeyParameters proto(short ptr) { - if (prototype == null) prototype = new KMKeyParameters(); + if (prototype == null) { + prototype = new KMKeyParameters(); + } instPtr = ptr; return prototype; } @@ -60,9 +63,13 @@ public static short instance(short vals) { } public static KMKeyParameters cast(short ptr) { - if (heap[ptr] != KEY_PARAM_TYPE) ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + if (heap[ptr] != KEY_PARAM_TYPE) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } short arrPtr = Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE)); - if (heap[arrPtr] != ARRAY_TYPE) ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + if (heap[arrPtr] != ARRAY_TYPE) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } return proto(ptr); } @@ -80,7 +87,7 @@ public static short findTag(short tagType, short tagKey, short keyParam) { return instParam.findTag(tagType, tagKey); } - public short findTag(short tagType, short tagKey){ + public short findTag(short tagType, short tagKey) { KMArray vals = KMArray.cast(getVals()); short index = 0; short length = vals.length(); @@ -100,16 +107,16 @@ 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, - KMType.UINT_TAG, KMType.MAX_USES_PER_BOOT - }; + // 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, + KMType.UINT_TAG, KMType.MAX_USES_PER_BOOT + }; byte index = 0; short tagInd; short tagPtr; @@ -136,30 +143,30 @@ public static boolean hasUnsupportedTags(short keyParamsPtr) { // KDF, ECIES_SINGLE_HASH_MODE missing from types.hal public static short makeHwEnforced(short keyParamsPtr, byte origin, - short osVersionObjPtr, short osPatchObjPtr, short vendorPatchObjPtr, - short bootPatchObjPtr, byte[] scratchPad) { + short osVersionObjPtr, short osPatchObjPtr, short vendorPatchObjPtr, + short bootPatchObjPtr, byte[] scratchPad) { final short[] hwEnforcedTagArr = { - // HW Enforced - KMType.ENUM_TAG, KMType.ORIGIN, - KMType.ENUM_ARRAY_TAG, KMType.PURPOSE, - KMType.ENUM_TAG, KMType.ALGORITHM, - KMType.UINT_TAG, KMType.KEYSIZE, - KMType.ULONG_TAG, KMType.RSA_PUBLIC_EXPONENT, - KMType.ENUM_TAG, KMType.BLOB_USAGE_REQ, - KMType.ENUM_ARRAY_TAG, KMType.DIGEST, - KMType.ENUM_ARRAY_TAG, KMType.PADDING, - KMType.ENUM_ARRAY_TAG, KMType.BLOCK_MODE, - 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.INCLUDE_UNIQUE_ID, - KMType.BOOL_TAG, KMType.ROLLBACK_RESISTANCE, - KMType.ENUM_TAG, KMType.USER_AUTH_TYPE, - KMType.BOOL_TAG, KMType.UNLOCKED_DEVICE_REQUIRED, - KMType.BOOL_TAG, KMType.RESET_SINCE_ID_ROTATION + // HW Enforced + KMType.ENUM_TAG, KMType.ORIGIN, + KMType.ENUM_ARRAY_TAG, KMType.PURPOSE, + KMType.ENUM_TAG, KMType.ALGORITHM, + KMType.UINT_TAG, KMType.KEYSIZE, + KMType.ULONG_TAG, KMType.RSA_PUBLIC_EXPONENT, + KMType.ENUM_TAG, KMType.BLOB_USAGE_REQ, + KMType.ENUM_ARRAY_TAG, KMType.DIGEST, + KMType.ENUM_ARRAY_TAG, KMType.PADDING, + KMType.ENUM_ARRAY_TAG, KMType.BLOCK_MODE, + 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.INCLUDE_UNIQUE_ID, + KMType.BOOL_TAG, KMType.ROLLBACK_RESISTANCE, + KMType.ENUM_TAG, KMType.USER_AUTH_TYPE, + KMType.BOOL_TAG, KMType.UNLOCKED_DEVICE_REQUIRED, + KMType.BOOL_TAG, KMType.RESET_SINCE_ID_ROTATION }; byte index = 0; short tagInd; @@ -197,10 +204,12 @@ public static short makeHwEnforced(short keyParamsPtr, byte origin, 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); + 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); + 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)); @@ -209,11 +218,11 @@ public static short makeHwEnforced(short keyParamsPtr, byte origin, // ALL_USERS, EXPORTABLE missing from types.hal public static short makeSwEnforced(short keyParamsPtr, byte[] scratchPad) { final short[] swEnforcedTagsArr = { - KMType.DATE_TAG, KMType.ACTIVE_DATETIME, - KMType.DATE_TAG, KMType.ORIGINATION_EXPIRE_DATETIME, - KMType.DATE_TAG, KMType.USAGE_EXPIRE_DATETIME, - KMType.UINT_TAG, KMType.USERID, - KMType.DATE_TAG, KMType.CREATION_DATETIME + KMType.DATE_TAG, KMType.ACTIVE_DATETIME, + KMType.DATE_TAG, KMType.ORIGINATION_EXPIRE_DATETIME, + KMType.DATE_TAG, KMType.USAGE_EXPIRE_DATETIME, + KMType.UINT_TAG, KMType.USERID, + KMType.DATE_TAG, KMType.CREATION_DATETIME }; byte index = 0; short tagInd; @@ -228,7 +237,7 @@ public static short makeSwEnforced(short keyParamsPtr, byte[] scratchPad) { tagPtr = KMArray.cast(arrPtr).get(index); tagKey = KMTag.getKey(tagPtr); tagType = KMTag.getTagType(tagPtr); - if (!isValidTag(tagType, tagKey)){ + if (!isValidTag(tagType, tagKey)) { KMException.throwIt(KMError.INVALID_KEY_BLOB); } while (tagInd < (short) swEnforcedTagsArr.length) { @@ -250,7 +259,7 @@ public static short makeHidden(short keyParamsPtr, short rootOfTrustBlob, byte[] if (appId != KMTag.INVALID_VALUE) { appId = KMByteTag.cast(appId).getValue(); } - short appData = + short appData = KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_DATA, keyParamsPtr); if (appData != KMTag.INVALID_VALUE) { appData = KMByteTag.cast(appData).getValue(); @@ -258,7 +267,8 @@ public static short makeHidden(short keyParamsPtr, short rootOfTrustBlob, byte[] return makeHidden(appId, appData, rootOfTrustBlob, scratchPad); } - public static short makeHidden(short appIdBlob, short appDataBlob, short rootOfTrustBlob, byte[] scratchPad){ + public static short makeHidden(short appIdBlob, short appDataBlob, short rootOfTrustBlob, + byte[] scratchPad) { // Order in which the hidden array is created should not change. short index = 0; KMByteBlob.cast(rootOfTrustBlob); @@ -273,16 +283,17 @@ public static short makeHidden(short appIdBlob, short appDataBlob, short rootOfT Util.setShort(scratchPad, index, appDataBlob); index += 2; } - return createKeyParameters(scratchPad, (short)(index/2)); + return createKeyParameters(scratchPad, (short) (index / 2)); } + public static boolean isValidTag(short tagType, short tagKey) { short[] invalidTagsArr = { - KMType.BYTES_TAG, KMType.NONCE, - KMType.BYTES_TAG, KMType.ASSOCIATED_DATA, - KMType.BYTES_TAG, KMType.UNIQUE_ID, - KMType.UINT_TAG, KMType.MAC_LENGTH, - KMType.BOOL_TAG, KMType.BOOTLOADER_ONLY + KMType.BYTES_TAG, KMType.NONCE, + KMType.BYTES_TAG, KMType.ASSOCIATED_DATA, + KMType.BYTES_TAG, KMType.UNIQUE_ID, + KMType.UINT_TAG, KMType.MAC_LENGTH, + KMType.BOOL_TAG, KMType.BOOTLOADER_ONLY }; short index = 0; if (tagKey == KMType.INVALID_TAG) { diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index abf6e670..07cc134b 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -32,6 +32,7 @@ * events. */ 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; @@ -43,23 +44,27 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe // "Keymaster HMAC Verification" - used for HMAC key verification. public static final byte[] sharingCheck = { - 0x4B, 0x65, 0x79, 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x48, 0x4D, 0x41, 0x43, 0x20, 0x56, - 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E + 0x4B, 0x65, 0x79, 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x48, 0x4D, 0x41, 0x43, 0x20, + 0x56, + 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E }; // "KeymasterSharedMac" public static final byte[] ckdfLable = { - 0x4B, 0x65, 0x79, 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4D, - 0x61, 0x63 + 0x4B, 0x65, 0x79, 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, + 0x4D, + 0x61, 0x63 }; // "Auth Verification" public static final byte[] authVerification = { - 0x41, 0x75, 0x74, 0x68, 0x20, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, - 0x6E + 0x41, 0x75, 0x74, 0x68, 0x20, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6F, + 0x6E }; // "confirmation token" public static final byte[] confirmationToken = { - 0x63, 0x6F, 0x6E, 0x66, 0x69, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x74, 0x6F, 0x6B, - 0x65, 0x6E + 0x63, 0x6F, 0x6E, 0x66, 0x69, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x74, 0x6F, + 0x6B, + 0x65, 0x6E }; // Possible states of the applet. @@ -180,7 +185,9 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe protected byte provisionStatus = NOT_PROVISIONED; protected static final short MAX_CERT_SIZE = 2048; - /** Registers this applet. */ + /** + * Registers this applet. + */ protected KMKeymasterApplet(KMSEProvider seImpl) { seProvider = seImpl; boolean isUpgrading = seImpl.isUpgrading(); @@ -189,7 +196,7 @@ protected KMKeymasterApplet(KMSEProvider seImpl) { data = JCSystem.makeTransientShortArray((short) DATA_ARRAY_SIZE, JCSystem.CLEAR_ON_RESET); tmpVariables = JCSystem.makeTransientShortArray((short) TMP_VARIABLE_ARRAY_SIZE, JCSystem.CLEAR_ON_RESET); - if(!isUpgrading) { + if (!isUpgrading) { keymasterState = KMKeymasterApplet.INIT_STATE; seProvider.createMasterKey((short) (KMRepository.MASTER_KEY_SIZE * 8)); } @@ -212,13 +219,17 @@ public boolean select() { return true; } - /** De-selects this applet. */ + /** + * De-selects this applet. + */ @Override public void deselect() { repository.onDeselect(); } - /** Uninstalls the applet after cleaning the repository. */ + /** + * Uninstalls the applet after cleaning the repository. + */ @Override public void uninstall() { repository.onUninstall(); @@ -245,7 +256,7 @@ private short mapISOErrorToKMError(short reason) { return KMError.UNKNOWN_ERROR; } } - + private short mapCryptoErrorToKMError(short reason) { switch (reason) { case CryptoException.ILLEGAL_USE: @@ -261,7 +272,7 @@ private short mapCryptoErrorToKMError(short reason) { default: return KMError.UNKNOWN_ERROR; } - } + } protected void validateApduHeader(APDU apdu) { // Read the apdu header and buffer. @@ -291,7 +302,7 @@ public void process(APDU apdu) { repository.onProcess(); // Verify whether applet is in correct state. if ((keymasterState == KMKeymasterApplet.INIT_STATE) - || (keymasterState == KMKeymasterApplet.ILLEGAL_STATE)) { + || (keymasterState == KMKeymasterApplet.ILLEGAL_STATE)) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } // If this is select applet apdu which is selecting this applet then @@ -358,11 +369,11 @@ public void process(APDU apdu) { } if ((keymasterState == KMKeymasterApplet.ACTIVE_STATE) - || (keymasterState == KMKeymasterApplet.IN_PROVISION_STATE)) { + || (keymasterState == KMKeymasterApplet.IN_PROVISION_STATE)) { switch (apduIns) { case INS_SET_BOOT_PARAMS_CMD: if (seProvider.isBootSignalEventSupported() - && (!seProvider.isDeviceRebooted())) { + && (!seProvider.isDeviceRebooted())) { ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); } processSetBootParamsCmd(apdu); @@ -378,8 +389,8 @@ public void process(APDU apdu) { } if ((keymasterState == KMKeymasterApplet.ACTIVE_STATE) - || ((keymasterState == KMKeymasterApplet.IN_PROVISION_STATE) - && isProvisioningComplete())) { + || ((keymasterState == KMKeymasterApplet.IN_PROVISION_STATE) + && isProvisioningComplete())) { switch (apduIns) { case INS_GENERATE_KEY_CMD: processGenerateKey(apdu); @@ -479,11 +490,11 @@ private void generateUniqueOperationHandle(byte[] buf, short offset, short len) } 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_PRESHARED_SECRET)) - && (0 != (provisionStatus & PROVISION_STATUS_BOOT_PARAM))) { + 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_PRESHARED_SECRET)) + && (0 != (provisionStatus & PROVISION_STATUS_BOOT_PARAM))) { return true; } else { return false; @@ -543,10 +554,13 @@ private void resetData() { index++; } } - /** Sends a response, may be extended response, as requested by the command. */ + + /** + * Sends a response, may be extended response, as requested by the command. + */ public static void sendOutgoing(APDU apdu) { if (((short) (bufferLength + bufferStartOffset)) > ((short) repository - .getHeap().length)) { + .getHeap().length)) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } // Send data @@ -555,7 +569,9 @@ public static void sendOutgoing(APDU apdu) { apdu.sendBytesLong(buffer, bufferStartOffset, bufferLength); } - /** Receives data, which can be extended data, as requested by the command instance. */ + /** + * Receives data, which can be extended data, as requested by the command instance. + */ public static void receiveIncoming(APDU apdu) { byte[] srcBuffer = apdu.getBuffer(); short recvLen = apdu.setIncomingAndReceive(); @@ -574,8 +590,8 @@ public static void receiveIncoming(APDU apdu) { private void processGetHwInfoCmd(APDU apdu) { // No arguments expected final byte[] JavacardKeymasterDevice = { - 0x4A, 0x61, 0x76, 0x61, 0x63, 0x61, 0x72, 0x64, 0x4B, 0x65, 0x79, 0x6D, 0x61, 0x73, 0x74, - 0x65, 0x72, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x4A, 0x61, 0x76, 0x61, 0x63, 0x61, 0x72, 0x64, 0x4B, 0x65, 0x79, 0x6D, 0x61, 0x73, 0x74, + 0x65, 0x72, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, }; final byte[] Google = {0x47, 0x6F, 0x6F, 0x67, 0x6C, 0x65}; @@ -674,18 +690,19 @@ private void processProvisionAttestationCertChainCmd(APDU apdu) { bufferStartOffset = repository.alloc(bufferLength); short bytesRead = 0; Util.arrayCopyNonAtomic(srcBuffer, srcOffset, buffer, bufferStartOffset, - recvLen); + recvLen); // tmpVariables[1] holds the total length + Header length. tmpVariables[1] = decoder.readCertificateChainLengthAndHeaderLen(buffer, - bufferStartOffset, recvLen); + bufferStartOffset, recvLen); while (recvLen > 0 && ((short) bytesRead <= bufferLength)) { seProvider.persistPartialCertificateChain(buffer, bufferStartOffset, - recvLen, bufferLength); + recvLen, bufferLength); bytesRead += recvLen; recvLen = apdu.receiveBytes(srcOffset); - if (recvLen > 0) + if (recvLen > 0) { Util.arrayCopyNonAtomic(srcBuffer, srcOffset, buffer, bufferStartOffset, - recvLen); + recvLen); + } } if (tmpVariables[1] != bytesRead) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); @@ -730,10 +747,13 @@ private void processProvisionAttestationKey(APDU apdu) { tmpVariables[0] = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.DIGEST, data[KEY_PARAMETERS]); if (tmpVariables[0] != KMType.INVALID_VALUE) { - if (KMEnumArrayTag.cast(tmpVariables[0]).length() != 1) + 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.SHA2_256) KMException.throwIt(KMError.INCOMPATIBLE_DIGEST); + if (tmpVariables[0] != KMType.SHA2_256) { + KMException.throwIt(KMError.INCOMPATIBLE_DIGEST); + } } else { KMException.throwIt(KMError.INVALID_ARGUMENT); } @@ -741,10 +761,13 @@ private void processProvisionAttestationKey(APDU apdu) { tmpVariables[0] = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PURPOSE, data[KEY_PARAMETERS]); if (tmpVariables[0] != KMType.INVALID_VALUE) { - if (KMEnumArrayTag.cast(tmpVariables[0]).length() != 1) + 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.ATTEST_KEY) KMException.throwIt(KMError.INCOMPATIBLE_PURPOSE); + if (tmpVariables[0] != KMType.ATTEST_KEY) { + KMException.throwIt(KMError.INCOMPATIBLE_PURPOSE); + } } else { KMException.throwIt(KMError.INVALID_ARGUMENT); } @@ -753,9 +776,9 @@ private void processProvisionAttestationKey(APDU apdu) { // persist key seProvider.createAttestationKey( - KMByteBlob.cast(data[SECRET]).getBuffer(), - KMByteBlob.cast(data[SECRET]).getStartOff(), - KMByteBlob.cast(data[SECRET]).length()); + KMByteBlob.cast(data[SECRET]).getBuffer(), + KMByteBlob.cast(data[SECRET]).getStartOff(), + KMByteBlob.cast(data[SECRET]).length()); } private void processProvisionAttestIdsCmd(APDU apdu) { @@ -938,9 +961,9 @@ private void processDeleteKeyCmd(APDU apdu) { KMArray.cast(tmpVariables[1]).add(KMKeymasterApplet.KEY_BLOB_PUB_KEY, KMByteBlob.exp()); 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()); + 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. @@ -1017,11 +1040,11 @@ private void processComputeSharedHmacCmd(APDU apdu) { if (tmpVariables[7] == 1) { if (0 == Util.arrayCompare( - repository.getHeap(), - (short) (tmpVariables[1] + tmpVariables[3]), - KMByteBlob.cast(tmpVariables[9]).getBuffer(), - KMByteBlob.cast(tmpVariables[9]).getStartOff(), - tmpVariables[6])) { + repository.getHeap(), + (short) (tmpVariables[1] + tmpVariables[3]), + KMByteBlob.cast(tmpVariables[9]).getBuffer(), + KMByteBlob.cast(tmpVariables[9]).getStartOff(), + tmpVariables[6])) { tmpVariables[7] = 2; // hmac nonce for this keymaster found. } else { tmpVariables[7] = 0; @@ -1129,7 +1152,7 @@ private void processUpgradeKeyCmd(APDU apdu) { } //Compare vendor patch levels tmpVariables[1] = - KMKeyParameters.findTag(KMType.UINT_TAG, KMType.VENDOR_PATCH_LEVEL, data[HW_PARAMETERS]); + 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) { @@ -1142,7 +1165,7 @@ private void processUpgradeKeyCmd(APDU apdu) { } //Compare boot patch levels tmpVariables[1] = - KMKeyParameters.findTag(KMType.UINT_TAG, KMType.BOOT_PATCH_LEVEL, data[HW_PARAMETERS]); + 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) { @@ -1373,7 +1396,9 @@ private void processAttestKeyCmd(APDU apdu) { KMException.throwIt(KMError.INCOMPATIBLE_ALGORITHM); } boolean rsaCert = true; - if (tmpVariables[0] == KMType.EC) rsaCert = false; + if (tmpVariables[0] == KMType.EC) { + rsaCert = false; + } KMAttestationCert cert = seProvider.getAttestationCert(rsaCert); // Save attestation application id - must be present. tmpVariables[0] = @@ -1401,12 +1426,14 @@ private void processAttestKeyCmd(APDU apdu) { // then it is an error. tmpVariables[1] = KMKeyParameters.findTag(KMType.DATE_TAG, KMType.ACTIVE_DATETIME, data[SW_PARAMETERS]); - if (tmpVariables[1] != KMType.INVALID_VALUE) + if (tmpVariables[1] != KMType.INVALID_VALUE) { tmpVariables[1] = KMIntegerTag.cast(tmpVariables[1]).getValue(); - else { + } else { tmpVariables[1] = KMKeyParameters.findTag(KMType.DATE_TAG, KMType.CREATION_DATETIME, data[SW_PARAMETERS]); - if (tmpVariables[1] == KMType.INVALID_VALUE) KMException.throwIt(KMError.INVALID_KEY_BLOB); + if (tmpVariables[1] == KMType.INVALID_VALUE) { + KMException.throwIt(KMError.INVALID_KEY_BLOB); + } tmpVariables[1] = KMIntegerTag.cast(tmpVariables[1]).getValue(); } // convert milliseconds to UTC date. Start of validity period has to be UTC. @@ -1445,15 +1472,15 @@ private void processAttestKeyCmd(APDU apdu) { // -------------------------------- private void addAttestationIds(KMAttestationCert cert) { final short[] attTags = - new short[] { - KMType.ATTESTATION_ID_BRAND, - KMType.ATTESTATION_ID_DEVICE, - KMType.ATTESTATION_ID_IMEI, - KMType.ATTESTATION_ID_MANUFACTURER, - KMType.ATTESTATION_ID_MEID, - KMType.ATTESTATION_ID_MODEL, - KMType.ATTESTATION_ID_PRODUCT, - KMType.ATTESTATION_ID_SERIAL + new short[]{ + KMType.ATTESTATION_ID_BRAND, + KMType.ATTESTATION_ID_DEVICE, + KMType.ATTESTATION_ID_IMEI, + KMType.ATTESTATION_ID_MANUFACTURER, + KMType.ATTESTATION_ID_MEID, + KMType.ATTESTATION_ID_MODEL, + KMType.ATTESTATION_ID_PRODUCT, + KMType.ATTESTATION_ID_SERIAL }; byte index = 0; short attIdTag; @@ -1481,44 +1508,46 @@ private void addTags(short params, boolean hwEnforced, KMAttestationCert cert) { private void setUniqueId(KMAttestationCert cert, byte[] scratchPad) { tmpVariables[0] = KMKeyParameters.findTag(KMType.BOOL_TAG, - KMType.INCLUDE_UNIQUE_ID, data[HW_PARAMETERS]); + KMType.INCLUDE_UNIQUE_ID, data[HW_PARAMETERS]); if (tmpVariables[0] == KMType.INVALID_VALUE) { return; } // temporal count T tmpVariables[0] = KMKeyParameters.findTag(KMType.DATE_TAG, - KMType.CREATION_DATETIME, data[SW_PARAMETERS]); - if (tmpVariables[0] == KMType.INVALID_VALUE) + KMType.CREATION_DATETIME, data[SW_PARAMETERS]); + if (tmpVariables[0] == KMType.INVALID_VALUE) { KMException.throwIt(KMError.INVALID_TAG); + } tmpVariables[0] = KMIntegerTag.cast(tmpVariables[0]).getValue(); // Application Id C tmpVariables[1] = KMKeyParameters.findTag(KMType.BYTES_TAG, - KMType.ATTESTATION_APPLICATION_ID, data[KEY_PARAMETERS]); - if (tmpVariables[1] == KMType.INVALID_VALUE) + KMType.ATTESTATION_APPLICATION_ID, data[KEY_PARAMETERS]); + if (tmpVariables[1] == KMType.INVALID_VALUE) { KMException.throwIt(KMError.ATTESTATION_APPLICATION_ID_MISSING); + } tmpVariables[1] = KMByteTag.cast(tmpVariables[1]).getValue(); // 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]); + KMType.RESET_SINCE_ID_ROTATION, data[HW_PARAMETERS]); if (tmpVariables[2] != KMType.INVALID_VALUE) { resetAfterRotation = 0x01; } cert.makeUniqueId( - scratchPad, - (short) 0, - 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, - seProvider.getMasterKey()); + scratchPad, + (short) 0, + 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, + seProvider.getMasterKey()); } private void processDestroyAttIdsCmd(APDU apdu) { @@ -1613,18 +1642,6 @@ private void processFinishOperationCmd(APDU apdu) { private void finishEncryptOperation(KMOperationState op, byte[] scratchPad) { short len = KMByteBlob.cast(data[INPUT_DATA]).length(); switch (op.getAlgorithm()) { - case KMType.RSA: - // Output size is always 256 bytes - data[OUTPUT_DATA] = KMByteBlob.instance((short) 256); - Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0); - op.getOperation() - .finish( - KMByteBlob.cast(data[INPUT_DATA]).getBuffer(), - KMByteBlob.cast(data[INPUT_DATA]).getStartOff(), - KMByteBlob.cast(data[INPUT_DATA]).length(), - KMByteBlob.cast(data[OUTPUT_DATA]).getBuffer(), - KMByteBlob.cast(data[OUTPUT_DATA]).getStartOff()); - break; case KMType.AES: case KMType.DES: if (op.getAlgorithm() == KMType.AES) { @@ -1674,8 +1691,9 @@ private void finishDecryptOperation(KMOperationState op, byte[] scratchPad) { case KMType.RSA: // Fill the scratch pad with zero Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0); - if (op.getPadding() == KMType.PADDING_NONE && len != 256) + if (op.getPadding() == KMType.PADDING_NONE && len != 256) { KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + } len = op.getOperation() .finish( @@ -1764,37 +1782,25 @@ private void finishSigningVerifyingOperation(KMOperationState op, byte[] scratch Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0); switch (op.getAlgorithm()) { case KMType.RSA: - // Output for signature is always 256 bytes. - data[OUTPUT_DATA] = KMByteBlob.instance((short) 256); // If there is no padding we can treat signing as a RSA decryption operation. - if (op.getDigest() == KMType.DIGEST_NONE && op.getPadding() == KMType.PADDING_NONE) { - // Input data of Verify operation must be 256 bytes - if (op.getPurpose() == KMType.VERIFY - && KMByteBlob.cast(data[INPUT_DATA]).length() != 256) { - KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - } - } try { if (op.getPurpose() == KMType.SIGN) { // len of signature will be 256 bytes - op.getOperation() - .sign( + short len = op.getOperation().sign( KMByteBlob.cast(data[INPUT_DATA]).getBuffer(), KMByteBlob.cast(data[INPUT_DATA]).getStartOff(), - KMByteBlob.cast(data[INPUT_DATA]).length(), + KMByteBlob.cast(data[INPUT_DATA]).length(), scratchPad, + (short) 0); + // Maximum output size of signature is 256 bytes. + data[OUTPUT_DATA] = KMByteBlob.instance((short) 256); + Util.arrayCopyNonAtomic( + scratchPad, + (short) 0, KMByteBlob.cast(data[OUTPUT_DATA]).getBuffer(), - KMByteBlob.cast(data[OUTPUT_DATA]).getStartOff()); + (short) (KMByteBlob.cast(data[OUTPUT_DATA]).getStartOff() + 256 - len), + len); } else { - if (!op.getOperation() - .verify( - KMByteBlob.cast(data[INPUT_DATA]).getBuffer(), - KMByteBlob.cast(data[INPUT_DATA]).getStartOff(), - KMByteBlob.cast(data[INPUT_DATA]).length(), - KMByteBlob.cast(data[SIGNATURE]).getBuffer(), - KMByteBlob.cast(data[SIGNATURE]).getStartOff(), - KMByteBlob.cast(data[SIGNATURE]).length())) { - KMException.throwIt(KMError.VERIFICATION_FAILED); - } + KMException.throwIt(KMError.UNSUPPORTED_PURPOSE); } } catch (CryptoException e) { KMException.throwIt(KMError.INVALID_ARGUMENT); @@ -1818,16 +1824,7 @@ private void finishSigningVerifyingOperation(KMOperationState op, byte[] scratch (short) 0); data[OUTPUT_DATA] = KMByteBlob.instance(scratchPad, (short) 0, len); } else { - if (!op.getOperation() - .verify( - KMByteBlob.cast(data[INPUT_DATA]).getBuffer(), - KMByteBlob.cast(data[INPUT_DATA]).getStartOff(), - len, - KMByteBlob.cast(data[SIGNATURE]).getBuffer(), - KMByteBlob.cast(data[SIGNATURE]).getStartOff(), - KMByteBlob.cast(data[SIGNATURE]).length())) { - KMException.throwIt(KMError.VERIFICATION_FAILED); - } + KMException.throwIt(KMError.UNSUPPORTED_PURPOSE); } break; case KMType.HMAC: @@ -1856,11 +1853,11 @@ private void finishSigningVerifyingOperation(KMOperationState op, byte[] scratch if (op.getPurpose() == KMType.VERIFY) { if (0 != Util.arrayCompare( - KMByteBlob.cast(data[OUTPUT_DATA]).getBuffer(), - KMByteBlob.cast(data[OUTPUT_DATA]).getStartOff(), - KMByteBlob.cast(data[SIGNATURE]).getBuffer(), - KMByteBlob.cast(data[SIGNATURE]).getStartOff(), - (short) (op.getMacLength() / 8))) { + KMByteBlob.cast(data[OUTPUT_DATA]).getBuffer(), + KMByteBlob.cast(data[OUTPUT_DATA]).getStartOff(), + KMByteBlob.cast(data[SIGNATURE]).getBuffer(), + KMByteBlob.cast(data[SIGNATURE]).getStartOff(), + (short) (op.getMacLength() / 8))) { KMException.throwIt(KMError.VERIFICATION_FAILED); } } @@ -1901,7 +1898,9 @@ private void authorizeDeviceUnlock(short hwToken) { KMType.BOOL_TAG, KMType.UNLOCKED_DEVICE_REQUIRED, data[HW_PARAMETERS]); if (ptr != KMType.INVALID_VALUE && repository.getDeviceLock()) { - if (hwToken == KMType.INVALID_VALUE) KMException.throwIt(KMError.DEVICE_LOCKED); + if (hwToken == KMType.INVALID_VALUE) { + KMException.throwIt(KMError.DEVICE_LOCKED); + } ptr = KMHardwareAuthToken.cast(hwToken).getTimestamp(); // Check if the current auth time stamp is greater then device locked time stamp short ts = repository.getDeviceTimeStamp(); @@ -2022,7 +2021,9 @@ private void processUpdateOperationCmd(APDU apdu) { // Check Operation Handle and get op state // Check Operation Handle KMOperationState op = repository.findOperation(data[OP_HANDLE]); - if (op == null) KMException.throwIt(KMError.INVALID_OPERATION_HANDLE); + if (op == null) { + KMException.throwIt(KMError.INVALID_OPERATION_HANDLE); + } // authorize the update operation authorizeUpdateFinishOperation(op, scratchPad); // If signing without digest then do length validation checks @@ -2162,17 +2163,18 @@ private void processBeginOperationCmd(APDU apdu) { /*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()); + 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()); + KMByteBlob.cast(buf).getBuffer(), + KMByteBlob.cast(buf).getStartOff(), + KMByteBlob.cast(buf).length()); KMOperationState op = repository.reserveOperation(opHandle); - if (op == null) + 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()); @@ -2237,13 +2239,15 @@ private void authorizePurpose(KMOperationState op) { switch (op.getAlgorithm()) { case KMType.AES: case KMType.DES: - if (op.getPurpose() == KMType.SIGN || op.getPurpose() == KMType.VERIFY) + if (op.getPurpose() == KMType.SIGN || op.getPurpose() == KMType.VERIFY) { KMException.throwIt(KMError.UNSUPPORTED_PURPOSE); + } break; case KMType.EC: case KMType.HMAC: - if (op.getPurpose() == KMType.ENCRYPT || op.getPurpose() == KMType.DECRYPT) + if (op.getPurpose() == KMType.ENCRYPT || op.getPurpose() == KMType.DECRYPT) { KMException.throwIt(KMError.UNSUPPORTED_PURPOSE); + } break; default: break; @@ -2260,17 +2264,21 @@ private void authorizeDigest(KMOperationState op) { short param = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.DIGEST, data[KEY_PARAMETERS]); if (param != KMType.INVALID_VALUE) { - if (KMEnumArrayTag.cast(param).length() != 1) KMException.throwIt(KMError.INVALID_ARGUMENT); + if (KMEnumArrayTag.cast(param).length() != 1) { + KMException.throwIt(KMError.INVALID_ARGUMENT); + } param = KMEnumArrayTag.cast(param).get((short) 0); - if (!KMEnumArrayTag.cast(digests).contains(param)) + if (!KMEnumArrayTag.cast(digests).contains(param)) { KMException.throwIt(KMError.INCOMPATIBLE_DIGEST); + } op.setDigest((byte) param); } short paramPadding = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PADDING, data[KEY_PARAMETERS]); if (paramPadding != KMType.INVALID_VALUE) { - if (KMEnumArrayTag.cast(paramPadding).length() != 1) + if (KMEnumArrayTag.cast(paramPadding).length() != 1) { KMException.throwIt(KMError.INVALID_ARGUMENT); + } paramPadding = KMEnumArrayTag.cast(paramPadding).get((short) 0); } switch (op.getAlgorithm()) { @@ -2282,7 +2290,9 @@ private void authorizeDigest(KMOperationState op) { break; case KMType.EC: case KMType.HMAC: - if (param == KMType.INVALID_VALUE) KMException.throwIt(KMError.UNSUPPORTED_DIGEST); + if (param == KMType.INVALID_VALUE) { + KMException.throwIt(KMError.UNSUPPORTED_DIGEST); + } break; default: break; @@ -2296,24 +2306,31 @@ private void authorizePadding(KMOperationState op) { short param = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PADDING, data[KEY_PARAMETERS]); if (param != KMType.INVALID_VALUE) { - if (KMEnumArrayTag.cast(param).length() != 1) KMException.throwIt(KMError.INVALID_ARGUMENT); + if (KMEnumArrayTag.cast(param).length() != 1) { + KMException.throwIt(KMError.INVALID_ARGUMENT); + } param = KMEnumArrayTag.cast(param).get((short) 0); - if (!KMEnumArrayTag.cast(paddings).contains(param)) + if (!KMEnumArrayTag.cast(paddings).contains(param)) { KMException.throwIt(KMError.INCOMPATIBLE_PADDING_MODE); + } } switch (op.getAlgorithm()) { case KMType.RSA: - if (param == KMType.INVALID_VALUE) KMException.throwIt(KMError.UNSUPPORTED_PADDING_MODE); + if (param == KMType.INVALID_VALUE) { + KMException.throwIt(KMError.UNSUPPORTED_PADDING_MODE); + } if ((op.getPurpose() == KMType.SIGN || op.getPurpose() == KMType.VERIFY) && param != KMType.PADDING_NONE && param != KMType.RSA_PSS - && param != KMType.RSA_PKCS1_1_5_SIGN) + && param != KMType.RSA_PKCS1_1_5_SIGN) { KMException.throwIt(KMError.UNSUPPORTED_PADDING_MODE); + } if ((op.getPurpose() == KMType.ENCRYPT || op.getPurpose() == KMType.DECRYPT) && param != KMType.PADDING_NONE && param != KMType.RSA_OAEP - && param != KMType.RSA_PKCS1_1_5_ENCRYPT) + && param != KMType.RSA_PKCS1_1_5_ENCRYPT) { KMException.throwIt(KMError.UNSUPPORTED_PADDING_MODE); + } if (param == KMType.PADDING_NONE && op.getDigest() != KMType.DIGEST_NONE) { KMException.throwIt(KMError.INCOMPATIBLE_DIGEST); } @@ -2325,7 +2342,9 @@ private void authorizePadding(KMOperationState op) { break; case KMType.DES: case KMType.AES: - if (param == KMType.INVALID_VALUE) KMException.throwIt(KMError.UNSUPPORTED_PADDING_MODE); + if (param == KMType.INVALID_VALUE) { + KMException.throwIt(KMError.UNSUPPORTED_PADDING_MODE); + } op.setPadding((byte) param); break; default: @@ -2337,7 +2356,9 @@ private void authorizeBlockModeAndMacLength(KMOperationState op) { short param = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.BLOCK_MODE, data[KEY_PARAMETERS]); if (param != KMType.INVALID_VALUE) { - if (KMEnumArrayTag.cast(param).length() != 1) KMException.throwIt(KMError.INVALID_ARGUMENT); + if (KMEnumArrayTag.cast(param).length() != 1) { + KMException.throwIt(KMError.INVALID_ARGUMENT); + } param = KMEnumArrayTag.cast(param).get((short) 0); } if (KMType.AES == op.getAlgorithm() || KMType.DES == op.getAlgorithm()) { @@ -2349,7 +2370,19 @@ private void authorizeBlockModeAndMacLength(KMOperationState op) { KMIntegerTag.getShortValue(KMType.UINT_TAG, KMType.MAC_LENGTH, data[KEY_PARAMETERS]); switch (op.getAlgorithm()) { case KMType.AES: - if (param == KMType.INVALID_VALUE) KMException.throwIt(KMError.INVALID_ARGUMENT); + //Validate the block mode. + switch (param) { + case KMType.ECB: + case KMType.CBC: + case KMType.CTR: + case KMType.GCM: + break; + default: + KMException.throwIt(KMError.UNSUPPORTED_BLOCK_MODE); + } + if (param == KMType.INVALID_VALUE) { + KMException.throwIt(KMError.INVALID_ARGUMENT); + } if (param == KMType.GCM) { if (op.getPadding() != KMType.PADDING_NONE) { KMException.throwIt(KMError.INCOMPATIBLE_PADDING_MODE); @@ -2360,15 +2393,25 @@ private void authorizeBlockModeAndMacLength(KMOperationState op) { if (macLen % 8 != 0 || macLen > 128 || macLen - < KMIntegerTag.getShortValue( - KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, data[HW_PARAMETERS])) { + < KMIntegerTag.getShortValue( + KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, data[HW_PARAMETERS])) { KMException.throwIt(KMError.INVALID_MAC_LENGTH); } op.setMacLength(macLen); } break; case KMType.DES: - if (param == KMType.INVALID_VALUE) KMException.throwIt(KMError.INVALID_ARGUMENT); + //Validate the block mode. + switch (param) { + case KMType.ECB: + case KMType.CBC: + break; + default: + KMException.throwIt(KMError.UNSUPPORTED_BLOCK_MODE); + } + if (param == KMType.INVALID_VALUE) { + KMException.throwIt(KMError.INVALID_ARGUMENT); + } break; case KMType.HMAC: if (macLen == KMType.INVALID_VALUE) { @@ -2382,11 +2425,11 @@ private void authorizeBlockModeAndMacLength(KMOperationState op) { } if (macLen < KMIntegerTag.getShortValue( - KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, data[HW_PARAMETERS])) { + KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, data[HW_PARAMETERS])) { KMException.throwIt(KMError.INVALID_MAC_LENGTH); } else if (macLen > KMIntegerTag.getShortValue( - KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, data[HW_PARAMETERS])) { + KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, data[HW_PARAMETERS])) { KMException.throwIt(KMError.UNSUPPORTED_MAC_LENGTH); } op.setMacLength(macLen); @@ -2443,8 +2486,8 @@ private void authorizeAndBeginOperation(KMOperationState op, byte[] scratchPad) // For symmetric decryption iv is required if (op.getPurpose() == KMType.DECRYPT && (op.getBlockMode() == KMType.CBC - || op.getBlockMode() == KMType.GCM - || op.getBlockMode() == KMType.CTR)) { + || op.getBlockMode() == KMType.GCM + || op.getBlockMode() == KMType.CTR)) { KMException.throwIt(KMError.MISSING_NONCE); } else if (op.getBlockMode() == KMType.ECB) { // For ECB we create zero length nonce @@ -2484,18 +2527,7 @@ private void beginCipherOperation(KMOperationState op) { KMByteBlob.cast(data[PUB_KEY]).getStartOff(), KMByteBlob.cast(data[PUB_KEY]).length())); } else { - op.setOperation( - seProvider.initAsymmetricOperation( - (byte) op.getPurpose(), - op.getAlgorithm(), - op.getPadding(), - op.getDigest(), - null, - (short) 0, - (short) 0, - KMByteBlob.cast(data[PUB_KEY]).getBuffer(), - KMByteBlob.cast(data[PUB_KEY]).getStartOff(), - KMByteBlob.cast(data[PUB_KEY]).length())); + KMException.throwIt(KMError.UNSUPPORTED_PURPOSE); } } catch (CryptoException exp) { KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM); @@ -2522,10 +2554,11 @@ private void beginCipherOperation(KMOperationState op) { KMByteBlob.cast(data[IV]).length(), op.getMacLength())); } catch (CryptoException exception) { - if (exception.getReason() == CryptoException.ILLEGAL_VALUE) + if (exception.getReason() == CryptoException.ILLEGAL_VALUE) { KMException.throwIt(KMError.INVALID_ARGUMENT); - else if (exception.getReason() == CryptoException.NO_SUCH_ALGORITHM) + } else if (exception.getReason() == CryptoException.NO_SUCH_ALGORITHM) { KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM); + } } } } @@ -2548,18 +2581,7 @@ private void beginSignVerifyOperation(KMOperationState op) { KMByteBlob.cast(data[PUB_KEY]).getStartOff(), KMByteBlob.cast(data[PUB_KEY]).length())); } else { - op.setOperation( - seProvider.initAsymmetricOperation( - (byte) op.getPurpose(), - op.getAlgorithm(), - op.getPadding(), - op.getDigest(), - null, - (short) 0, - (short) 0, - KMByteBlob.cast(data[PUB_KEY]).getBuffer(), - KMByteBlob.cast(data[PUB_KEY]).getStartOff(), - KMByteBlob.cast(data[PUB_KEY]).length())); + KMException.throwIt(KMError.UNSUPPORTED_PURPOSE); } } catch (CryptoException exp) { KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM); @@ -2581,18 +2603,7 @@ private void beginSignVerifyOperation(KMOperationState op) { (short) 0, (short) 0)); } else { - op.setOperation( - seProvider.initAsymmetricOperation( - (byte) op.getPurpose(), - op.getAlgorithm(), - op.getPadding(), - op.getDigest(), - null, - (short) 0, - (short) 0, - KMByteBlob.cast(data[PUB_KEY]).getBuffer(), - KMByteBlob.cast(data[PUB_KEY]).getStartOff(), - KMByteBlob.cast(data[PUB_KEY]).length())); + KMException.throwIt(KMError.UNSUPPORTED_PURPOSE); } } catch (CryptoException exp) { // Javacard does not support NO digest based signing. @@ -2600,17 +2611,17 @@ private void beginSignVerifyOperation(KMOperationState op) { } break; case KMType.HMAC: - // 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(). + // 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( @@ -2646,7 +2657,9 @@ private void authorizeUserSecureIdAuthTimeout(KMOperationState op) { KMKeyParameters.findTag(KMType.UINT_TAG, KMType.AUTH_TIMEOUT, data[HW_PARAMETERS]); if (tmpVariables[0] != KMType.INVALID_VALUE) { // check if hw token is empty - mac should not be empty. - if (data[HW_TOKEN] == KMType.INVALID_VALUE) KMException.throwIt(KMError.INVALID_MAC_LENGTH); + if (data[HW_TOKEN] == KMType.INVALID_VALUE) { + KMException.throwIt(KMError.INVALID_MAC_LENGTH); + } authTime = KMIntegerTag.cast(tmpVariables[0]).getValue(); // authenticate user authenticateUser(); @@ -2785,7 +2798,7 @@ private void importKey(APDU apdu, byte[] scratchPad) { } //Check if the tags are supported. - if(KMKeyParameters.hasUnsupportedTags(data[KEY_PARAMETERS])) { + if (KMKeyParameters.hasUnsupportedTags(data[KEY_PARAMETERS])) { KMException.throwIt(KMError.UNSUPPORTED_TAG); } // Check algorithm and dispatch to appropriate handler. @@ -2847,7 +2860,7 @@ private void importECKeys(byte[] scratchPad) { // As per NIST.SP.800-186 page 9, secret for 256 curve should be between // 256-383 if (((256 <= (short) (KMByteBlob.cast(data[SECRET]).length() * 8)) - && (383 >= (short) (KMByteBlob.cast(data[SECRET]).length() * 8))) + && (383 >= (short) (KMByteBlob.cast(data[SECRET]).length() * 8))) ^ tmpVariables[2] == 256) { KMException.throwIt(KMError.IMPORT_PARAMETER_MISMATCH); } @@ -2867,7 +2880,7 @@ private void importECKeys(byte[] scratchPad) { // As per NIST.SP.800-186 page 9, secret length for 256 curve should be between // 256-383 if (((256 <= (short) (KMByteBlob.cast(data[SECRET]).length() * 8)) - && (383 >= (short) (KMByteBlob.cast(data[SECRET]).length() * 8))) + && (383 >= (short) (KMByteBlob.cast(data[SECRET]).length() * 8))) ^ tmpVariables[3] == KMType.P_256) { KMException.throwIt(KMError.IMPORT_PARAMETER_MISMATCH); } @@ -3193,9 +3206,9 @@ private void processSetBootParamsCmd(APDU apdu) { KMInteger.cast(tmpVariables[2]).length()); repository.setBootPatchLevel( - KMInteger.cast(tmpVariables[3]).getBuffer(), - KMInteger.cast(tmpVariables[3]).getStartOff(), - KMInteger.cast(tmpVariables[3]).length()); + KMInteger.cast(tmpVariables[3]).getBuffer(), + KMInteger.cast(tmpVariables[3]).getStartOff(), + KMInteger.cast(tmpVariables[3]).length()); repository.setVerifiedBootKey( KMByteBlob.cast(tmpVariables[4]).getBuffer(), @@ -3278,10 +3291,10 @@ private static void processGenerateKey(APDU apdu) { } } //Check if the tags are supported. - if(KMKeyParameters.hasUnsupportedTags(data[KEY_PARAMETERS])) { + if (KMKeyParameters.hasUnsupportedTags(data[KEY_PARAMETERS])) { KMException.throwIt(KMError.UNSUPPORTED_TAG); } - + // Check algorithm and dispatch to appropriate handler. switch (tmpVariables[3]) { case KMType.RSA: @@ -3526,7 +3539,7 @@ private void checkVersionAndPatchLevel(byte[] scratchPad) { if (tmpVariables[0] != KMType.INVALID_VALUE) { tmpVariables[1] = repository.getOsVersion(); tmpVariables[1] = - KMUtils.unsignedByteArrayCompare( + KMInteger.unsignedByteArrayCompare( KMInteger.cast(tmpVariables[1]).getBuffer(), KMInteger.cast(tmpVariables[1]).getStartOff(), scratchPad, @@ -3545,7 +3558,7 @@ private void checkVersionAndPatchLevel(byte[] scratchPad) { if (tmpVariables[0] != KMType.INVALID_VALUE) { tmpVariables[1] = repository.getOsPatch(); tmpVariables[1] = - KMUtils.unsignedByteArrayCompare( + KMInteger.unsignedByteArrayCompare( KMInteger.cast(tmpVariables[1]).getBuffer(), KMInteger.cast(tmpVariables[1]).getStartOff(), scratchPad, @@ -3584,6 +3597,9 @@ private static void createEncryptedKeyBlob(byte[] scratchPad) { makeKeyCharacteristics(scratchPad); // make root of trust blob data[ROT] = repository.readROT(); + if (data[ROT] == KMType.INVALID_VALUE) { + KMException.throwIt(KMError.UNKNOWN_ERROR); + } // make hidden key params list data[HIDDEN_PARAMETERS] = @@ -3606,50 +3622,57 @@ private static void createEncryptedKeyBlob(byte[] scratchPad) { } private static void parseEncryptedKeyBlob(byte[] scratchPad) { - tmpVariables[0] = KMByteBlob.cast(data[KEY_BLOB]).getStartOff(); - tmpVariables[1] = KMArray.instance((short) 5); - KMArray.cast(tmpVariables[1]).add(KMKeymasterApplet.KEY_BLOB_SECRET, KMByteBlob.exp()); - KMArray.cast(tmpVariables[1]).add(KMKeymasterApplet.KEY_BLOB_AUTH_TAG, KMByteBlob.exp()); - KMArray.cast(tmpVariables[1]).add(KMKeymasterApplet.KEY_BLOB_NONCE, KMByteBlob.exp()); - 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[ROT] = repository.readROT(); + if (data[ROT] == KMType.INVALID_VALUE) { + KMException.throwIt(KMError.UNKNOWN_ERROR); + } try { - data[KEY_BLOB] = - decoder.decodeArray( - tmpVariables[1], + tmpVariables[0] = KMByteBlob.cast(data[KEY_BLOB]).getStartOff(); + tmpVariables[1] = KMArray.instance((short) 5); + KMArray.cast(tmpVariables[1]).add(KMKeymasterApplet.KEY_BLOB_SECRET, + KMByteBlob.exp()); + KMArray.cast(tmpVariables[1]).add(KMKeymasterApplet.KEY_BLOB_AUTH_TAG, + KMByteBlob.exp()); + KMArray.cast(tmpVariables[1]).add(KMKeymasterApplet.KEY_BLOB_NONCE, + KMByteBlob.exp()); + 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()); - } catch (ISOException e) { - KMException.throwIt(KMError.INVALID_KEY_BLOB); - } - tmpVariables[0] = KMArray.cast(data[KEY_BLOB]).length(); - if (tmpVariables[0] < 4) { + tmpVariables[0] = KMArray.cast(data[KEY_BLOB]).length(); + if (tmpVariables[0] < 4) { + KMException.throwIt(KMError.INVALID_KEY_BLOB); + } + data[AUTH_TAG] = KMArray.cast(data[KEY_BLOB]).get(KEY_BLOB_AUTH_TAG); + + // initialize data + data[NONCE] = KMArray.cast(data[KEY_BLOB]).get(KEY_BLOB_NONCE); + data[SECRET] = KMArray.cast(data[KEY_BLOB]).get(KEY_BLOB_SECRET); + data[KEY_CHARACTERISTICS] = KMArray.cast(data[KEY_BLOB]).get( + KEY_BLOB_KEYCHAR); + data[PUB_KEY] = KMType.INVALID_VALUE; + if (tmpVariables[0] == 5) { + data[PUB_KEY] = KMArray.cast(data[KEY_BLOB]).get(KEY_BLOB_PUB_KEY); + } + data[HW_PARAMETERS] = KMKeyCharacteristics + .cast(data[KEY_CHARACTERISTICS]).getHardwareEnforced(); + data[SW_PARAMETERS] = KMKeyCharacteristics + .cast(data[KEY_CHARACTERISTICS]).getSoftwareEnforced(); + + data[HIDDEN_PARAMETERS] = KMKeyParameters.makeHidden(data[APP_ID], + data[APP_DATA], data[ROT], scratchPad); + // make auth data + makeAuthData(scratchPad); + // Decrypt Secret and verify auth tag + decryptSecret(scratchPad); + } catch (Exception e) { KMException.throwIt(KMError.INVALID_KEY_BLOB); } - data[AUTH_TAG] = KMArray.cast(data[KEY_BLOB]).get(KEY_BLOB_AUTH_TAG); - - // initialize data - data[NONCE] = KMArray.cast(data[KEY_BLOB]).get(KEY_BLOB_NONCE); - data[SECRET] = KMArray.cast(data[KEY_BLOB]).get(KEY_BLOB_SECRET); - data[KEY_CHARACTERISTICS] = KMArray.cast(data[KEY_BLOB]).get(KEY_BLOB_KEYCHAR); - data[PUB_KEY] = KMType.INVALID_VALUE; - if (tmpVariables[0] == 5) { - data[PUB_KEY] = KMArray.cast(data[KEY_BLOB]).get(KEY_BLOB_PUB_KEY); - } - data[HW_PARAMETERS] = - KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getHardwareEnforced(); - data[SW_PARAMETERS] = - KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getSoftwareEnforced(); - data[ROT] = repository.readROT(); - - data[HIDDEN_PARAMETERS] = - KMKeyParameters.makeHidden(data[APP_ID], data[APP_DATA], data[ROT], scratchPad); - // make auth data - makeAuthData(scratchPad); - // Decrypt Secret and verify auth tag - decryptSecret(scratchPad); } private static void decryptSecret(byte[] scratchPad) { @@ -3777,9 +3800,9 @@ private static short deriveKey(byte[] scratchPad) { 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])); + repository.getHeap(), + (short) (tmpVariables[1] + tmpVariables[2]), + (short) (DERIVE_KEY_INPUT_SIZE - tmpVariables[2])); } // KeyDerivation: // 1. Do HMAC Sign, with below input parameters. @@ -3790,12 +3813,12 @@ private static short deriveKey(byte[] scratchPad) { // Consume only first 16 bytes as derived key. // Hmac sign. tmpVariables[3] = seProvider.hmacKDF( - seProvider.getMasterKey(), - repository.getHeap(), - tmpVariables[1], - DERIVE_KEY_INPUT_SIZE, - scratchPad, - (short) 0); + seProvider.getMasterKey(), + repository.getHeap(), + tmpVariables[1], + DERIVE_KEY_INPUT_SIZE, + scratchPad, + (short) 0); if (tmpVariables[3] < 16) { KMException.throwIt(KMError.UNKNOWN_ERROR); } @@ -3840,8 +3863,9 @@ 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) + if (tmp > 255) { carry = 1; // max unsigned byte value is 255 + } buf[(short) (result + index)] = (byte) (tmp & (byte) 0xFF); index--; } diff --git a/Applet/src/com/android/javacard/keymaster/KMMasterKey.java b/Applet/src/com/android/javacard/keymaster/KMMasterKey.java index 0ceb6291..7a88778e 100644 --- a/Applet/src/com/android/javacard/keymaster/KMMasterKey.java +++ b/Applet/src/com/android/javacard/keymaster/KMMasterKey.java @@ -16,10 +16,9 @@ package com.android.javacard.keymaster; /** - * KMMasterKey is a marker interface and the SE Provider has to implement - * 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. + * KMMasterKey is a marker interface and the SE Provider has to implement 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/KMOperation.java b/Applet/src/com/android/javacard/keymaster/KMOperation.java index 8db3312b..3132e4b3 100644 --- a/Applet/src/com/android/javacard/keymaster/KMOperation.java +++ b/Applet/src/com/android/javacard/keymaster/KMOperation.java @@ -21,23 +21,25 @@ * returned back to KMSEProvider for the reuse when the operation is finished. */ public interface KMOperation { + // Used for cipher operations short update(byte[] inputDataBuf, short inputDataStart, short inputDataLength, - byte[] outputDataBuf, short outputDataStart); + byte[] outputDataBuf, short outputDataStart); + // Used for signature operations short update(byte[] inputDataBuf, short inputDataStart, short inputDataLength); // Used for finishing cipher operations. short finish(byte[] inputDataBuf, short inputDataStart, short inputDataLength, - byte[] outputDataBuf, short outputDataStart); + byte[] outputDataBuf, short outputDataStart); // Used for finishing signing operations. short sign(byte[] inputDataBuf, short inputDataStart, short inputDataLength, - byte[] signBuf, short signStart); + byte[] signBuf, short signStart); // Used for finishing verifying operations. boolean verify(byte[] inputDataBuf, short inputDataStart, short inputDataLength, - byte[] signBuf, short signStart, short signLength); + byte[] signBuf, short signStart, short signLength); // Used for aborting the ongoing operations. void abort(); diff --git a/Applet/src/com/android/javacard/keymaster/KMOperationState.java b/Applet/src/com/android/javacard/keymaster/KMOperationState.java index 6ea96941..f1c65ea4 100644 --- a/Applet/src/com/android/javacard/keymaster/KMOperationState.java +++ b/Applet/src/com/android/javacard/keymaster/KMOperationState.java @@ -20,10 +20,10 @@ import javacard.framework.Util; /** - * KMOperationState is the container of an active operation started by beginOperation function. - * This operation state is persisted by the applet in non volatile memory. However, this state is not - * retained if applet is upgraded. There will be four operation state records maintained i.e. only four - * active operations are supported at any given time. + * KMOperationState is the container of an active operation started by beginOperation function. This + * operation state is persisted by the applet in non volatile memory. However, this state is not + * retained if applet is upgraded. There will be four operation state records maintained i.e. only + * four active operations are supported at any given time. */ public class KMOperationState { @@ -64,7 +64,9 @@ private KMOperationState() { } private static KMOperationState proto() { - if (prototype == null) prototype = new KMOperationState(); + if (prototype == null) { + prototype = new KMOperationState(); + } return prototype; } @@ -88,7 +90,9 @@ public static KMOperationState read(byte[] oprHandle, short off, Object[] slot) } public void persist() { - if (!dFlag) return; + if (!dFlag) { + return; + } KMRepository.instance().persistOperation(data, Util.getShort(data, OP_HANDLE), op); dFlag = false; } @@ -108,13 +112,14 @@ public void reset() { Util.arrayFillNonAtomic( data, (short) 0, (short) data.length, (byte) 0); } - private void dataUpdated(){ + + private void dataUpdated() { dFlag = true; } public void release() { Object[] ops = ((Object[]) slot[REFS]); - ((KMOperation)ops[OPERATION]).abort(); + ((KMOperation) ops[OPERATION]).abort(); JCSystem.beginTransaction(); Util.arrayFillNonAtomic( (byte[]) slot[0], (short) 0, (short) ((byte[]) slot[0]).length, (byte) 0); @@ -168,20 +173,29 @@ public void setAuthTime(byte[] timeBuf, short start) { } public void setOneTimeAuthReqd(boolean flag) { - if (flag) data[FLAGS] = (byte) (data[FLAGS] | SECURE_USER_ID_REQD); - else data[FLAGS] = (byte) (data[FLAGS] & (~SECURE_USER_ID_REQD)); + if (flag) { + data[FLAGS] = (byte) (data[FLAGS] | SECURE_USER_ID_REQD); + } else { + data[FLAGS] = (byte) (data[FLAGS] & (~SECURE_USER_ID_REQD)); + } dataUpdated(); } public void setAuthTimeoutValidated(boolean flag) { - if (flag) data[FLAGS] = (byte) (data[FLAGS] | AUTH_TIMEOUT_VALIDATED); - else data[FLAGS] = (byte) (data[FLAGS] & (~AUTH_TIMEOUT_VALIDATED)); + if (flag) { + data[FLAGS] = (byte) (data[FLAGS] | AUTH_TIMEOUT_VALIDATED); + } else { + data[FLAGS] = (byte) (data[FLAGS] & (~AUTH_TIMEOUT_VALIDATED)); + } dataUpdated(); } public void setAuthPerOperationReqd(boolean flag) { - if (flag) data[FLAGS] = (byte) (data[FLAGS] | AUTH_PER_OP_REQD); - else data[FLAGS] = (byte) (data[FLAGS] & (~AUTH_PER_OP_REQD)); + if (flag) { + data[FLAGS] = (byte) (data[FLAGS] | AUTH_PER_OP_REQD); + } else { + data[FLAGS] = (byte) (data[FLAGS] & (~AUTH_PER_OP_REQD)); + } dataUpdated(); } diff --git a/Applet/src/com/android/javacard/keymaster/KMPreSharedKey.java b/Applet/src/com/android/javacard/keymaster/KMPreSharedKey.java index 71dfcae6..273aeb4a 100644 --- a/Applet/src/com/android/javacard/keymaster/KMPreSharedKey.java +++ b/Applet/src/com/android/javacard/keymaster/KMPreSharedKey.java @@ -16,10 +16,9 @@ package com.android.javacard.keymaster; /** - * KMPreSharedKey is a marker interface and the SE Provider has to implement - * 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. + * KMPreSharedKey is a marker interface and the SE Provider has to implement 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 { diff --git a/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/src/com/android/javacard/keymaster/KMRepository.java index ee7cc6a8..204fe312 100644 --- a/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/Applet/src/com/android/javacard/keymaster/KMRepository.java @@ -24,10 +24,11 @@ import javacard.framework.Util; /** - * 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. + * 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 implements KMUpgradable { + // Data table configuration public static final short DATA_INDEX_SIZE = 22; public static final short DATA_INDEX_ENTRY_SIZE = 4; @@ -39,7 +40,8 @@ public class KMRepository implements KMUpgradable { 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; + private static final short OPERATION_HANDLE_ENTRY_SIZE = + OPERATION_HANDLE_SIZE + OPERATION_HANDLE_STATUS_SIZE; // Data table offsets public static final byte COMPUTED_HMAC_KEY = 8; @@ -106,10 +108,10 @@ public KMRepository(boolean isUpgrading) { //First byte in the operation handle buffer denotes whether the operation is //reserved or unreserved. byte index = 0; - while(index < MAX_OPS){ + while (index < MAX_OPS) { operationStateTable[index] = new Object[]{new byte[OPERATION_HANDLE_ENTRY_SIZE], - new Object[] {new byte[KMOperationState.MAX_DATA], - new Object[KMOperationState.MAX_REFS]}}; + new Object[]{new byte[KMOperationState.MAX_DATA], + new Object[KMOperationState.MAX_REFS]}}; index++; } //Initialize the device locked status @@ -134,7 +136,8 @@ public KMOperationState findOperation(byte[] buf, short off, short len) { 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]); + .read(opId, OPERATION_HANDLE_OFFSET, + (Object[]) ((Object[]) operationStateTable[index])[1]); } index++; } @@ -146,25 +149,26 @@ public KMOperationState findOperation(byte[] buf, short off, short len) { 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()); + 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()); + KMByteBlob.cast(buf).getBuffer(), + KMByteBlob.cast(buf).getStartOff(), + KMByteBlob.cast(buf).length()); } /* opHandle is a KMInteger */ - public KMOperationState reserveOperation(short opHandle){ + public KMOperationState reserveOperation(short opHandle) { short index = 0; byte[] opId; - while(index < MAX_OPS){ - opId = (byte[])((Object[])operationStateTable[index])[0]; + while (index < MAX_OPS) { + opId = (byte[]) ((Object[]) operationStateTable[index])[0]; /* Check for unreserved operation state */ if (opId[OPERATION_HANDLE_STATUS_OFFSET] == 0) { - return KMOperationState.instance(opHandle, (Object[])((Object[])operationStateTable[index])[1]); + return KMOperationState + .instance(opHandle, (Object[]) ((Object[]) operationStateTable[index])[1]); } index++; } @@ -172,28 +176,28 @@ public KMOperationState reserveOperation(short opHandle){ } public void persistOperation(byte[] data, short opHandle, KMOperation op) { - short index = 0; + 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()); + 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 ((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()))) { + && (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); + (short) ((byte[]) slot[0]).length); Object[] ops = ((Object[]) slot[1]); ops[0] = op; JCSystem.commitTransaction(); @@ -204,11 +208,11 @@ public void persistOperation(byte[] data, short opHandle, KMOperation op) { index = 0; //Persist a new operation. - while(index < MAX_OPS){ - opId = (byte[])((Object[])operationStateTable[index])[0]; - if(0 == opId[OPERATION_HANDLE_STATUS_OFFSET]){ - Object[] slot = (Object[])((Object[])operationStateTable[index])[1]; - JCSystem.beginTransaction(); + while (index < MAX_OPS) { + opId = (byte[]) ((Object[]) operationStateTable[index])[0]; + 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(), @@ -216,11 +220,12 @@ public void persistOperation(byte[] data, short opHandle, KMOperation op) { opId, OPERATION_HANDLE_OFFSET, OPERATION_HANDLE_SIZE); - Util.arrayCopy(data, (short) 0, (byte[]) slot[0], (short) 0, (short) ((byte[]) slot[0]).length); + 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(); - break; + break; } index++; } @@ -231,18 +236,18 @@ public void releaseOperation(KMOperationState op) { byte[] var; short buf = KMByteBlob.instance(OPERATION_HANDLE_SIZE); getOperationHandle( - op.getHandle(), - KMByteBlob.cast(buf).getBuffer(), - KMByteBlob.cast(buf).getStartOff(), - KMByteBlob.cast(buf).length()); + 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()))) { + (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; @@ -252,13 +257,17 @@ public void releaseOperation(KMOperationState op) { } 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); + if (len != COMPUTED_HMAC_KEY_SIZE) { + KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + } + writeDataEntry(COMPUTED_HMAC_KEY, key, start, 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); + if (len != HMAC_SEED_NONCE_SIZE) { + KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + } + writeDataEntry(HMAC_NONCE, nonce, offset, len); } public void clearHmacNonce() { @@ -274,7 +283,8 @@ public void onUninstall() { } - public void onProcess() {} + public void onProcess() { + } public void clean() { Util.arrayFillNonAtomic(heap, (short) 0, heapIndex, (byte) 0); @@ -282,7 +292,8 @@ public void clean() { reclaimIndex = HEAP_SIZE; } - public void onDeselect() {} + public void onDeselect() { + } public void onSelect() { // If write through caching is implemented then this method will restore the data into cache @@ -292,7 +303,7 @@ public void onSelect() { // reclaimMemory function immediately after the use. public short allocReclaimableMemory(short length) { if ((((short) (reclaimIndex - length)) <= heapIndex) - || (length >= HEAP_SIZE / 2)) { + || (length >= HEAP_SIZE / 2)) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } reclaimIndex -= length; @@ -318,7 +329,7 @@ public short allocAvailableMemory() { public short alloc(short length) { if ((((short) (heapIndex + length)) > heap.length) || - (((short) (heapIndex + length)) > reclaimIndex)) { + (((short) (heapIndex + length)) > reclaimIndex)) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } heapIndex += length; @@ -334,7 +345,7 @@ private short dataAlloc(short length) { } - private void newDataTable(boolean isUpgrading){ + private void newDataTable(boolean isUpgrading) { if (!isUpgrading) { if (dataTable == null) { dataTable = new byte[DATA_MEM_SIZE]; @@ -343,26 +354,27 @@ private void newDataTable(boolean isUpgrading){ } } - public void restoreData(short blob){ + public void restoreData(short blob) { JCSystem.beginTransaction(); Util.arrayCopy( - KMByteBlob.cast(blob).getBuffer(),KMByteBlob.cast(blob).getStartOff(),dataTable,(short)0, - KMByteBlob.cast(blob).length() + KMByteBlob.cast(blob).getBuffer(), KMByteBlob.cast(blob).getStartOff(), dataTable, + (short) 0, + KMByteBlob.cast(blob).length() ); JCSystem.commitTransaction(); } - public byte[] getDataTable(){ + public byte[] getDataTable() { return dataTable; } - private void clearDataEntry(short id){ + private void clearDataEntry(short id) { JCSystem.beginTransaction(); - id = (short)(id * DATA_INDEX_ENTRY_SIZE); - short dataLen = Util.getShort(dataTable,(short)(id+DATA_INDEX_ENTRY_LENGTH)); + id = (short) (id * DATA_INDEX_ENTRY_SIZE); + short dataLen = Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_LENGTH)); if (dataLen != 0) { - short dataPtr = Util.getShort(dataTable,(short)(id+DATA_INDEX_ENTRY_OFFSET)); - Util.arrayFillNonAtomic(dataTable, dataPtr,dataLen,(byte)0); + short dataPtr = Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_OFFSET)); + Util.arrayFillNonAtomic(dataTable, dataPtr, dataLen, (byte) 0); } JCSystem.commitTransaction(); } @@ -370,24 +382,26 @@ private void clearDataEntry(short id){ private void writeDataEntry(short id, byte[] buf, short offset, short len) { JCSystem.beginTransaction(); short dataPtr; - id = (short)(id * DATA_INDEX_ENTRY_SIZE); - short dataLen = Util.getShort(dataTable,(short)(id+DATA_INDEX_ENTRY_LENGTH)); + id = (short) (id * DATA_INDEX_ENTRY_SIZE); + short dataLen = Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_LENGTH)); if (dataLen == 0) { dataPtr = dataAlloc(len); - Util.setShort(dataTable,(short)(id+DATA_INDEX_ENTRY_OFFSET),dataPtr); - Util.setShort(dataTable,(short)(id+DATA_INDEX_ENTRY_LENGTH),len); - Util.arrayCopyNonAtomic(buf, offset,dataTable,dataPtr, len); + Util.setShort(dataTable, (short) (id + DATA_INDEX_ENTRY_OFFSET), dataPtr); + Util.setShort(dataTable, (short) (id + DATA_INDEX_ENTRY_LENGTH), len); + Util.arrayCopyNonAtomic(buf, offset, dataTable, dataPtr, len); } else { - if(len != dataLen) KMException.throwIt(KMError.UNKNOWN_ERROR); - dataPtr = Util.getShort(dataTable,(short)(id+DATA_INDEX_ENTRY_OFFSET)); - Util.arrayCopyNonAtomic(buf, offset,dataTable,dataPtr, len); + if (len != dataLen) { + KMException.throwIt(KMError.UNKNOWN_ERROR); + } + dataPtr = Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_OFFSET)); + Util.arrayCopyNonAtomic(buf, offset, dataTable, dataPtr, len); } JCSystem.commitTransaction(); } - private short readDataEntry(short id, byte[] buf, short offset){ - id = (short)(id * DATA_INDEX_ENTRY_SIZE); - short len = Util.getShort(dataTable,(short)(id+DATA_INDEX_ENTRY_LENGTH)); + private short readDataEntry(short id, byte[] buf, short offset) { + id = (short) (id * DATA_INDEX_ENTRY_SIZE); + short len = Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_LENGTH)); if (len != 0) { Util.arrayCopyNonAtomic( dataTable, @@ -399,9 +413,9 @@ private short readDataEntry(short id, byte[] buf, short offset){ return len; } - private short dataLength(short id){ - id = (short)(id * DATA_INDEX_ENTRY_SIZE); - return Util.getShort(dataTable,(short)(id+DATA_INDEX_ENTRY_LENGTH)); + private short dataLength(short id) { + id = (short) (id * DATA_INDEX_ENTRY_SIZE); + return Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_LENGTH)); } public byte[] getHeap() { @@ -416,15 +430,15 @@ public short getComputedHmacKey() { return readData(COMPUTED_HMAC_KEY); } - public void persistAttId(byte id, byte[] buf, short start, short len){ - writeDataEntry(id, buf,start,len); + public void persistAttId(byte id, byte[] buf, short start, short len) { + writeDataEntry(id, buf, start, len); } - public short getAttId(byte id){ + public short getAttId(byte id) { return readData(id); } - public void deleteAttIds(){ + public void deleteAttIds() { clearDataEntry(ATT_ID_BRAND); clearDataEntry(ATT_ID_MEID); clearDataEntry(ATT_ID_DEVICE); @@ -439,15 +453,17 @@ public short getIssuer() { return readData(CERT_ISSUER); } - public short readData(short id){ + public short readData(short id) { short blob = KMByteBlob.instance(dataLength(id)); - if(readDataEntry(id,KMByteBlob.cast(blob).getBuffer(),KMByteBlob.cast(blob).getStartOff())== 0){ + if (readDataEntry(id, KMByteBlob.cast(blob).getBuffer(), KMByteBlob.cast(blob).getStartOff()) + == 0) { return 0; } return blob; } + public void setIssuer(byte[] buf, short start, short len) { - writeDataEntry(CERT_ISSUER,buf,start,len); + writeDataEntry(CERT_ISSUER, buf, start, len); } @@ -456,189 +472,215 @@ public short getCertExpiryTime() { } public void setCertExpiryTime(byte[] buf, short start, short len) { - writeDataEntry(CERT_EXPIRY_TIME, buf,start,len); + writeDataEntry(CERT_EXPIRY_TIME, buf, start, len); } - private static final byte[] zero = {0,0,0,0,0,0,0,0}; + private static final byte[] zero = {0, 0, 0, 0, 0, 0, 0, 0}; - public short getOsVersion(){ + public short getOsVersion() { short blob = readData(BOOT_OS_VERSION); if (blob != 0) { return KMInteger.uint_32( KMByteBlob.cast(blob).getBuffer(), KMByteBlob.cast(blob).getStartOff()); - }else{ - return KMInteger.uint_32(zero,(short)0); + } else { + return KMInteger.uint_32(zero, (short) 0); } } - public short getVendorPatchLevel(){ + 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); + } else { + return KMInteger.uint_32(zero, (short) 0); } } - public short getBootPatchLevel(){ + 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); + } else { + return KMInteger.uint_32(zero, (short) 0); } } - public short getOsPatch(){ + public short getOsPatch() { short blob = readData(BOOT_OS_PATCH); if (blob != 0) { return KMInteger.uint_32( KMByteBlob.cast(blob).getBuffer(), KMByteBlob.cast(blob).getStartOff()); - }else{ - return KMInteger.uint_32(zero,(short)0); + } else { + return KMInteger.uint_32(zero, (short) 0); } } public short readROT() { + short totalLength = 0; 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 == 0) { + return KMType.INVALID_VALUE; } - if((length += readDataEntry( - BOOT_VERIFIED_BOOT_HASH, - KMByteBlob.cast(blob).getBuffer(), - (short) (KMByteBlob.cast(blob).getStartOff() + length))) == 0){ - return 0; + totalLength += length; + if ((length = dataLength(BOOT_VERIFIED_BOOT_HASH)) == 0) { + return KMType.INVALID_VALUE; } - if((length += readDataEntry( - BOOT_VERIFIED_BOOT_STATE, - KMByteBlob.cast(blob).getBuffer(), - (short) (KMByteBlob.cast(blob).getStartOff() + length))) == 0){ - return 0; + totalLength += length; + if ((length = dataLength(BOOT_VERIFIED_BOOT_STATE)) == 0) { + return KMType.INVALID_VALUE; } - if((length += readDataEntry( - BOOT_DEVICE_LOCKED_STATUS, - KMByteBlob.cast(blob).getBuffer(), - (short) (KMByteBlob.cast(blob).getStartOff() + length))) == 0){ - return 0; + totalLength += length; + if ((length = dataLength(BOOT_DEVICE_LOCKED_STATUS)) == 0) { + return KMType.INVALID_VALUE; } + totalLength += length; + + short blob = KMByteBlob.instance(totalLength); + length = readDataEntry(BOOT_VERIFIED_BOOT_KEY, KMByteBlob.cast(blob) + .getBuffer(), KMByteBlob.cast(blob).getStartOff()); + + length += readDataEntry(BOOT_VERIFIED_BOOT_HASH, KMByteBlob.cast(blob) + .getBuffer(), + (short) (KMByteBlob.cast(blob).getStartOff() + length)); + + length += readDataEntry(BOOT_VERIFIED_BOOT_STATE, KMByteBlob.cast(blob) + .getBuffer(), + (short) (KMByteBlob.cast(blob).getStartOff() + length)); + + readDataEntry(BOOT_DEVICE_LOCKED_STATUS, KMByteBlob.cast(blob) + .getBuffer(), + (short) (KMByteBlob.cast(blob).getStartOff() + length)); return blob; } - public short getVerifiedBootKey(){ + public short getVerifiedBootKey() { return readData(BOOT_VERIFIED_BOOT_KEY); } - public short getVerifiedBootHash(){ + public short getVerifiedBootHash() { return readData(BOOT_VERIFIED_BOOT_HASH); } public boolean getBootLoaderLock() { short blob = readData(BOOT_DEVICE_LOCKED_STATUS); - return (byte)((getHeap())[KMByteBlob.cast(blob).getStartOff()] & 0xFE) != 0; + return (byte) ((getHeap())[KMByteBlob.cast(blob).getStartOff()] & 0xFE) != 0; } - public byte getBootState(){ + public byte getBootState() { short blob = readData(BOOT_VERIFIED_BOOT_STATE); return (getHeap())[KMByteBlob.cast(blob).getStartOff()]; } - public boolean getDeviceLock(){ + public boolean getDeviceLock() { short blob = readData(DEVICE_LOCKED); - return (byte)((getHeap())[KMByteBlob.cast(blob).getStartOff()] & 0xFE) != 0; + return (byte) ((getHeap())[KMByteBlob.cast(blob).getStartOff()] & 0xFE) != 0; } - public boolean getDeviceLockPasswordOnly(){ + public boolean getDeviceLockPasswordOnly() { short blob = readData(DEVICE_LOCKED); - return (byte)((getHeap())[KMByteBlob.cast(blob).getStartOff()] & 0xFD) != 0; + return (byte) ((getHeap())[KMByteBlob.cast(blob).getStartOff()] & 0xFD) != 0; } - public short getDeviceTimeStamp(){ + public short getDeviceTimeStamp() { short blob = readData(DEVICE_LOCKED_TIME); - if(blob != 0){ - return KMInteger.uint_64(KMByteBlob.cast(blob).getBuffer(), - KMByteBlob.cast(blob).getStartOff()); - }else{ - return KMInteger.uint_64(zero,(short)0); + if (blob != 0) { + return KMInteger.uint_64(KMByteBlob.cast(blob).getBuffer(), + KMByteBlob.cast(blob).getStartOff()); + } else { + return KMInteger.uint_64(zero, (short) 0); } } - public void setOsVersion(byte[] buf, short start, short len){ - if(len != OS_VERSION_SIZE) KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - writeDataEntry(BOOT_OS_VERSION,buf,start,len); + public void setOsVersion(byte[] buf, short start, short len) { + if (len != OS_VERSION_SIZE) { + KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + } + writeDataEntry(BOOT_OS_VERSION, buf, start, len); } public void setVendorPatchLevel(byte[] buf, short start, short len) { - if (len != VENDOR_PATCH_SIZE) + 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) + if (len != BOOT_PATCH_SIZE) { KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + } writeDataEntry(BOOT_PATCH_LEVEL, buf, start, len); } 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); + 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){ + 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); + 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){ + 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(DEVICE_LOCKED,getHeap(),start,DEVICE_LOCK_FLAG_SIZE); + if (flag) { + (getHeap())[start] = (byte) ((getHeap())[start] | 0x02); + } else { + (getHeap())[start] = (byte) ((getHeap())[start] & 0xFD); + } + 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(DEVICE_LOCKED_TIME, buf, start,len); + public void setDeviceLockTimestamp(byte[] buf, short start, short len) { + if (len != DEVICE_LOCK_TS_SIZE) { + KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + } + writeDataEntry(DEVICE_LOCKED_TIME, buf, start, len); } - public void clearDeviceLockTimeStamp(){ + public void clearDeviceLockTimeStamp() { clearDataEntry(DEVICE_LOCKED_TIME); } - public void setOsPatch(byte[] buf, short start, short len){ - if(len != OS_PATCH_SIZE) KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - writeDataEntry(BOOT_OS_PATCH,buf,start,len); + public void setOsPatch(byte[] buf, short start, short len) { + if (len != OS_PATCH_SIZE) { + KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + } + writeDataEntry(BOOT_OS_PATCH, buf, start, len); } - public void setVerifiedBootKey(byte[] buf, short start, short len){ - if(len > BOOT_KEY_MAX_SIZE) KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - writeDataEntry(BOOT_VERIFIED_BOOT_KEY,buf,start,len); + public void setVerifiedBootKey(byte[] buf, short start, short len) { + if (len > BOOT_KEY_MAX_SIZE) { + KMException.throwIt(KMError.INVALID_INPUT_LENGTH); + } + 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); + 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); } - public void setBootState(byte state){ + public void setBootState(byte state) { short start = alloc(BOOT_STATE_SIZE); (getHeap())[start] = state; - writeDataEntry(BOOT_VERIFIED_BOOT_STATE,getHeap(),start,BOOT_STATE_SIZE); + writeDataEntry(BOOT_VERIFIED_BOOT_STATE, getHeap(), start, BOOT_STATE_SIZE); } @Override diff --git a/Applet/src/com/android/javacard/keymaster/KMSEProvider.java b/Applet/src/com/android/javacard/keymaster/KMSEProvider.java index a057eb9e..65ae8fb3 100644 --- a/Applet/src/com/android/javacard/keymaster/KMSEProvider.java +++ b/Applet/src/com/android/javacard/keymaster/KMSEProvider.java @@ -24,12 +24,14 @@ * can be only one provider in the applet package. */ 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. * * @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 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 startOff is the start offset. * @return length of the data in the buf. This should match the keysize (in bytes). @@ -43,15 +45,15 @@ public interface KMSEProvider extends KMUpgradable { * * @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 - * key in case of EC. + * key in case of EC. * @param privKeyStart is the start offset. * @param privKeyMaxLength is the maximum 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 - * EC. + * EC. * @param pubModStart is the start of offset. * @param pubModMaxLength is the maximum length of this public key buffer. * @param lengths is the actual length of the key pair - lengths[0] should be private key and - * lengths[1] should be public key. + * lengths[1] should be public key. */ void createAsymmetricKey( byte alg, @@ -64,11 +66,12 @@ void createAsymmetricKey( short[] lengths); /** - * Verify that the imported key is valid. If the algorithm and/or keysize are not supported then it - * should throw a CryptoException. + * 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 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 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). @@ -83,12 +86,12 @@ void createAsymmetricKey( * CryptoException. * * @param alg will be KMType.RSA or KMType.EC. - * @param privKeyBuf is the buffer that contains the private key exponent in case of RSA or private - * key in case of EC. + * @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 that contains the modulus in case of RSA or public key in case of - * EC. + * @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. * @return true if the key pair is supported and valid. @@ -132,8 +135,8 @@ boolean importAsymmetricKey( void getTrueRandomNumber(byte[] num, short offset, short length); /** - * 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 + * 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. @@ -175,8 +178,8 @@ short aesGCMEncrypt( short authTagLen); /** - * This is a oneshot operation that performs decryption operation using AES GCM algorithm. It throws - * CryptoException if algorithm is not supported. + * 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. @@ -216,7 +219,7 @@ boolean aesGCMDecrypt( short authTagStart, short authTagLen); - /** + /** * This is a oneshot operation that performs key derivation function using cmac kdf (CKDF) as * defined in android keymaster hal definition. * @@ -266,8 +269,8 @@ short hmacSign( 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. + * 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. @@ -278,12 +281,12 @@ short hmacSign( * @return length of the signature buffer in bytes. */ short hmacKDF( - KMMasterKey masterkey, - byte[] data, - short dataStart, - short dataLength, - byte[] signature, - short signatureStart); + KMMasterKey masterkey, + byte[] data, + short dataStart, + short dataLength, + byte[] signature, + short signatureStart); /** * This is a oneshot operation that verifies the signature using hmac algorithm. @@ -353,12 +356,12 @@ short rsaDecipherOAEP256( * @return length of the decrypted data. */ short ecSign256( - KMAttestationKey ecPrivKey, - byte[] inputDataBuf, - short inputDataStart, - short inputDataLength, - byte[] outputDataBuf, - short outputDataStart); + KMAttestationKey ecPrivKey, + byte[] inputDataBuf, + short inputDataStart, + short inputDataLength, + byte[] outputDataBuf, + short outputDataStart); /** * This creates a persistent operation for signing, verify, encryption and decryption using HMAC, @@ -367,19 +370,19 @@ short ecSign256( * 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 + * KMType.SIGN and KMType.VERIFY for HMAC algorithm * @param alg is KMType.HMAC, KMType.AES or KMType.DES. * @param digest is KMType.SHA2_256 in case of HMAC else it will be KMType.DIGEST_NONE. * @param padding is KMType.PADDING_NONE or KMType.PKCS7 (in case of AES and DES). * @param blockMode is KMType.CTR, KMType.GCM. KMType.CBC or KMType.ECB for AES or DES else it is - * 0. + * 0. * @param keyBuf is aes, des or hmac key buffer. * @param keyStart is the start of the key buffer. * @param keyLength is the length of the key buffer. * @param ivBuf is the iv buffer (in case on AES and DES algorithm without ECB mode) * @param ivStart is the start of the iv buffer. * @param ivLength is the length of the iv buffer. It will be zero in case of HMAC and AES/DES - * with ECB mode. + * with ECB mode. * @param macLength is the mac length in case of signing operation for hmac algorithm. * @return KMOperation instance. */ @@ -401,14 +404,14 @@ 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. It throws CryptoException + * 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. + * KMType.VERIFY for RSA and EC algorithms. * @param alg is KMType.RSA or KMType.EC algorithms. * @param padding is KMType.PADDING_NONE or KMType.RSA_OAEP, KMType.RSA_PKCS1_1_5_ENCRYPT, - * KMType.RSA_PKCS1_1_5_SIGN or KMType.RSA_PSS. + * KMType.RSA_PKCS1_1_5_SIGN or KMType.RSA_PSS. * @param digest is KMType.DIGEST_NONE or KMType.SHA2_256. * @param privKeyBuf is the private key in case of EC or private key exponent is case of RSA. * @param privKeyStart is the start of the private key. @@ -436,14 +439,13 @@ KMOperation initAsymmetricOperation( * The attestation certificate implementation will comply keymaster hal specifications. * * @param rsaCert if true indicates that certificate will attest a rsa public key else if false it - * is for ec public key. + * is for ec public key. * @return An empty instance of KMAttestationCert implementation. */ KMAttestationCert getAttestationCert(boolean rsaCert); /** - * This operation persists the certificate chain in the persistent memory - * in multiple requests. + * This operation persists the certificate chain in the persistent memory in multiple requests. * * @param buf buffer containing certificate chain. * @param offset is the start of the buffer. @@ -488,7 +490,9 @@ KMOperation initAsymmetricOperation( boolean isDeviceRebooted(); /** - * This function is supposed to be used to reset the device booted stated after set boot param is handled + * 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 clearDeviceBooted(boolean resetBootFlag); @@ -501,9 +505,9 @@ KMOperation initAsymmetricOperation( 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. + * 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. @@ -511,10 +515,9 @@ KMOperation initAsymmetricOperation( 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. + * 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. @@ -524,10 +527,9 @@ KMOperation initAsymmetricOperation( 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. + * 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. diff --git a/Applet/src/com/android/javacard/keymaster/KMTag.java b/Applet/src/com/android/javacard/keymaster/KMTag.java index 6cc251a6..fa9bb38e 100644 --- a/Applet/src/com/android/javacard/keymaster/KMTag.java +++ b/Applet/src/com/android/javacard/keymaster/KMTag.java @@ -19,14 +19,21 @@ import javacard.framework.Util; /** - * This class represents a tag as defined by keymaster hal specifications. It is composed of key value pair. - * The key consists of short tag type e.g. KMType.ENUM and short tag key e.g. KMType.ALGORITHM. The key is encoded as - * uint CBOR type with 4 bytes. This is followed by value which can be any CBOR type based on key. - * struct{byte tag=KMType.TAG_TYPE, short length, value) where value is subtype of KMTag i.e. - * struct{short tagType=one of tag types declared in KMType , short tagKey=one of the tag keys declared in KMType, - * value} where value is one of the sub-types of KMType. + * This class represents a tag as defined by keymaster hal specifications. It is composed of key + * value pair. The key consists of short tag type e.g. KMType.ENUM and short tag key e.g. + * KMType.ALGORITHM. The key is encoded as uint CBOR type with 4 bytes. This is followed by value + * which can be any CBOR type based on key. struct{byte tag=KMType.TAG_TYPE, short length, value) + * where value is subtype of KMTag i.e. struct{short tagType=one of tag types declared in KMType , + * short tagKey=one of the tag keys declared in KMType, value} where value is one of the sub-types + * of KMType. */ public class KMTag extends KMType { - public static short getTagType(short ptr){return Util.getShort(heap, (short)(ptr+TLV_HEADER_SIZE));} - public static short getKey(short ptr){return Util.getShort(heap, (short)(ptr+TLV_HEADER_SIZE+2));} + + public static short getTagType(short ptr) { + return Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE)); + } + + public static short getKey(short ptr) { + return Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE + 2)); + } } diff --git a/Applet/src/com/android/javacard/keymaster/KMType.java b/Applet/src/com/android/javacard/keymaster/KMType.java index 4d81de45..59a4b172 100644 --- a/Applet/src/com/android/javacard/keymaster/KMType.java +++ b/Applet/src/com/android/javacard/keymaster/KMType.java @@ -27,7 +27,8 @@ * prototype objects which just cast the structure over contiguous memory buffer. */ public abstract class KMType { - public static final short INVALID_VALUE = (short)0x8000; + + public static final short INVALID_VALUE = (short) 0x8000; protected static final byte TLV_HEADER_SIZE = 3; // Types @@ -283,12 +284,22 @@ public static void initialize() { KMType.heap = repository.getHeap(); } - public static byte getType(short ptr){return heap[ptr];} - public static short length(short ptr){return Util.getShort(heap, (short)(ptr+1));} - public static short getValue(short ptr){return Util.getShort(heap, (short)(ptr+TLV_HEADER_SIZE));} + public static byte getType(short ptr) { + return heap[ptr]; + } + + public static short length(short ptr) { + return Util.getShort(heap, (short) (ptr + 1)); + } + + public static short getValue(short ptr) { + return Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE)); + } - protected static short instance(byte type, short length){ - if (length < 0) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + protected static short instance(byte type, short length) { + if (length < 0) { + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + } short ptr = repository.alloc((short) (length + TLV_HEADER_SIZE)); heap[ptr] = type; Util.setShort(heap, (short) (ptr + 1), length); diff --git a/Applet/src/com/android/javacard/keymaster/KMUpgradable.java b/Applet/src/com/android/javacard/keymaster/KMUpgradable.java index 6815374e..0a241652 100644 --- a/Applet/src/com/android/javacard/keymaster/KMUpgradable.java +++ b/Applet/src/com/android/javacard/keymaster/KMUpgradable.java @@ -18,12 +18,13 @@ import org.globalplatform.upgrade.Element; public interface KMUpgradable { + void onSave(Element ele); - + void onRestore(Element ele); - + short getBackupPrimitiveByteCount(); - + short getBackupObjectCount(); } diff --git a/Applet/src/com/android/javacard/keymaster/KMVerificationToken.java b/Applet/src/com/android/javacard/keymaster/KMVerificationToken.java index c9c2f412..1a03b33c 100644 --- a/Applet/src/com/android/javacard/keymaster/KMVerificationToken.java +++ b/Applet/src/com/android/javacard/keymaster/KMVerificationToken.java @@ -19,15 +19,16 @@ import javacard.framework.ISO7816; import javacard.framework.ISOException; import javacard.framework.Util; + /** - * KMVerificationToken represents VerificationToken structure from android keymaster hal specifications. - * It corresponds to CBOR array type. - * struct{byte type=VERIFICATION_TOKEN_TYPE; short length=2; short arrayPtr} where arrayPtr is a pointer to - * ordered array with following elements: - * {KMInteger Challenge; KMInteger Timestamp; KMByteBlob PARAMETERS_VERIFIED; SecurityLevel level; - * KMByteBlob Mac}. + * KMVerificationToken represents VerificationToken structure from android keymaster hal + * specifications. It corresponds to CBOR array type. struct{byte type=VERIFICATION_TOKEN_TYPE; + * short length=2; short arrayPtr} where arrayPtr is a pointer to ordered array with following + * elements: {KMInteger Challenge; KMInteger Timestamp; KMByteBlob PARAMETERS_VERIFIED; + * SecurityLevel level; KMByteBlob Mac}. */ public class KMVerificationToken extends KMType { + public static final byte CHALLENGE = 0x00; public static final byte TIMESTAMP = 0x01; public static final byte PARAMETERS_VERIFIED = 0x02; @@ -37,10 +38,11 @@ public class KMVerificationToken extends KMType { private static KMVerificationToken prototype; private static short instPtr; - private KMVerificationToken() {} + private KMVerificationToken() { + } public static short exp() { - short arrPtr = KMArray.instance((short)5); + short arrPtr = KMArray.instance((short) 5); KMArray arr = KMArray.cast(arrPtr); arr.add(CHALLENGE, KMInteger.exp()); arr.add(TIMESTAMP, KMInteger.exp()); @@ -52,34 +54,42 @@ public static short exp() { } private static KMVerificationToken proto(short ptr) { - if (prototype == null) prototype = new KMVerificationToken(); + if (prototype == null) { + prototype = new KMVerificationToken(); + } instPtr = ptr; return prototype; } public static short instance() { - short arrPtr = KMArray.instance((short)5); + short arrPtr = KMArray.instance((short) 5); KMArray arr = KMArray.cast(arrPtr); - arr.add(CHALLENGE, KMInteger.uint_16((short)0)); - arr.add(TIMESTAMP, KMInteger.uint_16((short)0)); - arr.add(PARAMETERS_VERIFIED, KMByteBlob.instance((short)0)); + arr.add(CHALLENGE, KMInteger.uint_16((short) 0)); + arr.add(TIMESTAMP, KMInteger.uint_16((short) 0)); + arr.add(PARAMETERS_VERIFIED, KMByteBlob.instance((short) 0)); arr.add(SECURITY_LEVEL, KMEnum.instance(KMType.HARDWARE_TYPE, KMType.STRONGBOX)); - arr.add(MAC, KMByteBlob.instance((short)0)); + arr.add(MAC, KMByteBlob.instance((short) 0)); return instance(arrPtr); } public static short instance(short vals) { KMArray arr = KMArray.cast(vals); - if(arr.length() != 5)ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); - short ptr = KMType.instance(VERIFICATION_TOKEN_TYPE, (short)2); - Util.setShort(heap, (short)(ptr + TLV_HEADER_SIZE), vals); + if (arr.length() != 5) { + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + } + short ptr = KMType.instance(VERIFICATION_TOKEN_TYPE, (short) 2); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE), vals); return ptr; } public static KMVerificationToken cast(short ptr) { - if (heap[ptr] != VERIFICATION_TOKEN_TYPE) ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + if (heap[ptr] != VERIFICATION_TOKEN_TYPE) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } short arrPtr = Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE)); - if(heap[arrPtr] != ARRAY_TYPE) ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + if (heap[arrPtr] != ARRAY_TYPE) { + ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); + } return proto(ptr); } @@ -131,7 +141,7 @@ public short getParametersVerified() { } public void setParametersVerified(short vals) { - // KMKeyParameters.cast(vals); + // KMKeyParameters.cast(vals); KMByteBlob.cast(vals); short arrPtr = getVals(); KMArray.cast(arrPtr).add(PARAMETERS_VERIFIED, vals); diff --git a/HAL/keymaster/4.1/android.hardware.keymaster@4.1-javacard.service.xml b/HAL/keymaster/4.1/android.hardware.keymaster@4.1-javacard.service.xml index 5e365def..83fccabe 100644 --- a/HAL/keymaster/4.1/android.hardware.keymaster@4.1-javacard.service.xml +++ b/HAL/keymaster/4.1/android.hardware.keymaster@4.1-javacard.service.xml @@ -1,7 +1,7 @@ - - android.hardware.keymaster - hwbinder - @4.1::IKeymasterDevice/javacard - + + android.hardware.keymaster + hwbinder + @4.1::IKeymasterDevice/javacard +