1 /*
2  * Copyright(C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.javacard.keymaster;
18 
19 import com.android.javacard.seprovider.KMAttestationCert;
20 import com.android.javacard.seprovider.KMDataStoreConstants;
21 import com.android.javacard.seprovider.KMException;
22 import com.android.javacard.seprovider.KMKey;
23 import com.android.javacard.seprovider.KMOperation;
24 import com.android.javacard.seprovider.KMSEProvider;
25 import javacard.framework.APDU;
26 import javacard.framework.Applet;
27 import javacard.framework.AppletEvent;
28 import javacard.framework.ISO7816;
29 import javacard.framework.ISOException;
30 import javacard.framework.JCSystem;
31 import javacard.framework.Util;
32 import javacard.security.CryptoException;
33 import javacardx.apdu.ExtendedLength;
34 
35 /**
36  * KMKeymasterApplet implements the javacard applet. It creates an instance of the KMRepository and
37  * other install time objects. It also implements the keymaster state machine and handles javacard
38  * applet life cycle events.
39  */
40 public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLength {
41 
42   // Constants.
43   // Represents RSA_PUBLIC_EXPONENT value 65537.
44   public static final byte[] F4 = {0x01, 0x00, 0x01};
45   // Block size of AES algorithm.
46   public static final byte AES_BLOCK_SIZE = 16;
47   // Block size of DES algorithm.
48   public static final byte DES_BLOCK_SIZE = 8;
49   // The Key size in bits for the master key.
50   public static final short MASTER_KEY_SIZE = 128;
51   // The Key size of the transport key used in importWrappedKey.
52   public static final byte WRAPPING_KEY_SIZE = 32;
53   // The maximum allowed simultaneous operations.
54   public static final byte MAX_OPERATIONS_COUNT = 4;
55   // The size of the verified boot key in ROT.
56   public static final byte VERIFIED_BOOT_KEY_SIZE = 32;
57   // The size of the verified boot hash in ROT.
58   public static final byte VERIFIED_BOOT_HASH_SIZE = 32;
59   // The security level of TEE.
60   public static final byte TRUSTED_ENVIRONMENT = 1;
61   // "Keymaster HMAC Verification" - used for HMAC key verification.
62   public static final byte[] sharingCheck = {
63     0x4B, 0x65, 0x79, 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x48, 0x4D, 0x41, 0x43, 0x20, 0x56,
64     0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E
65   };
66   // The ckdfLabel "KeymasterSharedMac" in hex.
67   public static final byte[] ckdfLabel = {
68     0x4B, 0x65, 0x79, 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4D,
69     0x61, 0x63
70   };
71   // The "Auth Verification" string in hex.
72   public static final byte[] authVerification = {
73     0x41, 0x75, 0x74, 0x68, 0x20, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F,
74     0x6E
75   };
76   // The "confirmation token" string in hex.
77   public static final byte[] confirmationToken = {
78     0x63, 0x6F, 0x6E, 0x66, 0x69, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x74, 0x6F, 0x6B,
79     0x65, 0x6E
80   };
81   // The maximum buffer size for the encoded COSE structures.
82   public static final short MAX_COSE_BUF_SIZE = (short) 1024;
83   // Maximum allowed buffer size for to encode the key parameters
84   // which is used while creating mac for key parameters.
85   public static final short MAX_KEY_PARAMS_BUF_SIZE = (short) 3072; // 3K
86   // Temporary variables array size to store intermediary results.
87   public static final byte TMP_VARIABLE_ARRAY_SIZE = 5;
88   // Data Dictionary items
89   // Maximum Dictionary size.
90   public static final byte DATA_ARRAY_SIZE = 39;
91   // Below are the offsets of the data dictionary items.
92   public static final byte KEY_PARAMETERS = 0;
93   public static final byte KEY_CHARACTERISTICS = 1;
94   public static final byte HIDDEN_PARAMETERS = 2;
95   public static final byte HW_PARAMETERS = 3;
96   public static final byte SW_PARAMETERS = 4;
97   public static final byte AUTH_DATA = 5;
98   public static final byte AUTH_TAG = 6;
99   public static final byte NONCE = 7;
100   public static final byte KEY_BLOB = 8;
101   public static final byte AUTH_DATA_LENGTH = 9;
102   public static final byte SECRET = 10;
103   public static final byte ROT = 11;
104   public static final byte DERIVED_KEY = 12;
105   public static final byte RSA_PUB_EXPONENT = 13;
106   public static final byte APP_ID = 14;
107   public static final byte APP_DATA = 15;
108   public static final byte PUB_KEY = 16;
109   public static final byte IMPORTED_KEY_BLOB = 17;
110   public static final byte ORIGIN = 18;
111   public static final byte NOT_USED = 19;
112   public static final byte MASKING_KEY = 20;
113   public static final byte HMAC_SHARING_PARAMS = 21;
114   public static final byte OP_HANDLE = 22;
115   public static final byte IV = 23;
116   public static final byte INPUT_DATA = 24;
117   public static final byte OUTPUT_DATA = 25;
118   public static final byte HW_TOKEN = 26;
119   public static final byte VERIFICATION_TOKEN = 27;
120   public static final byte SIGNATURE = 28;
121   public static final byte ATTEST_KEY_BLOB = 29;
122   public static final byte ATTEST_KEY_PARAMS = 30;
123   public static final byte ATTEST_KEY_ISSUER = 31;
124   public static final byte CERTIFICATE = 32;
125   public static final byte PLAIN_SECRET = 33;
126   public static final byte TEE_PARAMETERS = 34;
127   public static final byte SB_PARAMETERS = 35;
128   public static final byte CONFIRMATION_TOKEN = 36;
129   public static final byte KEY_BLOB_VERSION_DATA_OFFSET = 37;
130   public static final byte CUSTOM_TAGS = 38;
131   // Below are the Keyblob offsets.
132   public static final byte KEY_BLOB_VERSION_OFFSET = 0;
133   public static final byte KEY_BLOB_SECRET = 1;
134   public static final byte KEY_BLOB_NONCE = 2;
135   public static final byte KEY_BLOB_AUTH_TAG = 3;
136   public static final byte KEY_BLOB_PARAMS = 4;
137   public static final byte KEY_BLOB_CUSTOM_TAGS = 5;
138   public static final byte KEY_BLOB_PUB_KEY = 6;
139   // AES GCM Auth tag length to be used while encrypting or decrypting the KeyBlob.
140   public static final byte AES_GCM_AUTH_TAG_LENGTH = 16;
141   // AES GCM nonce length to be used while encrypting or decrypting the KeyBlob.
142   public static final byte AES_GCM_NONCE_LENGTH = 12;
143   // KEYBLOB_CURRENT_VERSION goes into KeyBlob and will affect all
144   // the KeyBlobs if it is changed. please increment this
145   // version number whenever you change anything related to
146   // KeyBlob (structure, encryption algorithm etc).
147   public static final short KEYBLOB_CURRENT_VERSION = 3;
148   // KeyBlob Verion 1 constant.
149   public static final short KEYBLOB_VERSION_1 = 1;
150   // Array sizes of KeyBlob under different versions.
151   // The array size of a Symmetric key's KeyBlob for Version2 and Version3
152   public static final byte SYM_KEY_BLOB_SIZE_V2_V3 = 6;
153   // The array size of a Asymmetric key's KeyBlob for Version2 and Version3
154   public static final byte ASYM_KEY_BLOB_SIZE_V2_V3 = 7;
155   // The array size of a Symmetric key's KeyBlob for Version1
156   public static final byte SYM_KEY_BLOB_SIZE_V1 = 5;
157   // The array size of a Asymmetric key's KeyBlob for Version1
158   public static final byte ASYM_KEY_BLOB_SIZE_V1 = 6;
159   // The array size of a Symmetric key's KeyBlob for Version0
160   public static final byte SYM_KEY_BLOB_SIZE_V0 = 4;
161   // The array size of a Asymmetric key's KeyBlob for Version0
162   public static final byte ASYM_KEY_BLOB_SIZE_V0 = 5;
163   // Key type constants
164   // Represents the type of the Symmetric key.
165   public static final byte SYM_KEY_TYPE = 0;
166   // Represents the type of the Asymmetric key.
167   public static final byte ASYM_KEY_TYPE = 1;
168   // SHA-256 Digest length in bits
169   public static final short SHA256_DIGEST_LEN_BITS = 256;
170   // Minimum HMAC length in bits
171   public static final short MIN_HMAC_LENGTH_BITS = 64;
172   // Below are the constants for provision reporting status
173   public static final short NOT_PROVISIONED = 0x0000;
174   public static final short PROVISION_STATUS_ATTESTATION_KEY = 0x0001;
175   public static final short PROVISION_STATUS_ATTESTATION_CERT_CHAIN = 0x0002;
176   public static final short PROVISION_STATUS_ATTESTATION_CERT_PARAMS = 0x0004;
177   public static final short PROVISION_STATUS_ATTEST_IDS = 0x0008;
178   public static final short PROVISION_STATUS_PRESHARED_SECRET = 0x0010;
179   public static final short PROVISION_STATUS_PROVISIONING_LOCKED = 0x0020;
180   public static final short PROVISION_STATUS_DEVICE_UNIQUE_KEYPAIR = 0x0040;
181   public static final short PROVISION_STATUS_ADDITIONAL_CERT_CHAIN = 0x0080;
182   public static final short PROVISION_STATUS_SE_LOCKED = 0x0100;
183   public static final short PROVISION_STATUS_OEM_PUBLIC_KEY = 0x0200;
184   public static final short PROVISION_STATUS_SECURE_BOOT_MODE = 0x0400;
185   // This is the P1P2 constant of the APDU command header.
186   protected static final short KM_HAL_VERSION = (short) 0x5000;
187   // OEM lock / unlock verification constants.
188   // This is the verification label to authenticate the OEM to lock the provisioning for the
189   // OEM provision commands.
190   protected static final byte[] OEM_LOCK_PROVISION_VERIFICATION_LABEL = { // "OEM Provisioning Lock"
191     0x4f, 0x45, 0x4d, 0x20, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67,
192     0x20, 0x4c, 0x6f, 0x63, 0x6b
193   };
194   // This is the verification label to authenticate the OEM to unlock the provisioning for the
195   // OEM provision commands.
196   protected static final byte[] OEM_UNLOCK_PROVISION_VERIFICATION_LABEL = { // "Enable RMA"
197     0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x52, 0x4d, 0x41
198   };
199   // The maximum size of the seed allowed for the RNG entropy
200   protected static final short MAX_SEED_SIZE = 2048;
201   // The maximum size of the certificate returned by the generate key command.
202   protected static final short MAX_CERT_SIZE = 3000;
203   // The maximum size of the encoded key characteristics in CBOR.
204   protected static final short MAX_KEY_CHARS_SIZE = 512;
205   // The maximum size of the serialized KeyBlob.
206   protected static final short MAX_KEYBLOB_SIZE = 1024;
207   // The maximum size of the Auth data which is used while encrypting/decrypting the KeyBlob.
208   private static final short MAX_AUTH_DATA_SIZE = (short) 512;
209   // The minimum bits in length for AES-GCM tag.
210   private static final short MIN_GCM_TAG_LENGTH_BITS = (short) 96;
211   // The maximum bits in length for AES-GCM tag.
212   private static final short MAX_GCM_TAG_LENGTH_BITS = (short) 128;
213   // Subject is a fixed field with only CN= Android Keystore Key - same for all the keys
214   private static final byte[] defaultSubject = {
215     0x30, 0x1F, 0x31, 0x1D, 0x30, 0x1B, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x14, 0x41, 0x6e, 0x64,
216     0x72, 0x6f, 0x69, 0x64, 0x20, 0x4B, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x4B, 0x65,
217     0x79
218   };
219   // Constant for Dec 31, 9999 in milliseconds in hex.
220   private static final byte[] dec319999Ms = {
221     (byte) 0, (byte) 0, (byte) 0xE6, (byte) 0x77, (byte) 0xD2, (byte) 0x1F, (byte) 0xD8, (byte) 0x18
222   };
223   // Dec 31, 9999 represented in Generalized time format YYYYMMDDhhmmssZ.
224   // "99991231235959Z" in hex. Refer RFC 5280 section 4.1.2.5.2
225   private static final byte[] dec319999 = {
226     0x39, 0x39, 0x39, 0x39, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a,
227   };
228   // Jan 01, 1970 represented in UTC time format YYMMDDhhmmssZ.
229   // "700101000000Z" in hex. Refer RFC 5280 section 4.1.2.5.1
230   private static final byte[] jan01970 = {
231     0x37, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
232   };
233   // The KeyMint name "JavacardKeymintDevice" returned from getHwInfo.
234   private static final byte[] JavacardKeymintDevice = {
235     0x4a, 0x61, 0x76, 0x61, 0x63, 0x61, 0x72, 0x64, 0x4b, 0x65, 0x79, 0x6d, 0x69, 0x6e, 0x74, 0x44,
236     0x65, 0x76, 0x69, 0x63, 0x65,
237   };
238   // The KeyMint author name "Google" returned from getHwInfo.
239   public static final byte[] Google = {0x47, 0x6F, 0x6F, 0x67, 0x6C, 0x65};
240   // Attestation ID tags to be included in attestation record.
241   private static final short[] attTags = {
242     KMType.ATTESTATION_ID_BRAND,
243     KMType.ATTESTATION_ID_DEVICE,
244     KMType.ATTESTATION_ID_IMEI,
245     KMType.ATTESTATION_ID_MANUFACTURER,
246     KMType.ATTESTATION_ID_MEID,
247     KMType.ATTESTATION_ID_MODEL,
248     KMType.ATTESTATION_ID_PRODUCT,
249     KMType.ATTESTATION_ID_SERIAL
250   };
251   // Below are the constants of instructions in APDU command header.
252   // Top 32 commands are reserved for provisioning.
253   private static final byte KEYMINT_CMD_APDU_START = 0x20;
254   // RKP
255   public static final byte INS_GET_RKP_HARDWARE_INFO = KEYMINT_CMD_APDU_START + 27; // 0x3B
256   public static final byte INS_GENERATE_RKP_KEY_CMD = KEYMINT_CMD_APDU_START + 28; // 0x3C
257   public static final byte INS_BEGIN_SEND_DATA_CMD = KEYMINT_CMD_APDU_START + 29; // 0x3D
258   public static final byte INS_UPDATE_KEY_CMD = KEYMINT_CMD_APDU_START + 30; // 0x3E
259   // Constant
260   public static final byte INS_UPDATE_EEK_CHAIN_CMD = KEYMINT_CMD_APDU_START + 31; // 0x3F
261   public static final byte INS_UPDATE_CHALLENGE_CMD = KEYMINT_CMD_APDU_START + 32; // 0x40
262   public static final byte INS_FINISH_SEND_DATA_CMD = KEYMINT_CMD_APDU_START + 33; // 0x41
263   public static final byte INS_GET_RESPONSE_CMD = KEYMINT_CMD_APDU_START + 34; // 0x42
264   private static final byte INS_GENERATE_KEY_CMD = KEYMINT_CMD_APDU_START + 1; // 0x21
265   private static final byte INS_IMPORT_KEY_CMD = KEYMINT_CMD_APDU_START + 2; // 0x22
266   private static final byte INS_IMPORT_WRAPPED_KEY_CMD = KEYMINT_CMD_APDU_START + 3; // 0x23
267   private static final byte INS_EXPORT_KEY_CMD = KEYMINT_CMD_APDU_START + 4; // 0x24
268   private static final byte INS_ATTEST_KEY_CMD = KEYMINT_CMD_APDU_START + 5; // 0x25
269   private static final byte INS_UPGRADE_KEY_CMD = KEYMINT_CMD_APDU_START + 6; // 0x26
270   private static final byte INS_DELETE_KEY_CMD = KEYMINT_CMD_APDU_START + 7; // 0x27
271   private static final byte INS_DELETE_ALL_KEYS_CMD = KEYMINT_CMD_APDU_START + 8; // 0x28
272   private static final byte INS_ADD_RNG_ENTROPY_CMD = KEYMINT_CMD_APDU_START + 9; // 0x29
273   private static final byte INS_COMPUTE_SHARED_HMAC_CMD = KEYMINT_CMD_APDU_START + 10; // 0x2A
274   private static final byte INS_DESTROY_ATT_IDS_CMD = KEYMINT_CMD_APDU_START + 11; // 0x2B
275   private static final byte INS_VERIFY_AUTHORIZATION_CMD = KEYMINT_CMD_APDU_START + 12; // 0x2C
276   private static final byte INS_GET_HMAC_SHARING_PARAM_CMD = KEYMINT_CMD_APDU_START + 13; // 0x2D
277   private static final byte INS_GET_KEY_CHARACTERISTICS_CMD = KEYMINT_CMD_APDU_START + 14; // 0x2E
278   private static final byte INS_GET_HW_INFO_CMD = KEYMINT_CMD_APDU_START + 15; // 0x2F
279   private static final byte INS_BEGIN_OPERATION_CMD = KEYMINT_CMD_APDU_START + 16; // 0x30
280   private static final byte INS_UPDATE_OPERATION_CMD = KEYMINT_CMD_APDU_START + 17; // 0x31
281   private static final byte INS_FINISH_OPERATION_CMD = KEYMINT_CMD_APDU_START + 18; // 0x32
282   private static final byte INS_ABORT_OPERATION_CMD = KEYMINT_CMD_APDU_START + 19; // 0x33
283   private static final byte INS_DEVICE_LOCKED_CMD = KEYMINT_CMD_APDU_START + 20; // 0x34
284   private static final byte INS_EARLY_BOOT_ENDED_CMD = KEYMINT_CMD_APDU_START + 21; // 0x35
285   private static final byte INS_GET_CERT_CHAIN_CMD = KEYMINT_CMD_APDU_START + 22; // 0x36
286   private static final byte INS_UPDATE_AAD_OPERATION_CMD = KEYMINT_CMD_APDU_START + 23; // 0x37
287   private static final byte INS_BEGIN_IMPORT_WRAPPED_KEY_CMD = KEYMINT_CMD_APDU_START + 24; // 0x38
288   private static final byte INS_FINISH_IMPORT_WRAPPED_KEY_CMD = KEYMINT_CMD_APDU_START + 25; // 0x39
289   private static final byte INS_INIT_STRONGBOX_CMD = KEYMINT_CMD_APDU_START + 26; // 0x3A
290   // The instructions from 0x43 to 0x4C will be reserved for KeyMint 1.0 for any future use.
291   // KeyMint 2.0 Instructions
292   private static final byte INS_GET_ROT_CHALLENGE_CMD = KEYMINT_CMD_APDU_START + 45; // 0x4D
293   private static final byte INS_GET_ROT_DATA_CMD = KEYMINT_CMD_APDU_START + 46; // 0x4E
294   private static final byte INS_SEND_ROT_DATA_CMD = KEYMINT_CMD_APDU_START + 47; // 0x4F
295   private static final byte KEYMINT_CMD_APDU_END = KEYMINT_CMD_APDU_START + 48; // 0x50
296   private static final byte INS_END_KM_CMD = 0x7F;
297   // Instruction values from 0xCD to 0xFF are completely reserved for Vendors to use and
298   // will never be used by the base line code in future.
299   private static final byte INS_KM_VENDOR_START_CMD = (byte) 0xCD;
300   private static final byte INS_KM_VENDOR_END_CMD = (byte) 0xFF;
301   // Index in apduFlagsStatus[] to check if instruction command is case 4 type in the Apdu
302   protected static final byte APDU_CASE4_COMMAND_STATUS_INDEX = 0;
303   // Index in apduFlagsStatus[] to check if Apdu setIncomingAndReceive function is called
304   protected static final byte APDU_INCOMING_AND_RECEIVE_STATUS_INDEX = 1;
305   // The maximum buffer size of combined seed and nonce.
306   private static final byte HMAC_SHARED_PARAM_MAX_SIZE = 64;
307   // Instance of RemotelyProvisionedComponentDevice, used to redirect the rkp commands.
308   protected static KMRemotelyProvisionedComponentDevice rkp;
309   // Instance of Cbor encoder.
310   protected static KMEncoder encoder;
311   // Instance of Cbor decoder.
312   protected static KMDecoder decoder;
313   // Instance of KMRepository class for memory management.
314   protected static KMRepository repository;
315   // Instance of KMSEProvider for doing crypto operations.
316   protected static KMSEProvider seProvider;
317   // Holds the instance of KMOperationStates. A maximum of 4 instances of KMOperatioState is
318   // allowed.
319   protected static KMOperationState[] opTable;
320   // Instance of KMKeymintDataStore which helps to store and retrieve the data.
321   protected static KMKeymintDataStore kmDataStore;
322 
323   // Short array used to store the temporary results.
324   protected static short[] tmpVariables;
325   // Short array used to hold the dictionary items.
326   protected static short[] data;
327   // Buffer to store the transportKey which is used in the import wrapped key. Import wrapped
328   // key is divided into two stages 1. BEGIN_IMPORT_WRAPPED_KEY 2. FINISH_IMPORT_WRAPPED_KEY.
329   // The transportKey is retrieved and stored in this buffer at stage 1) and is later used in
330   // stage 2).
331   protected static byte[] wrappingKey;
332   // Transient byte array used to store the flags if APDU command type is of case 4 and if
333   // APDU setIncomingAndReceive() function is called or not.
334   protected static byte[] apduStatusFlags;
335 
336   /** Registers this applet. */
KMKeymasterApplet(KMSEProvider seImpl)337   protected KMKeymasterApplet(KMSEProvider seImpl) {
338     seProvider = seImpl;
339     boolean isUpgrading = seProvider.isUpgrading();
340     repository = new KMRepository(isUpgrading);
341     encoder = new KMEncoder();
342     decoder = new KMDecoder();
343     kmDataStore = new KMKeymintDataStore(seProvider, repository);
344     data = JCSystem.makeTransientShortArray(DATA_ARRAY_SIZE, JCSystem.CLEAR_ON_DESELECT);
345     tmpVariables =
346         JCSystem.makeTransientShortArray(TMP_VARIABLE_ARRAY_SIZE, JCSystem.CLEAR_ON_DESELECT);
347     wrappingKey =
348         JCSystem.makeTransientByteArray((short) (WRAPPING_KEY_SIZE + 1), JCSystem.CLEAR_ON_RESET);
349     resetWrappingKey();
350     apduStatusFlags = JCSystem.makeTransientByteArray((short) 2, JCSystem.CLEAR_ON_RESET);
351     opTable = new KMOperationState[MAX_OPERATIONS_COUNT];
352     short index = 0;
353     while (index < MAX_OPERATIONS_COUNT) {
354       opTable[index] = new KMOperationState();
355       index++;
356     }
357     KMType.initialize();
358     if (!isUpgrading) {
359       kmDataStore.createMasterKey(MASTER_KEY_SIZE);
360     }
361     // initialize default values
362     initHmacNonceAndSeed();
363     rkp =
364         new KMRemotelyProvisionedComponentDevice(
365             encoder, decoder, repository, seProvider, kmDataStore);
366   }
367 
368   /** Sends a response, may be extended response, as requested by the command. */
sendOutgoing(APDU apdu, short resp)369   public static void sendOutgoing(APDU apdu, short resp) {
370     // TODO handle the extended buffer stuff. We can reuse this.
371     short bufferStartOffset = repository.allocAvailableMemory();
372     byte[] buffer = repository.getHeap();
373     // TODO we can change the following to incremental send.
374     short bufferLength =
375         encoder.encode(resp, buffer, bufferStartOffset, repository.getHeapReclaimIndex());
376     if (((short) (bufferLength + bufferStartOffset)) > ((short) repository.getHeap().length)) {
377       ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
378     }
379 
380     /* In T=0 protocol, On a case 4 command, setIncomingAndReceive() must
381      * be invoked prior to calling setOutgoing(). Otherwise, erroneous
382      * behavior may result
383      * */
384     if (apduStatusFlags[APDU_CASE4_COMMAND_STATUS_INDEX] == 1
385         && apduStatusFlags[APDU_INCOMING_AND_RECEIVE_STATUS_INDEX] == 0
386         && APDU.getProtocol() == APDU.PROTOCOL_T0) {
387       apdu.setIncomingAndReceive();
388     }
389     // Send data
390     apdu.setOutgoing();
391     apdu.setOutgoingLength(bufferLength);
392     apdu.sendBytesLong(buffer, bufferStartOffset, bufferLength);
393   }
394 
395   /** Receives data, which can be extended data, as requested by the command instance. */
receiveIncoming(APDU apdu, short reqExp)396   public static short receiveIncoming(APDU apdu, short reqExp) {
397     byte[] srcBuffer = apdu.getBuffer();
398     short recvLen = apdu.setIncomingAndReceive();
399     short srcOffset = apdu.getOffsetCdata();
400     apduStatusFlags[APDU_INCOMING_AND_RECEIVE_STATUS_INDEX] = 1;
401     // TODO add logic to handle the extended length buffer. In this case the memory can be reused
402     //  from extended buffer.
403     short bufferLength = apdu.getIncomingLength();
404     short bufferStartOffset = repository.allocReclaimableMemory(bufferLength);
405     short index = bufferStartOffset;
406     byte[] buffer = repository.getHeap();
407     while (recvLen > 0 && ((short) (index - bufferStartOffset) < bufferLength)) {
408       Util.arrayCopyNonAtomic(srcBuffer, srcOffset, buffer, index, recvLen);
409       index += recvLen;
410       recvLen = apdu.receiveBytes(srcOffset);
411     }
412     short req = decoder.decode(reqExp, buffer, bufferStartOffset, bufferLength);
413     repository.reclaimMemory(bufferLength);
414     return req;
415   }
416 
createKeyBlobInstance(byte keyType)417   private static short createKeyBlobInstance(byte keyType) {
418     short arrayLen = 0;
419     switch (keyType) {
420       case ASYM_KEY_TYPE:
421         arrayLen = ASYM_KEY_BLOB_SIZE_V2_V3;
422         break;
423       case SYM_KEY_TYPE:
424         arrayLen = SYM_KEY_BLOB_SIZE_V2_V3;
425         break;
426       default:
427         KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM);
428     }
429     return KMArray.instance(arrayLen);
430   }
431 
addTags(short params, boolean hwEnforced, KMAttestationCert cert)432   private static void addTags(short params, boolean hwEnforced, KMAttestationCert cert) {
433     short index = 0;
434     short arr = KMKeyParameters.cast(params).getVals();
435     short len = KMArray.cast(arr).length();
436     short tag;
437     while (index < len) {
438       tag = KMArray.cast(arr).get(index);
439       cert.extensionTag(tag, hwEnforced);
440       index++;
441     }
442   }
443 
setUniqueId(KMAttestationCert cert, short attAppId, byte[] scratchPad)444   private static void setUniqueId(KMAttestationCert cert, short attAppId, byte[] scratchPad) {
445     if (!KMTag.isPresent(data[KEY_PARAMETERS], KMType.BOOL_TAG, KMType.INCLUDE_UNIQUE_ID)) {
446       return;
447     }
448     // temporal count T
449     short time =
450         KMKeyParameters.findTag(KMType.DATE_TAG, KMType.CREATION_DATETIME, data[KEY_PARAMETERS]);
451     if (time == KMType.INVALID_VALUE) {
452       KMException.throwIt(KMError.INVALID_KEY_BLOB);
453     }
454     time = KMIntegerTag.cast(time).getValue();
455 
456     // Reset After Rotation R - it will be part of HW Enforced key
457     // characteristics
458     byte resetAfterRotation = 0;
459     if (KMTag.isPresent(data[KEY_PARAMETERS], KMType.BOOL_TAG, KMType.RESET_SINCE_ID_ROTATION)) {
460       resetAfterRotation = 0x01;
461     }
462 
463     cert.makeUniqueId(
464         scratchPad,
465         (short) 0,
466         KMInteger.cast(time).getBuffer(),
467         KMInteger.cast(time).getStartOff(),
468         KMInteger.cast(time).length(),
469         KMByteBlob.cast(attAppId).getBuffer(),
470         KMByteBlob.cast(attAppId).getStartOff(),
471         KMByteBlob.cast(attAppId).length(),
472         resetAfterRotation,
473         kmDataStore.getMasterKey());
474   }
475 
validateRSAKey(byte[] scratchPad)476   private static void validateRSAKey(byte[] scratchPad) {
477     // Read key size
478     if (!KMTag.isValidKeySize(data[KEY_PARAMETERS])) {
479       KMException.throwIt(KMError.UNSUPPORTED_KEY_SIZE);
480     }
481     if (!KMTag.isValidPublicExponent(data[KEY_PARAMETERS])) {
482       KMException.throwIt(KMError.INVALID_ARGUMENT);
483     }
484   }
485 
486   // Generate key handlers
generateRSAKey(byte[] scratchPad)487   private static void generateRSAKey(byte[] scratchPad) {
488     // Validate RSA Key
489     validateRSAKey(scratchPad);
490     // Now generate 2048 bit RSA keypair for the given exponent
491     short[] lengths = tmpVariables;
492     data[PUB_KEY] = KMByteBlob.instance((short) 256);
493     data[SECRET] = KMByteBlob.instance((short) 256);
494     seProvider.createAsymmetricKey(
495         KMType.RSA,
496         KMByteBlob.cast(data[SECRET]).getBuffer(),
497         KMByteBlob.cast(data[SECRET]).getStartOff(),
498         KMByteBlob.cast(data[SECRET]).length(),
499         KMByteBlob.cast(data[PUB_KEY]).getBuffer(),
500         KMByteBlob.cast(data[PUB_KEY]).getStartOff(),
501         KMByteBlob.cast(data[PUB_KEY]).length(),
502         lengths);
503 
504     data[KEY_BLOB] = createKeyBlobInstance(ASYM_KEY_TYPE);
505     KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_PUB_KEY, data[PUB_KEY]);
506   }
507 
validateAESKey()508   private static void validateAESKey() {
509     // Read key size
510     if (!KMTag.isValidKeySize(data[KEY_PARAMETERS])) {
511       KMException.throwIt(KMError.UNSUPPORTED_KEY_SIZE);
512     }
513     // Read Block mode - array of byte values
514     if (KMTag.isPresent(data[KEY_PARAMETERS], KMType.ENUM_ARRAY_TAG, KMType.BLOCK_MODE)) {
515       short blockModes =
516           KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.BLOCK_MODE, data[KEY_PARAMETERS]);
517       // If it is a GCM mode
518       if (KMEnumArrayTag.cast(blockModes).contains(KMType.GCM)) {
519         // Min mac length must be present
520         KMTag.assertPresence(
521             data[KEY_PARAMETERS],
522             KMType.UINT_TAG,
523             KMType.MIN_MAC_LENGTH,
524             KMError.MISSING_MIN_MAC_LENGTH);
525         short macLength =
526             KMKeyParameters.findTag(KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, data[KEY_PARAMETERS]);
527         macLength = KMIntegerTag.cast(macLength).getValue();
528         // Validate the MIN_MAC_LENGTH for AES - should be multiple of 8, less then 128 bits
529         // and greater the 96 bits
530         if (KMInteger.cast(macLength).getSignificantShort() != 0
531             || KMInteger.cast(macLength).getShort() > 128
532             || KMInteger.cast(macLength).getShort() < 96
533             || (KMInteger.cast(macLength).getShort() % 8) != 0) {
534           KMException.throwIt(KMError.UNSUPPORTED_MIN_MAC_LENGTH);
535         }
536       }
537     }
538   }
539 
generateAESKey(byte[] scratchPad)540   private static void generateAESKey(byte[] scratchPad) {
541     validateAESKey();
542     short keysize =
543         KMIntegerTag.getShortValue(KMType.UINT_TAG, KMType.KEYSIZE, data[KEY_PARAMETERS]);
544     short len = seProvider.createSymmetricKey(KMType.AES, keysize, scratchPad, (short) 0);
545     data[SECRET] = KMByteBlob.instance(scratchPad, (short) 0, len);
546     data[KEY_BLOB] = createKeyBlobInstance(SYM_KEY_TYPE);
547   }
548 
validateECKeys()549   private static void validateECKeys() {
550     // Read key size
551     short ecCurve = KMEnumTag.getValue(KMType.ECCURVE, data[KEY_PARAMETERS]);
552     /* In KeyMint 2.0, If EC_CURVE not provided, generateKey
553      * must return ErrorCode::UNSUPPORTED_KEY_SIZE or ErrorCode::UNSUPPORTED_EC_CURVE.
554      */
555     if (ecCurve != KMType.P_256) {
556       KMException.throwIt(KMError.UNSUPPORTED_KEY_SIZE);
557     }
558     short ecKeySize = KMEnumTag.getValue(KMType.KEYSIZE, data[KEY_PARAMETERS]);
559     if ((ecKeySize != KMType.INVALID_VALUE) && !KMTag.isValidKeySize(data[KEY_PARAMETERS])) {
560       KMException.throwIt(KMError.UNSUPPORTED_KEY_SIZE);
561     }
562   }
563 
generateECKeys(byte[] scratchPad)564   private static void generateECKeys(byte[] scratchPad) {
565     validateECKeys();
566     short[] lengths = tmpVariables;
567     seProvider.createAsymmetricKey(
568         KMType.EC,
569         scratchPad,
570         (short) 0,
571         (short) 128,
572         scratchPad,
573         (short) 128,
574         (short) 128,
575         lengths);
576     data[PUB_KEY] = KMByteBlob.instance(scratchPad, (short) 128, lengths[1]);
577     data[SECRET] = KMByteBlob.instance(scratchPad, (short) 0, lengths[0]);
578     data[KEY_BLOB] = createKeyBlobInstance(ASYM_KEY_TYPE);
579     KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_PUB_KEY, data[PUB_KEY]);
580   }
581 
validateTDESKey()582   private static void validateTDESKey() {
583     if (!KMTag.isValidKeySize(data[KEY_PARAMETERS])) {
584       KMException.throwIt(KMError.UNSUPPORTED_KEY_SIZE);
585     }
586     // Read Minimum Mac length - it must not be present
587     KMTag.assertAbsence(
588         data[KEY_PARAMETERS], KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, KMError.INVALID_TAG);
589   }
590 
generateTDESKey(byte[] scratchPad)591   private static void generateTDESKey(byte[] scratchPad) {
592     validateTDESKey();
593     short len = seProvider.createSymmetricKey(KMType.DES, (short) 168, scratchPad, (short) 0);
594     data[SECRET] = KMByteBlob.instance(scratchPad, (short) 0, len);
595     data[KEY_BLOB] = createKeyBlobInstance(SYM_KEY_TYPE);
596   }
597 
validateHmacKey()598   private static void validateHmacKey() {
599     // If params does not contain any digest throw unsupported digest error.
600     KMTag.assertPresence(
601         data[KEY_PARAMETERS], KMType.ENUM_ARRAY_TAG, KMType.DIGEST, KMError.UNSUPPORTED_DIGEST);
602 
603     // check whether digest sizes are greater then or equal to min mac length.
604     // Only SHA256 digest must be supported.
605     if (!KMEnumArrayTag.contains(KMType.DIGEST, KMType.SHA2_256, data[KEY_PARAMETERS])) {
606       KMException.throwIt(KMError.UNSUPPORTED_DIGEST);
607     }
608     // Read Minimum Mac length
609     KMTag.assertPresence(
610         data[KEY_PARAMETERS],
611         KMType.UINT_TAG,
612         KMType.MIN_MAC_LENGTH,
613         KMError.MISSING_MIN_MAC_LENGTH);
614     short minMacLength =
615         KMIntegerTag.getShortValue(KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, data[KEY_PARAMETERS]);
616 
617     if (((short) (minMacLength % 8) != 0)
618         || minMacLength < MIN_HMAC_LENGTH_BITS
619         || minMacLength > SHA256_DIGEST_LEN_BITS) {
620       KMException.throwIt(KMError.UNSUPPORTED_MIN_MAC_LENGTH);
621     }
622     // Read Keysize
623     if (!KMTag.isValidKeySize(data[KEY_PARAMETERS])) {
624       KMException.throwIt(KMError.UNSUPPORTED_KEY_SIZE);
625     }
626   }
627 
generateHmacKey(byte[] scratchPad)628   private static void generateHmacKey(byte[] scratchPad) {
629     validateHmacKey();
630     short keysize =
631         KMIntegerTag.getShortValue(KMType.UINT_TAG, KMType.KEYSIZE, data[KEY_PARAMETERS]);
632     // generate HMAC Key
633     short len = seProvider.createSymmetricKey(KMType.HMAC, keysize, scratchPad, (short) 0);
634     data[SECRET] = KMByteBlob.instance(scratchPad, (short) 0, len);
635     data[KEY_BLOB] = createKeyBlobInstance(SYM_KEY_TYPE);
636   }
637 
638   // This function is only called from processUpgradeKey command.
639   // 1. Update the latest values of OSVersion, OSPatch, VendorPatch and BootPatch in the
640   //    KeyBlob's KeyCharacteristics.
641   // 2. Re-create KeyBlob's KeyCharacteristics from HW_PARAMS to make sure we don't miss
642   //    anything which happens in these functions makeSbEnforced and makeTeeEnforced in
643   //    the future. Like validations.
644   // 3. No need to create Keystore Enforced list here as it is not required to be included in
645   //    the KeyBlob's KeyCharacteristics.
646   // 4. No need to create KeyCharacteristics as upgradeKey does not require to return any
647   //    KeyCharacteristics back.
upgradeKeyBlobKeyCharacteristics(short hwParams, byte[] scratchPad)648   private static void upgradeKeyBlobKeyCharacteristics(short hwParams, byte[] scratchPad) {
649     short osVersion = kmDataStore.getOsVersion();
650     short osPatch = kmDataStore.getOsPatch();
651     short vendorPatch = kmDataStore.getVendorPatchLevel();
652     short bootPatch = kmDataStore.getBootPatchLevel();
653     data[SB_PARAMETERS] =
654         KMKeyParameters.makeSbEnforced(
655             hwParams, (byte) data[ORIGIN], osVersion, osPatch, vendorPatch, bootPatch, scratchPad);
656     data[TEE_PARAMETERS] = KMKeyParameters.makeTeeEnforced(hwParams, scratchPad);
657     data[HW_PARAMETERS] = KMKeyParameters.makeHwEnforced(data[SB_PARAMETERS], data[TEE_PARAMETERS]);
658   }
659 
makeKeyCharacteristics(byte[] scratchPad)660   private static void makeKeyCharacteristics(byte[] scratchPad) {
661     short osVersion = kmDataStore.getOsVersion();
662     short osPatch = kmDataStore.getOsPatch();
663     short vendorPatch = kmDataStore.getVendorPatchLevel();
664     short bootPatch = kmDataStore.getBootPatchLevel();
665     data[SB_PARAMETERS] =
666         KMKeyParameters.makeSbEnforced(
667             data[KEY_PARAMETERS],
668             (byte) data[ORIGIN],
669             osVersion,
670             osPatch,
671             vendorPatch,
672             bootPatch,
673             scratchPad);
674     data[TEE_PARAMETERS] = KMKeyParameters.makeTeeEnforced(data[KEY_PARAMETERS], scratchPad);
675     data[SW_PARAMETERS] = KMKeyParameters.makeKeystoreEnforced(data[KEY_PARAMETERS], scratchPad);
676     data[HW_PARAMETERS] = KMKeyParameters.makeHwEnforced(data[SB_PARAMETERS], data[TEE_PARAMETERS]);
677     data[KEY_CHARACTERISTICS] = KMKeyCharacteristics.instance();
678     KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).setStrongboxEnforced(data[SB_PARAMETERS]);
679     KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).setKeystoreEnforced(data[SW_PARAMETERS]);
680     KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).setTeeEnforced(data[TEE_PARAMETERS]);
681   }
682 
createEncryptedKeyBlob(byte[] scratchPad)683   private static void createEncryptedKeyBlob(byte[] scratchPad) {
684     // make root of trust blob
685     data[ROT] = readROT(scratchPad, KEYBLOB_CURRENT_VERSION);
686     if (data[ROT] == KMType.INVALID_VALUE) {
687       KMException.throwIt(KMError.UNKNOWN_ERROR);
688     }
689     // make hidden key params list
690     data[HIDDEN_PARAMETERS] =
691         KMKeyParameters.makeHidden(data[KEY_PARAMETERS], data[ROT], scratchPad);
692     data[KEY_BLOB_VERSION_DATA_OFFSET] = KMInteger.uint_16(KEYBLOB_CURRENT_VERSION);
693     // create custom tags
694     data[CUSTOM_TAGS] = KMKeyParameters.makeCustomTags(data[HW_PARAMETERS], scratchPad);
695     // encrypt the secret and cryptographically attach that to authorization data
696     encryptSecret(scratchPad);
697     // create key blob array
698     KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_SECRET, data[SECRET]);
699     KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_AUTH_TAG, data[AUTH_TAG]);
700     KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_NONCE, data[NONCE]);
701     KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_VERSION_OFFSET, data[KEY_BLOB_VERSION_DATA_OFFSET]);
702     KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_CUSTOM_TAGS, data[CUSTOM_TAGS]);
703 
704     short tempChar = KMKeyCharacteristics.instance();
705     short emptyParam = KMArray.instance((short) 0);
706     emptyParam = KMKeyParameters.instance(emptyParam);
707     KMKeyCharacteristics.cast(tempChar).setStrongboxEnforced(data[SB_PARAMETERS]);
708     KMKeyCharacteristics.cast(tempChar).setKeystoreEnforced(emptyParam);
709     KMKeyCharacteristics.cast(tempChar).setTeeEnforced(data[TEE_PARAMETERS]);
710     KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_PARAMS, tempChar);
711   }
712 
713   // Read RoT
readROT(byte[] scratchPad, short version)714   public static short readROT(byte[] scratchPad, short version) {
715     Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0);
716     short len = kmDataStore.getBootKey(scratchPad, (short) 0);
717     // As per IKeyMintDevice.aidl specification The root of trust
718     // consists of verifyBootKey, boot state and device locked.
719     if (version <= KEYBLOB_VERSION_1) {
720       // To parse old keyblobs verified boot hash is included in
721       // the root of trust.
722       len += kmDataStore.getVerifiedBootHash(scratchPad, (short) len);
723     }
724     short bootState = kmDataStore.getBootState();
725     len = Util.setShort(scratchPad, len, bootState);
726     if (kmDataStore.isDeviceBootLocked()) {
727       scratchPad[len] = (byte) 1;
728     } else {
729       scratchPad[len] = (byte) 0;
730     }
731     len++;
732     return KMByteBlob.instance(scratchPad, (short) 0, len);
733   }
734 
encryptSecret(byte[] scratchPad)735   private static void encryptSecret(byte[] scratchPad) {
736     // make nonce
737     data[NONCE] = KMByteBlob.instance(AES_GCM_NONCE_LENGTH);
738     data[AUTH_TAG] = KMByteBlob.instance(AES_GCM_AUTH_TAG_LENGTH);
739     seProvider.newRandomNumber(
740         KMByteBlob.cast(data[NONCE]).getBuffer(),
741         KMByteBlob.cast(data[NONCE]).getStartOff(),
742         KMByteBlob.cast(data[NONCE]).length());
743     // derive master key - stored in derivedKey
744     short len = deriveKey(scratchPad);
745     len =
746         seProvider.aesGCMEncrypt(
747             KMByteBlob.cast(data[DERIVED_KEY]).getBuffer(),
748             KMByteBlob.cast(data[DERIVED_KEY]).getStartOff(),
749             KMByteBlob.cast(data[DERIVED_KEY]).length(),
750             KMByteBlob.cast(data[SECRET]).getBuffer(),
751             KMByteBlob.cast(data[SECRET]).getStartOff(),
752             KMByteBlob.cast(data[SECRET]).length(),
753             scratchPad,
754             (short) 0,
755             KMByteBlob.cast(data[NONCE]).getBuffer(),
756             KMByteBlob.cast(data[NONCE]).getStartOff(),
757             KMByteBlob.cast(data[NONCE]).length(),
758             null,
759             (short) 0,
760             (short) 0,
761             KMByteBlob.cast(data[AUTH_TAG]).getBuffer(),
762             KMByteBlob.cast(data[AUTH_TAG]).getStartOff(),
763             KMByteBlob.cast(data[AUTH_TAG]).length());
764 
765     if (len > 0 && len != KMByteBlob.cast(data[SECRET]).length()) {
766       KMException.throwIt(KMError.INVALID_KEY_BLOB);
767     }
768     data[SECRET] = KMByteBlob.instance(scratchPad, (short) 0, len);
769   }
770 
getKeyType(short hardwareParams)771   private static byte getKeyType(short hardwareParams) {
772     short alg = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, hardwareParams);
773     if (KMEnumTag.cast(alg).getValue() == KMType.RSA
774         || KMEnumTag.cast(alg).getValue() == KMType.EC) {
775       return ASYM_KEY_TYPE;
776     }
777     return SYM_KEY_TYPE;
778   }
779 
makeAuthData(short version, byte[] scratchPad)780   private static void makeAuthData(short version, byte[] scratchPad) {
781     // For KeyBlob V2: Auth Data includes HW_PARAMETERS, HIDDEN_PARAMETERS, CUSTOM_TAGS, VERSION and
782     // PUB_KEY.
783     // For KeyBlob V1: Auth Data includes HW_PARAMETERS, HIDDEN_PARAMETERS, VERSION and PUB_KEY.
784     // For KeyBlob V0: Auth Data includes HW_PARAMETERS, HIDDEN_PARAMETERS and PUB_KEY.
785     // VERSION is included only for KeyBlobs having version >= 1.
786     // PUB_KEY is included for only ASYMMETRIC KeyBlobs.
787     short index = 0;
788     short numParams = 0;
789     Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 10, (byte) 0);
790     byte keyType = getKeyType(data[HW_PARAMETERS]);
791     // Copy the relevant parameters in the scratchPad in the order
792     // 1. HW_PARAMETERS
793     // 2. HIDDEN_PARAMETERS
794     // 3. VERSION ( Only Version >= 1)
795     // 4. PUB_KEY ( Only for Asymmetric Keys)
796     switch (version) {
797       case (short) 0:
798         numParams = 2;
799         Util.setShort(scratchPad, (short) 0, KMKeyParameters.cast(data[HW_PARAMETERS]).getVals());
800         Util.setShort(
801             scratchPad, (short) 2, KMKeyParameters.cast(data[HIDDEN_PARAMETERS]).getVals());
802         // For Asymmetric Keys include the PUB_KEY.
803         if (keyType == ASYM_KEY_TYPE) {
804           numParams = 3;
805           Util.setShort(scratchPad, (short) 4, data[PUB_KEY]);
806         }
807         break;
808       case (short) 1:
809         numParams = 3;
810         Util.setShort(scratchPad, (short) 0, KMKeyParameters.cast(data[HW_PARAMETERS]).getVals());
811         Util.setShort(
812             scratchPad, (short) 2, KMKeyParameters.cast(data[HIDDEN_PARAMETERS]).getVals());
813         Util.setShort(scratchPad, (short) 4, data[KEY_BLOB_VERSION_DATA_OFFSET]);
814         // For Asymmetric Keys include the PUB_KEY.
815         if (keyType == ASYM_KEY_TYPE) {
816           numParams = 4;
817           Util.setShort(scratchPad, (short) 6, data[PUB_KEY]);
818         }
819         break;
820       case (short) 2:
821         numParams = 4;
822         Util.setShort(scratchPad, (short) 0, KMKeyParameters.cast(data[HW_PARAMETERS]).getVals());
823         Util.setShort(
824             scratchPad, (short) 2, KMKeyParameters.cast(data[HIDDEN_PARAMETERS]).getVals());
825         Util.setShort(scratchPad, (short) 4, KMKeyParameters.cast(data[CUSTOM_TAGS]).getVals());
826         Util.setShort(scratchPad, (short) 6, data[KEY_BLOB_VERSION_DATA_OFFSET]);
827         // For Asymmetric Keys include the PUB_KEY.
828         if (keyType == ASYM_KEY_TYPE) {
829           numParams = 5;
830           Util.setShort(scratchPad, (short) 8, data[PUB_KEY]);
831         }
832         break;
833       default:
834         KMException.throwIt(KMError.INVALID_KEY_BLOB);
835     }
836     short prevReclaimIndex = repository.getHeapReclaimIndex();
837     short authIndex = repository.allocReclaimableMemory(MAX_AUTH_DATA_SIZE);
838     index = 0;
839     short len = 0;
840     Util.arrayFillNonAtomic(repository.getHeap(), authIndex, MAX_AUTH_DATA_SIZE, (byte) 0);
841     while (index < numParams) {
842       short tag = Util.getShort(scratchPad, (short) (index * 2));
843       len = encoder.encode(tag, repository.getHeap(), (short) (authIndex + 32), prevReclaimIndex);
844       Util.arrayCopyNonAtomic(
845           repository.getHeap(),
846           authIndex,
847           repository.getHeap(),
848           (short) (authIndex + len + 32),
849           (short) 32);
850       len =
851           seProvider.messageDigest256(
852               repository.getHeap(),
853               (short) (authIndex + 32),
854               (short) (len + 32),
855               repository.getHeap(),
856               authIndex);
857       if (len != 32) {
858         KMException.throwIt(KMError.UNKNOWN_ERROR);
859       }
860       index++;
861     }
862     short authDataIndex = repository.alloc(len);
863     Util.arrayCopyNonAtomic(
864         repository.getHeap(), authIndex, repository.getHeap(), authDataIndex, len);
865     repository.reclaimMemory(MAX_AUTH_DATA_SIZE);
866     data[AUTH_DATA] = authDataIndex;
867     data[AUTH_DATA_LENGTH] = len;
868   }
869 
deriveKeyForOldKeyBlobs(byte[] scratchPad)870   private static short deriveKeyForOldKeyBlobs(byte[] scratchPad) {
871     // KeyDerivation:
872     // 1. Do HMAC Sign, Auth data.
873     // 2. HMAC Sign generates an output of 32 bytes length.
874     // Consume only first 16 bytes as derived key.
875     // Hmac sign.
876     short len =
877         seProvider.hmacKDF(
878             kmDataStore.getMasterKey(),
879             repository.getHeap(),
880             data[AUTH_DATA],
881             data[AUTH_DATA_LENGTH],
882             scratchPad,
883             (short) 0);
884     if (len < 16) {
885       KMException.throwIt(KMError.UNKNOWN_ERROR);
886     }
887     len = 16;
888     data[DERIVED_KEY] = KMByteBlob.instance(scratchPad, (short) 0, len);
889     return len;
890   }
891 
deriveKey(byte[] scratchPad)892   private static short deriveKey(byte[] scratchPad) {
893     // For KeyBlob V3: Auth Data includes HW_PARAMETERS, HIDDEN_PARAMETERS, CUSTOM_TAGS, VERSION and
894     // PUB_KEY.
895     short index = 0;
896     Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 10, (byte) 0);
897     byte keyType = getKeyType(data[HW_PARAMETERS]);
898     // Copy the relevant parameters in the scratchPad in the order
899     // 1. HW_PARAMETERS
900     // 2. HIDDEN_PARAMETERS
901     // 3. CUSTOM_TAGS
902     // 3. VERSION ( Only Version >= 1)
903     // 4. PUB_KEY ( Only for Asymmetric Keys)
904     short numParams = 4;
905     Util.setShort(scratchPad, (short) 0, KMKeyParameters.cast(data[HW_PARAMETERS]).getVals());
906     Util.setShort(scratchPad, (short) 2, KMKeyParameters.cast(data[HIDDEN_PARAMETERS]).getVals());
907     Util.setShort(scratchPad, (short) 4, KMKeyParameters.cast(data[CUSTOM_TAGS]).getVals());
908     Util.setShort(scratchPad, (short) 6, data[KEY_BLOB_VERSION_DATA_OFFSET]);
909     // For Asymmetric Keys include the PUB_KEY.
910     if (keyType == ASYM_KEY_TYPE) {
911       numParams = 5;
912       Util.setShort(scratchPad, (short) 8, data[PUB_KEY]);
913     }
914     short prevReclaimIndex = repository.getHeapReclaimIndex();
915     short authIndex = repository.allocReclaimableMemory(MAX_AUTH_DATA_SIZE);
916     Util.arrayFillNonAtomic(repository.getHeap(), authIndex, MAX_AUTH_DATA_SIZE, (byte) 0);
917     short len = 0;
918     KMOperation operation = null;
919     try {
920       operation =
921           seProvider.initSymmetricOperation(
922               KMType.SIGN,
923               KMType.HMAC,
924               KMType.SHA2_256,
925               KMType.PADDING_NONE,
926               (byte) KMType.INVALID_VALUE,
927               (Object) kmDataStore.getMasterKey(),
928               KMDataStoreConstants.INTERFACE_TYPE_MASTER_KEY,
929               (byte[]) null,
930               (short) 0,
931               (short) 0,
932               (short) 0,
933               false);
934 
935       byte arrayHeader = (byte) 0x80;
936       arrayHeader |= (byte) numParams;
937       ((byte[]) repository.getHeap())[authIndex] = arrayHeader;
938       operation.update(repository.getHeap(), authIndex, (short) 1);
939 
940       while (index < numParams) {
941         short tag = Util.getShort(scratchPad, (short) (index * 2));
942         len = encoder.encode(tag, repository.getHeap(), (short) authIndex, prevReclaimIndex);
943         operation.update(repository.getHeap(), authIndex, len);
944         index++;
945       }
946       repository.reclaimMemory(MAX_AUTH_DATA_SIZE);
947       // KeyDerivation:
948       // 1. Do HMAC Sign, Auth data.
949       // 2. HMAC Sign generates an output of 32 bytes length.
950       // Consume only first 16 bytes as derived key.
951       // Hmac sign.
952       len = operation.sign(scratchPad, (short) 0, (short) 0, scratchPad, (short) 0);
953     } finally {
954       if (operation != null) {
955         operation.abort();
956       }
957     }
958     if (len < 16) {
959       KMException.throwIt(KMError.UNKNOWN_ERROR);
960     }
961     len = 16;
962     data[DERIVED_KEY] = KMByteBlob.instance(scratchPad, (short) 0, len);
963     return len;
964   }
965 
sendResponse(APDU apdu, short err)966   public static void sendResponse(APDU apdu, short err) {
967     short resp = KMArray.instance((short) 1);
968     err = KMError.translate(err);
969     short error = KMInteger.uint_16(err);
970     KMArray.cast(resp).add((short) 0, error);
971     sendOutgoing(apdu, resp);
972   }
973 
generateRkpKey(byte[] scratchPad, short keyParams)974   public static void generateRkpKey(byte[] scratchPad, short keyParams) {
975     data[KEY_PARAMETERS] = keyParams;
976     generateECKeys(scratchPad);
977     // create key blob
978     data[ORIGIN] = KMType.GENERATED;
979     makeKeyCharacteristics(scratchPad);
980     createEncryptedKeyBlob(scratchPad);
981     short prevReclaimIndex = repository.getHeapReclaimIndex();
982     short offset = repository.allocReclaimableMemory(MAX_KEYBLOB_SIZE);
983     data[KEY_BLOB] =
984         encoder.encode(
985             data[KEY_BLOB], repository.getHeap(), offset, prevReclaimIndex, MAX_KEYBLOB_SIZE);
986     data[KEY_BLOB] = KMByteBlob.instance(repository.getHeap(), offset, data[KEY_BLOB]);
987     repository.reclaimMemory(MAX_KEYBLOB_SIZE);
988   }
989 
getPubKey()990   public static short getPubKey() {
991     return data[PUB_KEY];
992   }
993 
getPivateKey()994   public static short getPivateKey() {
995     return data[KEY_BLOB];
996   }
997 
998   /**
999    * Encodes the object to the provided apdu buffer.
1000    *
1001    * @param object Object to be encoded.
1002    * @param apduBuf Buffer on which the encoded data is copied.
1003    * @param apduOff Start offset of the buffer.
1004    * @param maxLen Max value of the expected out length.
1005    * @return length of the encoded buffer.
1006    */
encodeToApduBuffer( short object, byte[] apduBuf, short apduOff, short maxLen)1007   public static short encodeToApduBuffer(
1008       short object, byte[] apduBuf, short apduOff, short maxLen) {
1009     short prevReclaimIndex = repository.getHeapReclaimIndex();
1010     short offset = repository.allocReclaimableMemory(maxLen);
1011     short len = encoder.encode(object, repository.getHeap(), offset, prevReclaimIndex, maxLen);
1012     Util.arrayCopyNonAtomic(repository.getHeap(), offset, apduBuf, apduOff, len);
1013     // release memory
1014     repository.reclaimMemory(maxLen);
1015     return len;
1016   }
1017 
validateCertChain( boolean validateEekRoot, byte expCertAlg, byte expLeafCertAlg, short certChainArr, byte[] scratchPad, Object[] authorizedEekRoots)1018   public static short validateCertChain(
1019       boolean validateEekRoot,
1020       byte expCertAlg,
1021       byte expLeafCertAlg,
1022       short certChainArr,
1023       byte[] scratchPad,
1024       Object[] authorizedEekRoots) {
1025     short len = KMArray.cast(certChainArr).length();
1026     short coseHeadersExp = KMCoseHeaders.exp();
1027     // prepare exp for coseky
1028     short coseKeyExp = KMCoseKey.exp();
1029     short ptr1;
1030     short ptr2;
1031     short signStructure;
1032     short encodedLen;
1033     short prevCoseKey = 0;
1034     short keySize;
1035     short alg = expCertAlg;
1036     short index;
1037     for (index = 0; index < len; index++) {
1038       ptr1 = KMArray.cast(certChainArr).get(index);
1039 
1040       // validate protected Headers
1041       ptr2 = KMArray.cast(ptr1).get(KMCose.COSE_SIGN1_PROTECTED_PARAMS_OFFSET);
1042       ptr2 =
1043           decoder.decode(
1044               coseHeadersExp,
1045               KMByteBlob.cast(ptr2).getBuffer(),
1046               KMByteBlob.cast(ptr2).getStartOff(),
1047               KMByteBlob.cast(ptr2).length());
1048       if (!KMCoseHeaders.cast(ptr2).isDataValid(rkp.rkpTmpVariables, alg, KMType.INVALID_VALUE)) {
1049         KMException.throwIt(KMError.STATUS_FAILED);
1050       }
1051 
1052       // parse and get the public key from payload.
1053       ptr2 = KMArray.cast(ptr1).get(KMCose.COSE_SIGN1_PAYLOAD_OFFSET);
1054       ptr2 =
1055           decoder.decode(
1056               coseKeyExp,
1057               KMByteBlob.cast(ptr2).getBuffer(),
1058               KMByteBlob.cast(ptr2).getStartOff(),
1059               KMByteBlob.cast(ptr2).length());
1060       if ((index == (short) (len - 1)) && len > 1) {
1061         alg = expLeafCertAlg;
1062       }
1063       if (!KMCoseKey.cast(ptr2)
1064           .isDataValid(
1065               rkp.rkpTmpVariables,
1066               KMCose.COSE_KEY_TYPE_EC2,
1067               KMType.INVALID_VALUE,
1068               alg,
1069               KMCose.COSE_ECCURVE_256)) {
1070         KMException.throwIt(KMError.STATUS_FAILED);
1071       }
1072       if (prevCoseKey == 0) {
1073         prevCoseKey = ptr2;
1074       }
1075       // Get the public key.
1076       keySize = KMCoseKey.cast(prevCoseKey).getEcdsa256PublicKey(scratchPad, (short) 0);
1077       if (keySize != 65) {
1078         KMException.throwIt(KMError.STATUS_FAILED);
1079       }
1080       if (validateEekRoot && (index == 0)) {
1081         boolean found = false;
1082         // In prod mode the first pubkey should match a well-known Google public key.
1083         for (short i = 0; i < (short) authorizedEekRoots.length; i++) {
1084           if (0
1085               == Util.arrayCompare(
1086                   scratchPad,
1087                   (short) 0,
1088                   (byte[]) authorizedEekRoots[i],
1089                   (short) 0,
1090                   (short) ((byte[]) authorizedEekRoots[i]).length)) {
1091             found = true;
1092             break;
1093           }
1094         }
1095         if (!found) {
1096           KMException.throwIt(KMError.STATUS_FAILED);
1097         }
1098       }
1099       // Validate signature.
1100       signStructure =
1101           KMCose.constructCoseSignStructure(
1102               KMArray.cast(ptr1).get(KMCose.COSE_SIGN1_PROTECTED_PARAMS_OFFSET),
1103               KMByteBlob.instance((short) 0),
1104               KMArray.cast(ptr1).get(KMCose.COSE_SIGN1_PAYLOAD_OFFSET));
1105       encodedLen =
1106           KMKeymasterApplet.encodeToApduBuffer(
1107               signStructure, scratchPad, keySize, KMKeymasterApplet.MAX_COSE_BUF_SIZE);
1108 
1109       short signatureLen =
1110           rkp.encodeES256CoseSignSignature(
1111               KMByteBlob.cast(KMArray.cast(ptr1).get(KMCose.COSE_SIGN1_SIGNATURE_OFFSET))
1112                   .getBuffer(),
1113               KMByteBlob.cast(KMArray.cast(ptr1).get(KMCose.COSE_SIGN1_SIGNATURE_OFFSET))
1114                   .getStartOff(),
1115               KMByteBlob.length(KMArray.cast(ptr1).get(KMCose.COSE_SIGN1_SIGNATURE_OFFSET)),
1116               scratchPad,
1117               (short) (keySize + encodedLen));
1118 
1119       if (!seProvider.ecVerify256(
1120           scratchPad,
1121           (short) 0,
1122           keySize,
1123           scratchPad,
1124           keySize,
1125           encodedLen,
1126           scratchPad,
1127           (short) (keySize + encodedLen),
1128           signatureLen)) {
1129         KMException.throwIt(KMError.STATUS_FAILED);
1130       }
1131       prevCoseKey = ptr2;
1132     }
1133     return prevCoseKey;
1134   }
1135 
generateBcc(boolean testMode, byte[] scratchPad)1136   public static short generateBcc(boolean testMode, byte[] scratchPad) {
1137     if (!testMode && kmDataStore.isProvisionLocked()) {
1138       KMException.throwIt(KMError.STATUS_FAILED);
1139     }
1140     KMKey deviceUniqueKey = kmDataStore.getRkpDeviceUniqueKeyPair(testMode);
1141     short temp = deviceUniqueKey.getPublicKey(scratchPad, (short) 0);
1142     short coseKey =
1143         KMCose.constructCoseKey(
1144             rkp.rkpTmpVariables,
1145             KMInteger.uint_8(KMCose.COSE_KEY_TYPE_EC2),
1146             KMType.INVALID_VALUE,
1147             KMNInteger.uint_8(KMCose.COSE_ALG_ES256),
1148             KMInteger.uint_8(KMCose.COSE_ECCURVE_256),
1149             scratchPad,
1150             (short) 0,
1151             temp,
1152             KMType.INVALID_VALUE,
1153             false);
1154     temp =
1155         KMKeymasterApplet.encodeToApduBuffer(
1156             coseKey, scratchPad, (short) 0, KMKeymasterApplet.MAX_COSE_BUF_SIZE);
1157     // Construct payload.
1158     short payload =
1159         KMCose.constructCoseCertPayload(
1160             KMCosePairTextStringTag.instance(
1161                 KMInteger.uint_8(KMCose.ISSUER),
1162                 KMTextString.instance(
1163                     KMCose.TEST_ISSUER_NAME, (short) 0, (short) KMCose.TEST_ISSUER_NAME.length)),
1164             KMCosePairTextStringTag.instance(
1165                 KMInteger.uint_8(KMCose.SUBJECT),
1166                 KMTextString.instance(
1167                     KMCose.TEST_SUBJECT_NAME, (short) 0, (short) KMCose.TEST_SUBJECT_NAME.length)),
1168             KMCosePairByteBlobTag.instance(
1169                 KMNInteger.uint_32(KMCose.SUBJECT_PUBLIC_KEY, (short) 0),
1170                 KMByteBlob.instance(scratchPad, (short) 0, temp)),
1171             KMCosePairByteBlobTag.instance(
1172                 KMNInteger.uint_32(KMCose.KEY_USAGE, (short) 0),
1173                 KMByteBlob.instance(
1174                     KMCose.KEY_USAGE_SIGN, (short) 0, (short) KMCose.KEY_USAGE_SIGN.length)));
1175     // temp temporarily holds the length of encoded cert payload.
1176     temp =
1177         KMKeymasterApplet.encodeToApduBuffer(
1178             payload, scratchPad, (short) 0, KMKeymasterApplet.MAX_COSE_BUF_SIZE);
1179     payload = KMByteBlob.instance(scratchPad, (short) 0, temp);
1180 
1181     // protected header
1182     short protectedHeader =
1183         KMCose.constructHeaders(
1184             rkp.rkpTmpVariables,
1185             KMNInteger.uint_8(KMCose.COSE_ALG_ES256),
1186             KMType.INVALID_VALUE,
1187             KMType.INVALID_VALUE,
1188             KMType.INVALID_VALUE);
1189     // temp temporarily holds the length of encoded headers.
1190     temp =
1191         KMKeymasterApplet.encodeToApduBuffer(
1192             protectedHeader, scratchPad, (short) 0, KMKeymasterApplet.MAX_COSE_BUF_SIZE);
1193     protectedHeader = KMByteBlob.instance(scratchPad, (short) 0, temp);
1194 
1195     // unprotected headers.
1196     short arr = KMArray.instance((short) 0);
1197     short unprotectedHeader = KMCoseHeaders.instance(arr);
1198 
1199     // construct cose sign structure.
1200     short coseSignStructure =
1201         KMCose.constructCoseSignStructure(protectedHeader, KMByteBlob.instance((short) 0), payload);
1202     // temp temporarily holds the length of encoded sign structure.
1203     // Encode cose Sign_Structure.
1204     temp =
1205         KMKeymasterApplet.encodeToApduBuffer(
1206             coseSignStructure, scratchPad, (short) 0, KMKeymasterApplet.MAX_COSE_BUF_SIZE);
1207     // do sign
1208     short len =
1209         seProvider.signWithDeviceUniqueKey(
1210             deviceUniqueKey, scratchPad, (short) 0, temp, scratchPad, temp);
1211     len =
1212         KMAsn1Parser.instance()
1213             .decodeEcdsa256Signature(KMByteBlob.instance(scratchPad, temp, len), scratchPad, temp);
1214     coseSignStructure = KMByteBlob.instance(scratchPad, temp, len);
1215 
1216     // construct cose_sign1
1217     short coseSign1 =
1218         KMCose.constructCoseSign1(protectedHeader, unprotectedHeader, payload, coseSignStructure);
1219 
1220     // [Cose_Key, Cose_Sign1]
1221     short bcc = KMArray.instance((short) 2);
1222     KMArray.cast(bcc).add((short) 0, coseKey);
1223     KMArray.cast(bcc).add((short) 1, coseSign1);
1224     return bcc;
1225   }
1226 
initHmacNonceAndSeed()1227   protected void initHmacNonceAndSeed() {
1228     short nonce = repository.alloc((short) 32);
1229     seProvider.newRandomNumber(
1230         repository.getHeap(), nonce, KMKeymintDataStore.HMAC_SEED_NONCE_SIZE);
1231     kmDataStore.initHmacNonce(repository.getHeap(), nonce, KMKeymintDataStore.HMAC_SEED_NONCE_SIZE);
1232   }
1233 
releaseAllOperations()1234   private void releaseAllOperations() {
1235     short index = 0;
1236     while (index < MAX_OPERATIONS_COUNT) {
1237       opTable[index].reset();
1238       index++;
1239     }
1240   }
1241 
reserveOperation(short algorithm, short opHandle)1242   private KMOperationState reserveOperation(short algorithm, short opHandle) {
1243     short index = 0;
1244     while (index < MAX_OPERATIONS_COUNT) {
1245       if (opTable[index].getAlgorithm() == KMType.INVALID_VALUE) {
1246         opTable[index].reset();
1247         opTable[index].setAlgorithm(algorithm);
1248         opTable[index].setHandle(
1249             KMInteger.cast(opHandle).getBuffer(),
1250             KMInteger.cast(opHandle).getStartOff(),
1251             KMInteger.cast(opHandle).length());
1252         return opTable[index];
1253       }
1254       index++;
1255     }
1256     return null;
1257   }
1258 
findOperation(short handle)1259   private KMOperationState findOperation(short handle) {
1260     return findOperation(
1261         KMInteger.cast(handle).getBuffer(),
1262         KMInteger.cast(handle).getStartOff(),
1263         KMInteger.cast(handle).length());
1264   }
1265 
findOperation(byte[] opHandle, short start, short len)1266   private KMOperationState findOperation(byte[] opHandle, short start, short len) {
1267     short index = 0;
1268     while (index < MAX_OPERATIONS_COUNT) {
1269       if (opTable[index].compare(opHandle, start, len) == 0) {
1270         if (opTable[index].getAlgorithm() != KMType.INVALID_VALUE) {
1271           return opTable[index];
1272         }
1273       }
1274       index++;
1275     }
1276     return null;
1277   }
1278 
releaseOperation(KMOperationState op)1279   private void releaseOperation(KMOperationState op) {
1280     op.reset();
1281   }
1282 
1283   /**
1284    * Selects this applet.
1285    *
1286    * @return Returns true if the keymaster is in correct state
1287    */
1288   @Override
select()1289   public boolean select() {
1290     repository.onSelect();
1291     return true;
1292   }
1293 
1294   /** De-selects this applet. */
1295   @Override
deselect()1296   public void deselect() {
1297     repository.onDeselect();
1298   }
1299 
1300   /** Uninstalls the applet after cleaning the repository. */
1301   @Override
uninstall()1302   public void uninstall() {
1303     repository.onUninstall();
1304   }
1305 
mapISOErrorToKMError(short reason)1306   protected short mapISOErrorToKMError(short reason) {
1307     switch (reason) {
1308       case ISO7816.SW_CLA_NOT_SUPPORTED:
1309         return KMError.UNSUPPORTED_CLA;
1310       case ISO7816.SW_CONDITIONS_NOT_SATISFIED:
1311         return KMError.SW_CONDITIONS_NOT_SATISFIED;
1312       case ISO7816.SW_COMMAND_NOT_ALLOWED:
1313         return KMError.CMD_NOT_ALLOWED;
1314       case ISO7816.SW_DATA_INVALID:
1315         return KMError.INVALID_DATA;
1316       case ISO7816.SW_INCORRECT_P1P2:
1317         return KMError.INVALID_P1P2;
1318       case ISO7816.SW_INS_NOT_SUPPORTED:
1319         return KMError.UNSUPPORTED_INSTRUCTION;
1320       case ISO7816.SW_WRONG_LENGTH:
1321         return KMError.SW_WRONG_LENGTH;
1322       case ISO7816.SW_UNKNOWN:
1323       default:
1324         return KMError.UNKNOWN_ERROR;
1325     }
1326   }
1327 
mapCryptoErrorToKMError(short reason)1328   protected short mapCryptoErrorToKMError(short reason) {
1329     switch (reason) {
1330       case CryptoException.ILLEGAL_USE:
1331         return KMError.CRYPTO_ILLEGAL_USE;
1332       case CryptoException.ILLEGAL_VALUE:
1333         return KMError.CRYPTO_ILLEGAL_VALUE;
1334       case CryptoException.INVALID_INIT:
1335         return KMError.CRYPTO_INVALID_INIT;
1336       case CryptoException.NO_SUCH_ALGORITHM:
1337         return KMError.CRYPTO_NO_SUCH_ALGORITHM;
1338       case CryptoException.UNINITIALIZED_KEY:
1339         return KMError.CRYPTO_UNINITIALIZED_KEY;
1340       default:
1341         return KMError.UNKNOWN_ERROR;
1342     }
1343   }
1344 
updateApduStatusFlags(short apduIns)1345   public void updateApduStatusFlags(short apduIns) {
1346     switch (apduIns) {
1347       case INS_EXPORT_KEY_CMD:
1348       case INS_DELETE_ALL_KEYS_CMD:
1349       case INS_DESTROY_ATT_IDS_CMD:
1350       case INS_VERIFY_AUTHORIZATION_CMD:
1351       case INS_GET_HMAC_SHARING_PARAM_CMD:
1352       case INS_GET_HW_INFO_CMD:
1353       case INS_EARLY_BOOT_ENDED_CMD:
1354       case INS_GET_ROT_CHALLENGE_CMD:
1355       case INS_GET_ROT_DATA_CMD:
1356       case INS_GET_RKP_HARDWARE_INFO:
1357       case INS_FINISH_SEND_DATA_CMD:
1358       case INS_GET_RESPONSE_CMD:
1359         apduStatusFlags[APDU_CASE4_COMMAND_STATUS_INDEX] = 0;
1360         break;
1361       default:
1362         // By default the instruction is set to case 4 command instruction.
1363         break;
1364     }
1365   }
1366 
1367   /**
1368    * Processes an incoming APDU and handles it using command objects.
1369    *
1370    * @param apdu the incoming APDU
1371    */
1372   @Override
process(APDU apdu)1373   public void process(APDU apdu) {
1374     try {
1375       resetTransientBuffers();
1376       repository.onProcess();
1377       // If this is select applet apdu which is selecting this applet then return
1378       if (apdu.isISOInterindustryCLA()) {
1379         if (selectingApplet()) {
1380           return;
1381         }
1382       }
1383       byte[] apduBuffer = apdu.getBuffer();
1384       byte apduIns = apduBuffer[ISO7816.OFFSET_INS];
1385       if (!isKeyMintReady(apduIns)) {
1386         ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED);
1387       }
1388       switch (apduIns) {
1389         case INS_INIT_STRONGBOX_CMD:
1390           processInitStrongBoxCmd(apdu);
1391           sendResponse(apdu, KMError.OK);
1392           return;
1393         case INS_GENERATE_KEY_CMD:
1394           processGenerateKey(apdu);
1395           break;
1396         case INS_IMPORT_KEY_CMD:
1397           processImportKeyCmd(apdu);
1398           break;
1399         case INS_BEGIN_IMPORT_WRAPPED_KEY_CMD:
1400           processBeginImportWrappedKeyCmd(apdu);
1401           break;
1402         case INS_FINISH_IMPORT_WRAPPED_KEY_CMD:
1403           processFinishImportWrappedKeyCmd(apdu);
1404           break;
1405         case INS_EXPORT_KEY_CMD:
1406           processExportKeyCmd(apdu);
1407           break;
1408         case INS_UPGRADE_KEY_CMD:
1409           processUpgradeKeyCmd(apdu);
1410           break;
1411         case INS_DELETE_KEY_CMD:
1412           processDeleteKeyCmd(apdu);
1413           break;
1414         case INS_DELETE_ALL_KEYS_CMD:
1415           processDeleteAllKeysCmd(apdu);
1416           break;
1417         case INS_ADD_RNG_ENTROPY_CMD:
1418           processAddRngEntropyCmd(apdu);
1419           break;
1420         case INS_COMPUTE_SHARED_HMAC_CMD:
1421           processComputeSharedHmacCmd(apdu);
1422           break;
1423         case INS_DESTROY_ATT_IDS_CMD:
1424           processDestroyAttIdsCmd(apdu);
1425           break;
1426         case INS_VERIFY_AUTHORIZATION_CMD:
1427           processVerifyAuthorizationCmd(apdu);
1428           break;
1429         case INS_GET_HMAC_SHARING_PARAM_CMD:
1430           processGetHmacSharingParamCmd(apdu);
1431           break;
1432         case INS_GET_KEY_CHARACTERISTICS_CMD:
1433           processGetKeyCharacteristicsCmd(apdu);
1434           break;
1435         case INS_GET_HW_INFO_CMD:
1436           processGetHwInfoCmd(apdu);
1437           break;
1438         case INS_BEGIN_OPERATION_CMD:
1439           processBeginOperationCmd(apdu);
1440           break;
1441         case INS_UPDATE_OPERATION_CMD:
1442           processUpdateOperationCmd(apdu);
1443           break;
1444         case INS_FINISH_OPERATION_CMD:
1445           processFinishOperationCmd(apdu);
1446           break;
1447         case INS_ABORT_OPERATION_CMD:
1448           processAbortOperationCmd(apdu);
1449           break;
1450         case INS_DEVICE_LOCKED_CMD:
1451           processDeviceLockedCmd(apdu);
1452           break;
1453         case INS_EARLY_BOOT_ENDED_CMD:
1454           processEarlyBootEndedCmd(apdu);
1455           break;
1456         case INS_UPDATE_AAD_OPERATION_CMD:
1457           processUpdateAadOperationCmd(apdu);
1458           break;
1459         case INS_GENERATE_RKP_KEY_CMD:
1460         case INS_BEGIN_SEND_DATA_CMD:
1461         case INS_UPDATE_CHALLENGE_CMD:
1462         case INS_UPDATE_EEK_CHAIN_CMD:
1463         case INS_UPDATE_KEY_CMD:
1464         case INS_FINISH_SEND_DATA_CMD:
1465         case INS_GET_RESPONSE_CMD:
1466         case INS_GET_RKP_HARDWARE_INFO:
1467           rkp.process(apduIns, apdu);
1468           break;
1469           // KeyMint 2.0
1470         case INS_GET_ROT_CHALLENGE_CMD:
1471           processGetRootOfTrustChallenge(apdu);
1472           break;
1473         case INS_GET_ROT_DATA_CMD:
1474           sendResponse(apdu, KMError.UNIMPLEMENTED);
1475           break;
1476         case INS_SEND_ROT_DATA_CMD:
1477           processSendRootOfTrust(apdu);
1478           break;
1479         default:
1480           ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
1481       }
1482     } catch (KMException exception) {
1483       freeOperations();
1484       resetWrappingKey();
1485       sendResponse(apdu, KMException.reason());
1486     } catch (ISOException exp) {
1487       freeOperations();
1488       resetWrappingKey();
1489       sendResponse(apdu, mapISOErrorToKMError(exp.getReason()));
1490     } catch (CryptoException e) {
1491       freeOperations();
1492       resetWrappingKey();
1493       sendResponse(apdu, mapCryptoErrorToKMError(e.getReason()));
1494     } catch (Exception e) {
1495       freeOperations();
1496       resetWrappingKey();
1497       sendResponse(apdu, KMError.GENERIC_UNKNOWN_ERROR);
1498     } finally {
1499       repository.clean();
1500     }
1501   }
1502 
processGetRootOfTrustChallenge(APDU apdu)1503   private void processGetRootOfTrustChallenge(APDU apdu) {
1504     byte[] scratchpad = apdu.getBuffer();
1505     // Generate 16-byte random challenge nonce, used to prove freshness when exchanging root of
1506     // trust data.
1507     seProvider.newRandomNumber(scratchpad, (short) 0, (short) 16);
1508     kmDataStore.setChallenge(scratchpad, (short) 0, (short) 16);
1509     short challenge = KMByteBlob.instance(scratchpad, (short) 0, (short) 16);
1510     short arr = KMArray.instance((short) 2);
1511     KMArray.cast(arr).add((short) 0, KMInteger.uint_16(KMError.OK));
1512     KMArray.cast(arr).add((short) 1, challenge);
1513     sendOutgoing(apdu, arr);
1514   }
1515 
sendRootOfTrustCmd(APDU apdu)1516   private short sendRootOfTrustCmd(APDU apdu) {
1517     short arrInst = KMArray.instance((short) 4);
1518     short headers = KMCoseHeaders.exp();
1519     KMArray.cast(arrInst).add((short) 0, KMByteBlob.exp());
1520     KMArray.cast(arrInst).add((short) 1, headers);
1521     KMArray.cast(arrInst).add((short) 2, KMByteBlob.exp());
1522     KMArray.cast(arrInst).add((short) 3, KMByteBlob.exp());
1523     short semanticTag = KMSemanticTag.exp(arrInst);
1524     short arr = KMArray.exp(semanticTag);
1525     return receiveIncoming(apdu, arr);
1526   }
1527 
processSendRootOfTrust(APDU apdu)1528   private void processSendRootOfTrust(APDU apdu) {
1529     byte[] scratchPad = apdu.getBuffer();
1530     short cmd = KMType.INVALID_VALUE;
1531     // As per VTS if the input data is empty or not well-formed
1532     // CoseMac return VERIFICATION_FAILED error.
1533     try {
1534       cmd = sendRootOfTrustCmd(apdu);
1535     } catch (Exception e) {
1536       KMException.throwIt(KMError.VERIFICATION_FAILED);
1537     }
1538 
1539     short semanticTag = KMArray.cast(cmd).get((short) 0);
1540     short coseMacPtr = KMSemanticTag.cast(semanticTag).getValuePtr();
1541     // Exp for KMCoseHeaders
1542     short coseHeadersExp = KMCoseHeaders.exp();
1543     // validate protected Headers
1544     short ptr = KMArray.cast(coseMacPtr).get(KMCose.COSE_MAC0_PROTECTED_PARAMS_OFFSET);
1545     ptr =
1546         decoder.decode(
1547             coseHeadersExp,
1548             KMByteBlob.cast(ptr).getBuffer(),
1549             KMByteBlob.cast(ptr).getStartOff(),
1550             KMByteBlob.cast(ptr).length());
1551 
1552     if (!KMCoseHeaders.cast(ptr)
1553         .isDataValid(tmpVariables, KMCose.COSE_ALG_HMAC_256, KMType.INVALID_VALUE)) {
1554       KMException.throwIt(KMError.VERIFICATION_FAILED);
1555     }
1556 
1557     // Validate the Mac
1558     short len = kmDataStore.getChallenge(scratchPad, (short) 0);
1559     short extAad = KMByteBlob.instance(scratchPad, (short) 0, len);
1560     // Compute CoseMac Structure and compare the macs.
1561     short rotPayload = KMArray.cast(coseMacPtr).get(KMCose.COSE_MAC0_PAYLOAD_OFFSET);
1562     short macStructure =
1563         KMCose.constructCoseMacStructure(
1564             KMArray.cast(coseMacPtr).get(KMCose.COSE_MAC0_PROTECTED_PARAMS_OFFSET),
1565             extAad,
1566             rotPayload);
1567     short encodedLen =
1568         KMKeymasterApplet.encodeToApduBuffer(
1569             macStructure, scratchPad, (short) 0, KMKeymasterApplet.MAX_COSE_BUF_SIZE);
1570 
1571     if (!seProvider.hmacVerify(
1572         kmDataStore.getComputedHmacKey(),
1573         scratchPad,
1574         (short) 0,
1575         encodedLen,
1576         KMByteBlob.cast(KMArray.cast(coseMacPtr).get(KMCose.COSE_MAC0_TAG_OFFSET)).getBuffer(),
1577         KMByteBlob.cast(KMArray.cast(coseMacPtr).get(KMCose.COSE_MAC0_TAG_OFFSET)).getStartOff(),
1578         KMByteBlob.cast(KMArray.cast(coseMacPtr).get(KMCose.COSE_MAC0_TAG_OFFSET)).length())) {
1579       KMException.throwIt(KMError.VERIFICATION_FAILED);
1580     }
1581     // Store the data only once after reboot.
1582     // Allow set boot params only when the host device reboots and the applet is in
1583     // active state. If host does not support boot signal event, then allow this
1584     // instruction any time.
1585     kmDataStore.getDeviceBootStatus(scratchPad, (short) 0);
1586     if (((scratchPad[0] & KMKeymintDataStore.SET_BOOT_PARAMS_SUCCESS) == 0)) {
1587       // store the data.
1588       storeRootOfTrust(rotPayload, scratchPad);
1589       kmDataStore.setDeviceBootStatus(KMKeymintDataStore.SET_BOOT_PARAMS_SUCCESS);
1590     }
1591     // Invalidate the challenge
1592     Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 16, (byte) 0);
1593     kmDataStore.setChallenge(scratchPad, (short) 0, (short) 16);
1594     sendResponse(apdu, KMError.OK);
1595   }
1596 
storeRootOfTrust(short rotPayload, byte[] scratchPad)1597   private void storeRootOfTrust(short rotPayload, byte[] scratchPad) {
1598     short byteBlobExp = KMByteBlob.exp();
1599     short intExp = KMInteger.exp();
1600     short boolExp = KMSimpleValue.exp();
1601     short arr = KMArray.instance((short) 5);
1602     KMArray.cast(arr).add((short) 0, byteBlobExp); // Verfied boot key.
1603     KMArray.cast(arr).add((short) 1, boolExp); // deviceLocked.
1604     KMArray.cast(arr).add((short) 2, intExp); // Verified Boot State.
1605     KMArray.cast(arr).add((short) 3, byteBlobExp); // Verfied boot hash.
1606     KMArray.cast(arr).add((short) 4, intExp); // Boot patch level
1607     short semanticExp = KMSemanticTag.exp(arr);
1608 
1609     short semanticPtr =
1610         decoder.decode(
1611             semanticExp,
1612             KMByteBlob.cast(rotPayload).getBuffer(),
1613             KMByteBlob.cast(rotPayload).getStartOff(),
1614             KMByteBlob.cast(rotPayload).length());
1615     short rotArr = KMSemanticTag.cast(semanticPtr).getValuePtr();
1616     // Store verified boot key
1617     short ptr = KMArray.cast(rotArr).get((short) 0);
1618     kmDataStore.setBootKey(
1619         KMByteBlob.cast(ptr).getBuffer(),
1620         KMByteBlob.cast(ptr).getStartOff(),
1621         KMByteBlob.cast(ptr).length());
1622     // Store Boot device locked.
1623     ptr = KMArray.cast(rotArr).get((short) 1);
1624     kmDataStore.setDeviceLocked(
1625         (KMSimpleValue.cast(ptr).getValue() == KMSimpleValue.TRUE) ? true : false);
1626     // Store verified boot state
1627     ptr = KMArray.cast(rotArr).get((short) 2);
1628     kmDataStore.setBootState(KMInteger.cast(ptr).getShort());
1629     // Store Verified boot hash
1630     ptr = KMArray.cast(rotArr).get((short) 3);
1631     kmDataStore.setVerifiedBootHash(
1632         KMByteBlob.cast(ptr).getBuffer(),
1633         KMByteBlob.cast(ptr).getStartOff(),
1634         KMByteBlob.cast(ptr).length());
1635     // Store boot patch level
1636     ptr = KMArray.cast(rotArr).get((short) 4);
1637     kmDataStore.setBootPatchLevel(
1638         KMInteger.cast(ptr).getBuffer(),
1639         KMInteger.cast(ptr).getStartOff(),
1640         KMInteger.cast(ptr).length());
1641   }
1642 
1643   // After every device boot, the Keymaster becomes ready to execute all the commands only after
1644   // 1. boot parameters are set,
1645   // 2. system properties are set and
1646   // 3. computed the shared secret successfully.
isKeyMintReady(byte apduIns)1647   private boolean isKeyMintReady(byte apduIns) {
1648     if (kmDataStore.isDeviceReady()) {
1649       return true;
1650     }
1651     // Below commands are allowed even if the Keymaster is not ready.
1652     switch (apduIns) {
1653       case INS_GET_HW_INFO_CMD:
1654       case INS_GET_RKP_HARDWARE_INFO:
1655       case INS_ADD_RNG_ENTROPY_CMD:
1656       case INS_GET_HMAC_SHARING_PARAM_CMD:
1657       case INS_COMPUTE_SHARED_HMAC_CMD:
1658       case INS_EARLY_BOOT_ENDED_CMD:
1659       case INS_DELETE_ALL_KEYS_CMD:
1660       case INS_INIT_STRONGBOX_CMD:
1661       case INS_GET_ROT_CHALLENGE_CMD:
1662       case INS_SEND_ROT_DATA_CMD:
1663         return true;
1664       default:
1665         break;
1666     }
1667     return false;
1668   }
1669 
generateUniqueOperationHandle(byte[] buf, short offset, short len)1670   private void generateUniqueOperationHandle(byte[] buf, short offset, short len) {
1671     do {
1672       seProvider.newRandomNumber(buf, offset, len);
1673     } while (null != findOperation(buf, offset, len));
1674   }
1675 
freeOperations()1676   private void freeOperations() {
1677     if (data[OP_HANDLE] != KMType.INVALID_VALUE) {
1678       KMOperationState op = findOperation(data[OP_HANDLE]);
1679       if (op != null) {
1680         releaseOperation(op);
1681       }
1682     }
1683   }
1684 
processEarlyBootEndedCmd(APDU apdu)1685   private void processEarlyBootEndedCmd(APDU apdu) {
1686     kmDataStore.setEarlyBootEndedStatus(true);
1687     sendResponse(apdu, KMError.OK);
1688   }
1689 
deviceLockedCmd(APDU apdu)1690   private short deviceLockedCmd(APDU apdu) {
1691     short cmd = KMArray.instance((short) 2);
1692     short ptr = KMVerificationToken.exp();
1693     // passwordOnly
1694     KMArray.cast(cmd).add((short) 0, KMInteger.exp());
1695     // verification token
1696     KMArray.cast(cmd).add((short) 1, ptr);
1697     return receiveIncoming(apdu, cmd);
1698   }
1699 
processDeviceLockedCmd(APDU apdu)1700   private void processDeviceLockedCmd(APDU apdu) {
1701     short cmd = deviceLockedCmd(apdu);
1702     byte[] scratchPad = apdu.getBuffer();
1703     short passwordOnly = KMArray.cast(cmd).get((short) 0);
1704     short verToken = KMArray.cast(cmd).get((short) 1);
1705     passwordOnly = KMInteger.cast(passwordOnly).getByte();
1706     validateVerificationToken(verToken, scratchPad);
1707     short verTime = KMVerificationToken.cast(verToken).getTimestamp();
1708     short lastDeviceLockedTime;
1709     try {
1710       lastDeviceLockedTime = kmDataStore.getDeviceTimeStamp();
1711     } catch (KMException e) {
1712       lastDeviceLockedTime = KMInteger.uint_8((byte) 0);
1713     }
1714     if (KMInteger.compare(verTime, lastDeviceLockedTime) > 0) {
1715       Util.arrayFillNonAtomic(scratchPad, (short) 0, KMInteger.UINT_64, (byte) 0);
1716       KMInteger.cast(verTime).getValue(scratchPad, (short) 0, KMInteger.UINT_64);
1717       kmDataStore.setDeviceLock(true);
1718       kmDataStore.setDeviceLockPasswordOnly(passwordOnly == 0x01);
1719       kmDataStore.setDeviceLockTimestamp(scratchPad, (short) 0, KMInteger.UINT_64);
1720     }
1721     sendResponse(apdu, KMError.OK);
1722   }
1723 
resetWrappingKey()1724   private void resetWrappingKey() {
1725     if (!isValidWrappingKey()) {
1726       return;
1727     }
1728     Util.arrayFillNonAtomic(wrappingKey, (short) 1, WRAPPING_KEY_SIZE, (byte) 0);
1729     wrappingKey[0] = -1;
1730   }
1731 
isValidWrappingKey()1732   private boolean isValidWrappingKey() {
1733     return wrappingKey[0] != -1;
1734   }
1735 
getWrappingKey()1736   private short getWrappingKey() {
1737     return KMByteBlob.instance(wrappingKey, (short) 1, WRAPPING_KEY_SIZE);
1738   }
1739 
setWrappingKey(short key)1740   private void setWrappingKey(short key) {
1741     if (KMByteBlob.cast(key).length() != WRAPPING_KEY_SIZE) {
1742       KMException.throwIt(KMError.UNKNOWN_ERROR);
1743     }
1744     wrappingKey[0] = 0;
1745     Util.arrayCopyNonAtomic(
1746         KMByteBlob.cast(key).getBuffer(),
1747         KMByteBlob.cast(key).getStartOff(),
1748         wrappingKey,
1749         (short) 1,
1750         WRAPPING_KEY_SIZE);
1751   }
1752 
resetTransientBuffers()1753   protected void resetTransientBuffers() {
1754     short index = 0;
1755     while (index < data.length) {
1756       data[index] = KMType.INVALID_VALUE;
1757       index++;
1758     }
1759     index = 0;
1760     while (index < tmpVariables.length) {
1761       tmpVariables[index] = KMType.INVALID_VALUE;
1762       index++;
1763     }
1764   }
1765 
sendOutgoing( APDU apdu, KMAttestationCert cert, short certStart, short keyblob, short keyChars)1766   public void sendOutgoing(
1767       APDU apdu, KMAttestationCert cert, short certStart, short keyblob, short keyChars) {
1768     // This is the special case where the output is encoded manually without using
1769     // the encoder algorithm. Encoder creates a duplicate copy for each KMType Object.
1770     // The output of the generateKey, importKey and importWrappedKey commands are huge so
1771     // by manually encoding we can avoid duplicate copies.
1772     // The output data is directly written to the end of heap in the below order
1773     // output = [
1774     //     errorCode  : uint // ErrorCode
1775     //     keyBlob    : bstr // KeyBlob.
1776     //     keyChars
1777     //     certifcate
1778     // ]
1779     // certificate = [
1780     //     x509_cert : bstr // X509 certificate
1781     // ]
1782     // keyChars = {  // Map
1783     // }
1784     byte[] buffer = repository.getHeap();
1785 
1786     if (cert == null) {
1787       // This happens for Symmetric keys.
1788       short bufferStart = repository.allocReclaimableMemory((short) 1);
1789       buffer[bufferStart] = (byte) 0x80; // Array of 0 length.
1790     } else {
1791       // Encode the certificate into cbor data at the end of the heap
1792       // certData = [
1793       //     x509_cert : bstr // X509 certificate
1794       // ]
1795       short bufferStart =
1796           encoder.encodeCert(
1797               repository.getHeap(), certStart, cert.getCertStart(), cert.getCertLength());
1798       // reclaim the unused memory in the certificate.
1799       repository.reclaimMemory((short) (bufferStart - certStart));
1800     }
1801 
1802     // Encode KeyCharacteristics at the end of heap just before data[CERTIFICATE]
1803     encodeKeyCharacteristics(keyChars);
1804     // and encode it to the end of the buffer before KEY_CHARACTERISTICS
1805     encodeKeyBlob(keyblob);
1806     // Write Array header and ErrorCode before data[KEY_BLOB]
1807     short bufferStartOffset = repository.allocReclaimableMemory((short) 2);
1808     Util.setShort(buffer, bufferStartOffset, (short) 0x8400);
1809 
1810     short bufferLength = (short) (KMRepository.HEAP_SIZE - bufferStartOffset);
1811     /* In T=0 protocol, On a case 4 command, setIncomingAndReceive() must
1812      * be invoked prior to calling setOutgoing(). Otherwise, erroneous
1813      * behavior may result
1814      * */
1815     if (apduStatusFlags[APDU_CASE4_COMMAND_STATUS_INDEX] == 1
1816         && apduStatusFlags[APDU_INCOMING_AND_RECEIVE_STATUS_INDEX] == 0
1817         && APDU.getProtocol() == APDU.PROTOCOL_T0) {
1818       apdu.setIncomingAndReceive();
1819     }
1820     // Send data
1821     apdu.setOutgoing();
1822     apdu.setOutgoingLength(bufferLength);
1823     apdu.sendBytesLong(buffer, bufferStartOffset, bufferLength);
1824   }
1825 
processGetHwInfoCmd(APDU apdu)1826   private void processGetHwInfoCmd(APDU apdu) {
1827     // No arguments expected
1828     final byte version = 2;
1829     // Make the response
1830     short respPtr = KMArray.instance((short) 6);
1831     KMArray resp = KMArray.cast(respPtr);
1832     resp.add((short) 0, KMInteger.uint_16(KMError.OK));
1833     resp.add((short) 1, KMInteger.uint_8(version));
1834     resp.add((short) 2, KMEnum.instance(KMType.HARDWARE_TYPE, KMType.STRONGBOX));
1835     resp.add(
1836         (short) 3,
1837         KMByteBlob.instance(
1838             JavacardKeymintDevice, (short) 0, (short) JavacardKeymintDevice.length));
1839     resp.add((short) 4, KMByteBlob.instance(Google, (short) 0, (short) Google.length));
1840     resp.add((short) 5, KMInteger.uint_8((byte) 1));
1841     // send buffer to host
1842     sendOutgoing(apdu, respPtr);
1843   }
1844 
addRngEntropyCmd(APDU apdu)1845   private short addRngEntropyCmd(APDU apdu) {
1846     short cmd = KMArray.instance((short) 1);
1847     // Rng entropy
1848     KMArray.cast(cmd).add((short) 0, KMByteBlob.exp());
1849     return receiveIncoming(apdu, cmd);
1850   }
1851 
processAddRngEntropyCmd(APDU apdu)1852   private void processAddRngEntropyCmd(APDU apdu) {
1853     // Receive the incoming request fully from the host.
1854     short cmd = addRngEntropyCmd(apdu);
1855     // Process
1856     KMByteBlob blob = KMByteBlob.cast(KMArray.cast(cmd).get((short) 0));
1857     // Maximum 2KiB of seed is allowed.
1858     if (blob.length() > MAX_SEED_SIZE) {
1859       KMException.throwIt(KMError.INVALID_INPUT_LENGTH);
1860     }
1861     seProvider.addRngEntropy(blob.getBuffer(), blob.getStartOff(), blob.length());
1862     sendResponse(apdu, KMError.OK);
1863   }
1864 
getKeyCharacteristicsCmd(APDU apdu)1865   private short getKeyCharacteristicsCmd(APDU apdu) {
1866     short cmd = KMArray.instance((short) 3);
1867     KMArray.cast(cmd).add((short) 0, KMByteBlob.exp());
1868     KMArray.cast(cmd).add((short) 1, KMByteBlob.exp());
1869     KMArray.cast(cmd).add((short) 2, KMByteBlob.exp());
1870     return receiveIncoming(apdu, cmd);
1871   }
1872 
processGetKeyCharacteristicsCmd(APDU apdu)1873   private void processGetKeyCharacteristicsCmd(APDU apdu) {
1874     // Receive the incoming request fully from the host.
1875     short cmd = getKeyCharacteristicsCmd(apdu);
1876     // Re-purpose the apdu buffer as scratch pad.
1877     byte[] scratchPad = apdu.getBuffer();
1878     data[KEY_BLOB] = KMArray.cast(cmd).get((short) 0);
1879     data[APP_ID] = KMArray.cast(cmd).get((short) 1);
1880     data[APP_DATA] = KMArray.cast(cmd).get((short) 2);
1881     if (KMByteBlob.cast(data[APP_ID]).length() > KMByteTag.MAX_APP_ID_APP_DATA_SIZE
1882         || KMByteBlob.cast(data[APP_DATA]).length() > KMByteTag.MAX_APP_ID_APP_DATA_SIZE) {
1883       ISOException.throwIt(ISO7816.SW_DATA_INVALID);
1884     }
1885     if (!KMByteBlob.cast(data[APP_ID]).isValid()) {
1886       data[APP_ID] = KMType.INVALID_VALUE;
1887     }
1888     if (!KMByteBlob.cast(data[APP_DATA]).isValid()) {
1889       data[APP_DATA] = KMType.INVALID_VALUE;
1890     }
1891     // Check if key requires upgrade. The KeyBlob is parsed inside isKeyUpgradeRequired
1892     // function itself.
1893     if (isKeyUpgradeRequired(data[KEY_BLOB], data[APP_ID], data[APP_DATA], scratchPad)) {
1894       KMException.throwIt(KMError.KEY_REQUIRES_UPGRADE);
1895     }
1896     // make response.
1897     short resp = KMArray.instance((short) 2);
1898     KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK));
1899     KMArray.cast(resp).add((short) 1, data[KEY_CHARACTERISTICS]);
1900     sendOutgoing(apdu, resp);
1901   }
1902 
processGetHmacSharingParamCmd(APDU apdu)1903   private void processGetHmacSharingParamCmd(APDU apdu) {
1904     // No Arguments
1905     // Create HMAC Sharing Parameters
1906     short params = KMHmacSharingParameters.instance();
1907     short nonce = kmDataStore.getHmacNonce();
1908     short seed = KMByteBlob.instance((short) 0);
1909     KMHmacSharingParameters.cast(params).setNonce(nonce);
1910     KMHmacSharingParameters.cast(params).setSeed(seed);
1911     // prepare the response
1912     short resp = KMArray.instance((short) 2);
1913     KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK));
1914     KMArray.cast(resp).add((short) 1, params);
1915     sendOutgoing(apdu, resp);
1916   }
1917 
processDeleteAllKeysCmd(APDU apdu)1918   private void processDeleteAllKeysCmd(APDU apdu) {
1919     // No arguments
1920     // This function is triggered when a factory reset event occurs.
1921     // Regenerate the master key to render all keys unusable.
1922     kmDataStore.regenerateMasterKey();
1923     // Send ok
1924     sendResponse(apdu, KMError.OK);
1925   }
1926 
createKeyBlobExp(short version)1927   private short createKeyBlobExp(short version) {
1928     short keyBlob = KMType.INVALID_VALUE;
1929     short byteBlobExp = KMByteBlob.exp();
1930     short keyChar = KMKeyCharacteristics.exp();
1931     short keyParam = KMKeyParameters.exp();
1932     switch (version) {
1933       case (short) 0:
1934         // Old KeyBlob has a maximum of 5 elements.
1935         keyBlob = KMArray.instance(ASYM_KEY_BLOB_SIZE_V0);
1936         KMArray.cast(keyBlob).add((short) 0, byteBlobExp); // Secret
1937         KMArray.cast(keyBlob).add((short) 1, byteBlobExp); // Nonce
1938         KMArray.cast(keyBlob).add((short) 2, byteBlobExp); // AuthTag
1939         KMArray.cast(keyBlob).add((short) 3, keyChar); // KeyChars
1940         KMArray.cast(keyBlob).add((short) 4, byteBlobExp); // PubKey
1941         break;
1942       case (short) 1:
1943         keyBlob = KMArray.instance(ASYM_KEY_BLOB_SIZE_V1);
1944         KMArray.cast(keyBlob).add((short) 0, KMInteger.exp()); // Version
1945         KMArray.cast(keyBlob).add((short) 1, byteBlobExp); // Secret
1946         KMArray.cast(keyBlob).add((short) 2, byteBlobExp); // Nonce
1947         KMArray.cast(keyBlob).add((short) 3, byteBlobExp); // AuthTag
1948         KMArray.cast(keyBlob).add((short) 4, keyChar); // KeyChars
1949         KMArray.cast(keyBlob).add((short) 5, byteBlobExp); // PubKey
1950         break;
1951       case (short) 2:
1952       case (short) 3:
1953         keyBlob = KMArray.instance(ASYM_KEY_BLOB_SIZE_V2_V3);
1954         KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_VERSION_OFFSET, KMInteger.exp());
1955         KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_SECRET, byteBlobExp);
1956         KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_AUTH_TAG, byteBlobExp);
1957         KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_NONCE, byteBlobExp);
1958         KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_PARAMS, keyChar);
1959         KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_CUSTOM_TAGS, keyParam);
1960         KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_PUB_KEY, byteBlobExp);
1961         break;
1962       default:
1963         KMException.throwIt(KMError.INVALID_KEY_BLOB);
1964     }
1965     return keyBlob;
1966   }
1967 
processDeleteKeyCmd(APDU apdu)1968   private void processDeleteKeyCmd(APDU apdu) {
1969     // Send ok
1970     sendResponse(apdu, KMError.OK);
1971   }
1972 
computeSharedHmacCmd(APDU apdu)1973   private short computeSharedHmacCmd(APDU apdu) {
1974     short params = KMHmacSharingParameters.exp();
1975     short paramsVec = KMArray.exp(params);
1976     short cmd = KMArray.instance((short) 1);
1977     KMArray.cast(cmd).add((short) 0, paramsVec);
1978     return receiveIncoming(apdu, cmd);
1979   }
1980 
processComputeSharedHmacCmd(APDU apdu)1981   private void processComputeSharedHmacCmd(APDU apdu) {
1982     // Receive the incoming request fully from the host into buffer.
1983     short cmd = computeSharedHmacCmd(apdu);
1984     byte[] scratchPad = apdu.getBuffer();
1985     data[HMAC_SHARING_PARAMS] = KMArray.cast(cmd).get((short) 0);
1986     // Concatenate HMAC Params
1987     // tmpVariables[0]
1988     short paramsLen = KMArray.cast(data[HMAC_SHARING_PARAMS]).length(); // total number of params
1989     // tmpVariables[1]
1990     short concateBuffer = repository.alloc((short) (paramsLen * HMAC_SHARED_PARAM_MAX_SIZE));
1991     // tmpVariables[2]
1992     short paramIndex = 0; // index for params
1993     // tmpVariables[3]
1994     short bufferIndex = 0; // index for concatenation buffer
1995     // To check if nonce created by Strongbox is found. This value becomes 1 if both
1996     // seed and nonce created here are found in hmac sharing parameters received.
1997     // tmpVariables[7] = 0;
1998     short found = 0;
1999     // tmpVariables[9]
2000     short nonce = kmDataStore.getHmacNonce();
2001 
2002     while (paramIndex < paramsLen) {
2003       // read HmacSharingParam
2004       // tmpVariables[4]
2005       short param = KMArray.cast(data[HMAC_SHARING_PARAMS]).get(paramIndex);
2006       // get seed - 32 bytes max
2007       // tmpVariables[5]
2008       short seed = KMHmacSharingParameters.cast(param).getSeed();
2009       // tmpVariables[6]
2010       short seedLength = KMByteBlob.cast(seed).length();
2011       // if seed is present
2012       if (seedLength != 0) {
2013         // then copy that to concatenation buffer
2014         Util.arrayCopyNonAtomic(
2015             KMByteBlob.cast(seed).getBuffer(),
2016             KMByteBlob.cast(seed).getStartOff(),
2017             repository.getHeap(),
2018             (short) (concateBuffer + bufferIndex), // concat index
2019             seedLength);
2020         bufferIndex += seedLength; // increment the concat index
2021       } else if (found == 0) {
2022         found = 1; // Applet does not have any seed. Potentially
2023       }
2024       // if nonce is present get nonce - 32 bytes
2025       // tmpVariables[5]
2026       short paramNonce = KMHmacSharingParameters.cast(param).getNonce();
2027       short nonceLen = KMByteBlob.cast(paramNonce).length();
2028       // if nonce is less then 32 - it is an error
2029       if (nonceLen < 32) {
2030         KMException.throwIt(KMError.INVALID_ARGUMENT);
2031       }
2032       // copy nonce to concatenation buffer
2033       Util.arrayCopyNonAtomic(
2034           KMByteBlob.cast(paramNonce).getBuffer(),
2035           KMByteBlob.cast(paramNonce).getStartOff(),
2036           repository.getHeap(),
2037           (short) (concateBuffer + bufferIndex), // index
2038           nonceLen);
2039 
2040       // Check if the nonce generated here is present in the hmacSharingParameters array.
2041       // Otherwise throw INVALID_ARGUMENT error.
2042       if (found == 1) {
2043         if (0
2044             == Util.arrayCompare(
2045                 repository.getHeap(),
2046                 (short) (concateBuffer + bufferIndex),
2047                 KMByteBlob.cast(nonce).getBuffer(),
2048                 KMByteBlob.cast(nonce).getStartOff(),
2049                 nonceLen)) {
2050           found = 2; // hmac nonce for this keymaster found.
2051         } else {
2052           found = 0;
2053         }
2054       }
2055       bufferIndex += nonceLen; // increment by nonce length
2056       paramIndex++; // go to next hmac param in the vector
2057     }
2058     if (found != 2) {
2059       KMException.throwIt(KMError.INVALID_ARGUMENT);
2060     }
2061     // generate the key and store it in scratch pad - 32 bytes
2062     // tmpVariables[6]
2063     short keyLen =
2064         seProvider.cmacKDF(
2065             kmDataStore.getPresharedKey(),
2066             ckdfLabel,
2067             (short) 0,
2068             (short) ckdfLabel.length,
2069             repository.getHeap(),
2070             concateBuffer,
2071             bufferIndex,
2072             scratchPad,
2073             (short) 0);
2074 
2075     // persist the computed hmac key.
2076     kmDataStore.createComputedHmacKey(scratchPad, (short) 0, keyLen);
2077     // Generate sharingKey verification signature and store that in scratch pad.
2078     // tmpVariables[5]
2079     short signLen =
2080         seProvider.hmacSign(
2081             scratchPad,
2082             (short) 0,
2083             keyLen,
2084             sharingCheck,
2085             (short) 0,
2086             (short) sharingCheck.length,
2087             scratchPad,
2088             keyLen);
2089     kmDataStore.setDeviceBootStatus(KMKeymintDataStore.NEGOTIATED_SHARED_SECRET_SUCCESS);
2090     // verification signature blob - 32 bytes
2091     // tmpVariables[1]
2092     short signature = KMByteBlob.instance(scratchPad, keyLen, signLen);
2093     // prepare the response
2094     short resp = KMArray.instance((short) 2);
2095     KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK));
2096     KMArray.cast(resp).add((short) 1, signature);
2097     sendOutgoing(apdu, resp);
2098   }
2099 
upgradeKeyCmd(APDU apdu)2100   private short upgradeKeyCmd(APDU apdu) {
2101     short cmd = KMArray.instance((short) 2);
2102     short keyParams = KMKeyParameters.exp();
2103     KMArray.cast(cmd).add((short) 0, KMByteBlob.exp()); // Key Blob
2104     KMArray.cast(cmd).add((short) 1, keyParams); // Key Params
2105     return receiveIncoming(apdu, cmd);
2106   }
2107 
isKeyUpgradeRequired( short keyBlob, short appId, short appData, byte[] scratchPad)2108   private boolean isKeyUpgradeRequired(
2109       short keyBlob, short appId, short appData, byte[] scratchPad) {
2110     // Check if the KeyBlob is compatible. If there is any change in the KeyBlob, the version
2111     // Parameter in the KeyBlob should be updated to the next version.
2112     short version = readKeyBlobVersion(keyBlob);
2113     parseEncryptedKeyBlob(keyBlob, appId, appData, scratchPad, version);
2114     if (version < KEYBLOB_CURRENT_VERSION) {
2115       return true;
2116     }
2117     short bootPatchLevel = kmDataStore.getBootPatchLevel();
2118     // Fill the key-value properties in the scratchpad
2119     Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 16, (byte) 0);
2120     Util.setShort(scratchPad, (short) 0, KMType.OS_VERSION);
2121     Util.setShort(scratchPad, (short) 2, kmDataStore.getOsVersion());
2122     Util.setShort(scratchPad, (short) 4, KMType.OS_PATCH_LEVEL);
2123     Util.setShort(scratchPad, (short) 6, kmDataStore.getOsPatch());
2124     Util.setShort(scratchPad, (short) 8, KMType.VENDOR_PATCH_LEVEL);
2125     Util.setShort(scratchPad, (short) 10, kmDataStore.getVendorPatchLevel());
2126     Util.setShort(scratchPad, (short) 12, KMType.BOOT_PATCH_LEVEL);
2127     Util.setShort(scratchPad, (short) 14, bootPatchLevel);
2128     short index = 0;
2129     short tag;
2130     short systemParam;
2131     boolean isKeyUpgradeRequired = false;
2132     while (index < 16) {
2133       tag = Util.getShort(scratchPad, index);
2134       systemParam = Util.getShort(scratchPad, (short) (index + 2));
2135       // validate the tag and check if key needs upgrade.
2136       short tagValue = KMKeyParameters.findTag(KMType.UINT_TAG, tag, data[HW_PARAMETERS]);
2137       tagValue = KMIntegerTag.cast(tagValue).getValue();
2138       short zero = KMInteger.uint_8((byte) 0);
2139       if (tagValue != KMType.INVALID_VALUE) {
2140         // OS version in key characteristics must be less the OS version stored in Javacard or the
2141         // stored version must be zero. Then only upgrade is allowed else it is invalid argument.
2142         if ((tag == KMType.OS_VERSION
2143             && KMInteger.compare(tagValue, systemParam) == 1
2144             && KMInteger.compare(systemParam, zero) == 0)) {
2145           // Key needs upgrade.
2146           isKeyUpgradeRequired = true;
2147         } else if ((KMInteger.compare(tagValue, systemParam) == -1)) {
2148           // Each os version or patch level associated with the key must be less than it's
2149           // corresponding value stored in Javacard, then only upgrade is allowed otherwise it
2150           // is invalid argument.
2151           isKeyUpgradeRequired = true;
2152         } else if (KMInteger.compare(tagValue, systemParam) == 1) {
2153           KMException.throwIt(KMError.INVALID_ARGUMENT);
2154         }
2155       } else {
2156         KMException.throwIt(KMError.UNKNOWN_ERROR);
2157       }
2158       index += 4;
2159     }
2160     return isKeyUpgradeRequired;
2161   }
2162 
processUpgradeKeyCmd(APDU apdu)2163   private void processUpgradeKeyCmd(APDU apdu) {
2164     // Receive the incoming request fully from the host into buffer.
2165     short cmd = upgradeKeyCmd(apdu);
2166     byte[] scratchPad = apdu.getBuffer();
2167 
2168     short keyBlob = KMArray.cast(cmd).get((short) 0);
2169     data[KEY_PARAMETERS] = KMArray.cast(cmd).get((short) 1);
2170     short appId = getApplicationId(data[KEY_PARAMETERS]);
2171     short appData = getApplicationData(data[KEY_PARAMETERS]);
2172 
2173     data[KEY_BLOB] = KMType.INVALID_VALUE;
2174     // Check if the KeyBlob requires upgrade. The KeyBlob is parsed inside isKeyUpgradeRequired
2175     // function itself, but if there is a difference in the KeyBlob version isKeyUpgradeRequired()
2176     // does not parse the KeyBlob.
2177     boolean isKeyUpgradeRequired = isKeyUpgradeRequired(keyBlob, appId, appData, scratchPad);
2178     if (isKeyUpgradeRequired) {
2179       // copy origin
2180       data[ORIGIN] = KMEnumTag.getValue(KMType.ORIGIN, data[HW_PARAMETERS]);
2181       byte keyType = getKeyType(data[HW_PARAMETERS]);
2182       switch (keyType) {
2183         case ASYM_KEY_TYPE:
2184           data[KEY_BLOB] = KMArray.instance(ASYM_KEY_BLOB_SIZE_V2_V3);
2185           KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_PUB_KEY, data[PUB_KEY]);
2186           break;
2187         case SYM_KEY_TYPE:
2188           data[KEY_BLOB] = KMArray.instance(SYM_KEY_BLOB_SIZE_V2_V3);
2189           break;
2190         default:
2191           KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM);
2192       }
2193       // Update the system properties to the latest values and also re-create the KeyBlob's
2194       // KeyCharacteristics to make sure all the values are up-to-date with the latest applet
2195       // changes.
2196       upgradeKeyBlobKeyCharacteristics(data[HW_PARAMETERS], scratchPad);
2197       // create new key blob with current os version etc.
2198       createEncryptedKeyBlob(scratchPad);
2199       short prevReclaimIndex = repository.getHeapReclaimIndex();
2200       short offset = repository.allocReclaimableMemory(MAX_KEYBLOB_SIZE);
2201       data[KEY_BLOB] =
2202           encoder.encode(
2203               data[KEY_BLOB], repository.getHeap(), offset, prevReclaimIndex, MAX_KEYBLOB_SIZE);
2204       data[KEY_BLOB] = KMByteBlob.instance(repository.getHeap(), offset, data[KEY_BLOB]);
2205       repository.reclaimMemory(MAX_KEYBLOB_SIZE);
2206     } else {
2207       data[KEY_BLOB] = KMByteBlob.instance((short) 0);
2208     }
2209     // prepare the response
2210     short resp = KMArray.instance((short) 2);
2211     KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK));
2212     KMArray.cast(resp).add((short) 1, data[KEY_BLOB]);
2213     sendOutgoing(apdu, resp);
2214   }
2215 
processExportKeyCmd(APDU apdu)2216   private void processExportKeyCmd(APDU apdu) {
2217     sendResponse(apdu, KMError.UNIMPLEMENTED);
2218   }
2219 
processWrappingKeyBlob(short keyBlob, short wrapParams, byte[] scratchPad)2220   private void processWrappingKeyBlob(short keyBlob, short wrapParams, byte[] scratchPad) {
2221     // Read App Id and App Data if any from un wrapping key params
2222     data[APP_ID] = getApplicationId(wrapParams);
2223     data[APP_DATA] = getApplicationData(wrapParams);
2224     data[KEY_PARAMETERS] = wrapParams;
2225     data[KEY_BLOB] = keyBlob;
2226     // Check if key requires upgrade. The KeyBlob is parsed inside isKeyUpgradeRequired
2227     // function itself.
2228     if (isKeyUpgradeRequired(data[KEY_BLOB], data[APP_ID], data[APP_DATA], scratchPad)) {
2229       KMException.throwIt(KMError.KEY_REQUIRES_UPGRADE);
2230     }
2231     validateWrappingKeyBlob();
2232   }
2233 
validateWrappingKeyBlob()2234   private void validateWrappingKeyBlob() {
2235     // check whether the wrapping key is RSA with purpose KEY_WRAP, padding RSA_OAEP and Digest
2236     // SHA2_256.
2237     KMTag.assertPresence(
2238         data[SB_PARAMETERS],
2239         KMType.ENUM_TAG,
2240         KMType.ALGORITHM,
2241         KMError.UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM);
2242     if (KMEnumTag.getValue(KMType.ALGORITHM, data[HW_PARAMETERS]) != KMType.RSA) {
2243       KMException.throwIt(KMError.UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM);
2244     }
2245     if (!KMEnumArrayTag.contains(KMType.DIGEST, KMType.SHA2_256, data[HW_PARAMETERS])) {
2246       KMException.throwIt(KMError.INCOMPATIBLE_DIGEST);
2247     }
2248     if (!KMEnumArrayTag.contains(KMType.PADDING, KMType.RSA_OAEP, data[HW_PARAMETERS])) {
2249       KMException.throwIt(KMError.INCOMPATIBLE_PADDING_MODE);
2250     }
2251     if (!KMEnumArrayTag.contains(KMType.PURPOSE, KMType.WRAP_KEY, data[HW_PARAMETERS])) {
2252       KMException.throwIt((KMError.INCOMPATIBLE_PURPOSE));
2253     }
2254 
2255     // Check that the digest and padding mode specified in unwrapping  parameters are SHA2_256
2256     // and RSA_OAEP respectively.
2257     if (!KMEnumArrayTag.contains(KMType.DIGEST, KMType.SHA2_256, data[KEY_PARAMETERS])) {
2258       KMException.throwIt(KMError.INCOMPATIBLE_DIGEST);
2259     }
2260     if (!KMEnumArrayTag.contains(KMType.PADDING, KMType.RSA_OAEP, data[KEY_PARAMETERS])) {
2261       KMException.throwIt(KMError.INCOMPATIBLE_PADDING_MODE);
2262     }
2263   }
2264 
decryptTransportKey( short privExp, short modulus, short transportKey, byte[] scratchPad)2265   private short decryptTransportKey(
2266       short privExp, short modulus, short transportKey, byte[] scratchPad) {
2267     short length =
2268         seProvider.rsaDecipherOAEP256(
2269             KMByteBlob.cast(privExp).getBuffer(),
2270             KMByteBlob.cast(privExp).getStartOff(),
2271             KMByteBlob.cast(privExp).length(),
2272             KMByteBlob.cast(modulus).getBuffer(),
2273             KMByteBlob.cast(modulus).getStartOff(),
2274             KMByteBlob.cast(modulus).length(),
2275             KMByteBlob.cast(transportKey).getBuffer(),
2276             KMByteBlob.cast(transportKey).getStartOff(),
2277             KMByteBlob.cast(transportKey).length(),
2278             scratchPad,
2279             (short) 0);
2280     return KMByteBlob.instance(scratchPad, (short) 0, length);
2281   }
2282 
unmask(short data, short maskingKey)2283   private void unmask(short data, short maskingKey) {
2284     short dataLength = KMByteBlob.cast(data).length();
2285     short maskLength = KMByteBlob.cast(maskingKey).length();
2286     // Length of masking key and transport key must be same.
2287     if (maskLength != dataLength) {
2288       KMException.throwIt(KMError.IMPORT_PARAMETER_MISMATCH);
2289     }
2290     short index = 0; // index
2291     // Xor every byte of masking and key and store the result in data[SECRET]
2292     while (index < maskLength) {
2293       short var1 = (short) (((short) KMByteBlob.cast(maskingKey).get(index)) & 0x00FF);
2294       short var2 = (short) (((short) KMByteBlob.cast(data).get(index)) & 0x00FF);
2295       KMByteBlob.cast(data).add(index, (byte) (var1 ^ var2));
2296       index++;
2297     }
2298   }
2299 
beginImportWrappedKeyCmd(APDU apdu)2300   private short beginImportWrappedKeyCmd(APDU apdu) {
2301     short cmd = KMArray.instance((short) 4);
2302     short params = KMKeyParameters.expAny();
2303     KMArray.cast(cmd).add((short) 0, KMByteBlob.exp()); // Encrypted Transport Key
2304     KMArray.cast(cmd).add((short) 1, KMByteBlob.exp()); // Wrapping Key KeyBlob
2305     KMArray.cast(cmd).add((short) 2, KMByteBlob.exp()); // Masking Key
2306     params = KMKeyParameters.exp();
2307     KMArray.cast(cmd).add((short) 3, params); // Wrapping key blob Params
2308     return receiveIncoming(apdu, cmd);
2309   }
2310 
processBeginImportWrappedKeyCmd(APDU apdu)2311   private void processBeginImportWrappedKeyCmd(APDU apdu) {
2312     // Receive the incoming request fully from the host into buffer.
2313     short cmd = beginImportWrappedKeyCmd(apdu);
2314     byte[] scratchPad = apdu.getBuffer();
2315     // Step -1 parse the wrapping key blob
2316     // read wrapping key blob
2317     short keyBlob = KMArray.cast(cmd).get((short) 1);
2318     // read un wrapping key params
2319     short wrappingKeyParameters = KMArray.cast(cmd).get((short) 3);
2320     processWrappingKeyBlob(keyBlob, wrappingKeyParameters, scratchPad);
2321     // Step 2 - decrypt the encrypted transport key - 32 bytes AES-GCM key
2322     short transportKey =
2323         decryptTransportKey(
2324             data[SECRET], data[PUB_KEY], KMArray.cast(cmd).get((short) 0), scratchPad);
2325     // Step 3 - XOR the decrypted AES-GCM key with with masking key
2326     unmask(transportKey, KMArray.cast(cmd).get((short) 2));
2327     if (isValidWrappingKey()) {
2328       KMException.throwIt(KMError.UNKNOWN_ERROR);
2329     }
2330     setWrappingKey(transportKey);
2331     sendResponse(apdu, KMError.OK);
2332   }
2333 
aesGCMDecrypt( short aesSecret, short input, short nonce, short authData, short authTag, byte[] scratchPad)2334   private short aesGCMDecrypt(
2335       short aesSecret, short input, short nonce, short authData, short authTag, byte[] scratchPad) {
2336     Util.arrayFillNonAtomic(scratchPad, (short) 0, KMByteBlob.cast(input).length(), (byte) 0);
2337     if (!seProvider.aesGCMDecrypt(
2338         KMByteBlob.cast(aesSecret).getBuffer(),
2339         KMByteBlob.cast(aesSecret).getStartOff(),
2340         KMByteBlob.cast(aesSecret).length(),
2341         KMByteBlob.cast(input).getBuffer(),
2342         KMByteBlob.cast(input).getStartOff(),
2343         KMByteBlob.cast(input).length(),
2344         scratchPad,
2345         (short) 0,
2346         KMByteBlob.cast(nonce).getBuffer(),
2347         KMByteBlob.cast(nonce).getStartOff(),
2348         KMByteBlob.cast(nonce).length(),
2349         KMByteBlob.cast(authData).getBuffer(),
2350         KMByteBlob.cast(authData).getStartOff(),
2351         KMByteBlob.cast(authData).length(),
2352         KMByteBlob.cast(authTag).getBuffer(),
2353         KMByteBlob.cast(authTag).getStartOff(),
2354         KMByteBlob.cast(authTag).length())) {
2355       KMException.throwIt(KMError.VERIFICATION_FAILED);
2356     }
2357     return KMByteBlob.instance(scratchPad, (short) 0, KMByteBlob.cast(input).length());
2358   }
2359 
finishImportWrappedKeyCmd(APDU apdu)2360   private short finishImportWrappedKeyCmd(APDU apdu) {
2361     short cmd = KMArray.instance((short) 8);
2362     short params = KMKeyParameters.expAny();
2363     KMArray.cast(cmd).add((short) 0, params); // Key Params of wrapped key
2364     KMArray.cast(cmd).add((short) 1, KMEnum.instance(KMType.KEY_FORMAT)); // Key Format
2365     KMArray.cast(cmd).add((short) 2, KMByteBlob.exp()); // Wrapped Import Key Blob
2366     KMArray.cast(cmd).add((short) 3, KMByteBlob.exp()); // Auth Tag
2367     KMArray.cast(cmd).add((short) 4, KMByteBlob.exp()); // IV - Nonce
2368     KMArray.cast(cmd).add((short) 5, KMByteBlob.exp()); // Wrapped Key ASSOCIATED AUTH DATA
2369     KMArray.cast(cmd).add((short) 6, KMInteger.exp()); // Password Sid
2370     KMArray.cast(cmd).add((short) 7, KMInteger.exp()); // Biometric Sid
2371     return receiveIncoming(apdu, cmd);
2372   }
2373 
2374   // TODO remove cmd later on
processFinishImportWrappedKeyCmd(APDU apdu)2375   private void processFinishImportWrappedKeyCmd(APDU apdu) {
2376     short cmd = finishImportWrappedKeyCmd(apdu);
2377     short keyParameters = KMArray.cast(cmd).get((short) 0);
2378     short keyFmt = KMArray.cast(cmd).get((short) 1);
2379     keyFmt = KMEnum.cast(keyFmt).getVal();
2380     validateImportKey(keyParameters, keyFmt);
2381     byte[] scratchPad = apdu.getBuffer();
2382     // Step 4 - AES-GCM decrypt the wrapped key
2383     data[INPUT_DATA] = KMArray.cast(cmd).get((short) 2);
2384     data[AUTH_TAG] = KMArray.cast(cmd).get((short) 3);
2385     data[NONCE] = KMArray.cast(cmd).get((short) 4);
2386     data[AUTH_DATA] = KMArray.cast(cmd).get((short) 5);
2387 
2388     if (!isValidWrappingKey()) {
2389       KMException.throwIt(KMError.UNKNOWN_ERROR);
2390     }
2391     data[IMPORTED_KEY_BLOB] =
2392         aesGCMDecrypt(
2393             getWrappingKey(),
2394             data[INPUT_DATA],
2395             data[NONCE],
2396             data[AUTH_DATA],
2397             data[AUTH_TAG],
2398             scratchPad);
2399     resetWrappingKey();
2400     // Step 5 - Import decrypted key
2401     data[ORIGIN] = KMType.SECURELY_IMPORTED;
2402     data[KEY_PARAMETERS] = keyParameters;
2403     // create key blob array
2404     importKey(apdu, keyFmt, scratchPad);
2405   }
2406 
makeCommonCert(byte[] scratchPad)2407   private KMAttestationCert makeCommonCert(byte[] scratchPad) {
2408     short alg = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, data[KEY_PARAMETERS]);
2409     boolean rsaCert = KMEnumTag.cast(alg).getValue() == KMType.RSA;
2410     KMAttestationCert cert = KMAttestationCertImpl.instance(rsaCert, seProvider);
2411 
2412     short subject =
2413         KMKeyParameters.findTag(
2414             KMType.BYTES_TAG, KMType.CERTIFICATE_SUBJECT_NAME, data[KEY_PARAMETERS]);
2415 
2416     // If no subject name is specified then use the default subject name.
2417     if (subject == KMType.INVALID_VALUE || KMByteTag.cast(subject).length() == 0) {
2418       subject = KMByteBlob.instance(defaultSubject, (short) 0, (short) defaultSubject.length);
2419     } else {
2420       subject = KMByteTag.cast(subject).getValue();
2421     }
2422     cert.subjectName(subject);
2423     // Validity period must be specified
2424     short notBefore =
2425         KMKeyParameters.findTag(
2426             KMType.DATE_TAG, KMType.CERTIFICATE_NOT_BEFORE, data[KEY_PARAMETERS]);
2427     if (notBefore == KMType.INVALID_VALUE) {
2428       KMException.throwIt(KMError.MISSING_NOT_BEFORE);
2429     }
2430     notBefore = KMIntegerTag.cast(notBefore).getValue();
2431     short notAfter =
2432         KMKeyParameters.findTag(
2433             KMType.DATE_TAG, KMType.CERTIFICATE_NOT_AFTER, data[KEY_PARAMETERS]);
2434     if (notAfter == KMType.INVALID_VALUE) {
2435       KMException.throwIt(KMError.MISSING_NOT_AFTER);
2436     }
2437     notAfter = KMIntegerTag.cast(notAfter).getValue();
2438     // VTS sends notBefore == Epoch.
2439     Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 8, (byte) 0);
2440     short epoch = KMInteger.instance(scratchPad, (short) 0, (short) 8);
2441     short end = KMInteger.instance(dec319999Ms, (short) 0, (short) dec319999Ms.length);
2442     if (KMInteger.compare(notBefore, epoch) == 0) {
2443       cert.notBefore(
2444           KMByteBlob.instance(jan01970, (short) 0, (short) jan01970.length), true, scratchPad);
2445     } else {
2446       cert.notBefore(notBefore, false, scratchPad);
2447     }
2448     // VTS sends notAfter == Dec 31st 9999
2449     if (KMInteger.compare(notAfter, end) == 0) {
2450       cert.notAfter(
2451           KMByteBlob.instance(dec319999, (short) 0, (short) dec319999.length), true, scratchPad);
2452     } else {
2453       cert.notAfter(notAfter, false, scratchPad);
2454     }
2455     // Serial number
2456     short serialNum =
2457         KMKeyParameters.findTag(
2458             KMType.BIGNUM_TAG, KMType.CERTIFICATE_SERIAL_NUM, data[KEY_PARAMETERS]);
2459     if (serialNum != KMType.INVALID_VALUE) {
2460       serialNum = KMBignumTag.cast(serialNum).getValue();
2461     } else {
2462       serialNum = KMByteBlob.instance((short) 1);
2463       KMByteBlob.cast(serialNum).add((short) 0, (byte) 1);
2464     }
2465     cert.serialNumber(serialNum);
2466     return cert;
2467   }
2468 
makeAttestationCert( short attKeyBlob, short attKeyParam, short attChallenge, short issuer, byte[] scratchPad)2469   private KMAttestationCert makeAttestationCert(
2470       short attKeyBlob, short attKeyParam, short attChallenge, short issuer, byte[] scratchPad) {
2471     KMAttestationCert cert = makeCommonCert(scratchPad);
2472 
2473     // Read App Id and App Data.
2474     short appId = getApplicationId(attKeyParam);
2475     short appData = getApplicationData(attKeyParam);
2476     // Take backup of the required global variables KEY_BLOB, PUB_KEY, SECRET, KEY_CHAR
2477     // and HW_PARAMS before they get overridden by isKeyUpgradeRequired() function.
2478     short origBlob = data[KEY_BLOB];
2479     short pubKey = data[PUB_KEY];
2480     short privKey = data[SECRET];
2481     short hwParams = data[HW_PARAMETERS];
2482     short keyChars = data[KEY_CHARACTERISTICS];
2483     short customTags = data[CUSTOM_TAGS];
2484     // Check if key requires upgrade for attestKeyBlob. The KeyBlob is parsed inside
2485     // isKeyUpgradeRequired function itself.
2486     if (isKeyUpgradeRequired(attKeyBlob, appId, appData, scratchPad)) {
2487       KMException.throwIt(KMError.KEY_REQUIRES_UPGRADE);
2488     }
2489     // Get the private key of the attest key.
2490     short attestationKeySecret = KMArray.cast(data[KEY_BLOB]).get(KEY_BLOB_SECRET);
2491     // Get the KeyCharacteristics and SB param of the attest key
2492     short attestKeyCharacteristics = KMArray.cast(data[KEY_BLOB]).get(KEY_BLOB_PARAMS);
2493     short attestKeySbParams =
2494         KMKeyCharacteristics.cast(attestKeyCharacteristics).getStrongboxEnforced();
2495     // If the attest key's purpose is not "attest key" then error.
2496     short attKeyPurpose =
2497         KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PURPOSE, attestKeySbParams);
2498     if (!KMEnumArrayTag.cast(attKeyPurpose).contains(KMType.ATTEST_KEY)) {
2499       KMException.throwIt(KMError.INCOMPATIBLE_PURPOSE);
2500     }
2501     KMAsn1Parser asn1Decoder = KMAsn1Parser.instance();
2502     try {
2503       asn1Decoder.validateDerSubject(issuer);
2504     } catch (KMException e) {
2505       KMException.throwIt(KMError.INVALID_ISSUER_SUBJECT_NAME);
2506     }
2507     if (KMByteBlob.cast(issuer).length() > KMConfigurations.MAX_SUBJECT_DER_LEN) {
2508       KMException.throwIt(KMError.INVALID_ISSUER_SUBJECT_NAME);
2509     }
2510     // If issuer is not present then it is an error
2511     if (KMByteBlob.cast(issuer).length() <= 0) {
2512       KMException.throwIt(KMError.MISSING_ISSUER_SUBJECT_NAME);
2513     }
2514     short alg = KMEnumTag.getValue(KMType.ALGORITHM, attestKeySbParams);
2515     if (alg == KMType.RSA) {
2516       short attestationKeyPublic = KMArray.cast(data[KEY_BLOB]).get(KEY_BLOB_PUB_KEY);
2517       cert.rsaAttestKey(attestationKeySecret, attestationKeyPublic, KMType.ATTESTATION_CERT);
2518     } else if (alg == KMType.EC) {
2519       cert.ecAttestKey(attestationKeySecret, KMType.ATTESTATION_CERT);
2520     } else {
2521       KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM);
2522     }
2523     cert.attestationChallenge(attChallenge);
2524     cert.issuer(issuer);
2525 
2526     // Restore back the global variables.
2527     data[PUB_KEY] = pubKey;
2528     data[SECRET] = privKey;
2529     data[KEY_BLOB] = origBlob;
2530     data[HW_PARAMETERS] = hwParams;
2531     data[KEY_CHARACTERISTICS] = keyChars;
2532     data[CUSTOM_TAGS] = customTags;
2533     data[SW_PARAMETERS] =
2534         KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getKeystoreEnforced();
2535     data[TEE_PARAMETERS] = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getTeeEnforced();
2536     data[SB_PARAMETERS] =
2537         KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getStrongboxEnforced();
2538     cert.publicKey(data[PUB_KEY]);
2539 
2540     // Save attestation application id - must be present.
2541     short attAppId =
2542         KMKeyParameters.findTag(
2543             KMType.BYTES_TAG, KMType.ATTESTATION_APPLICATION_ID, data[KEY_PARAMETERS]);
2544     if (attAppId == KMType.INVALID_VALUE) {
2545       KMException.throwIt(KMError.ATTESTATION_APPLICATION_ID_MISSING);
2546     }
2547     cert.extensionTag(attAppId, false);
2548     // unique id byte blob - uses application id and temporal month count of
2549     // creation time.
2550     attAppId = KMByteTag.cast(attAppId).getValue();
2551     setUniqueId(cert, attAppId, scratchPad);
2552     // Add Attestation Ids if present
2553     addAttestationIds(cert, scratchPad);
2554 
2555     // Add Tags
2556     addTags(data[HW_PARAMETERS], true, cert);
2557     addTags(data[SW_PARAMETERS], false, cert);
2558     // Add Device Boot locked status
2559     cert.deviceLocked(kmDataStore.isDeviceBootLocked());
2560     // VB data
2561     cert.verifiedBootHash(getVerifiedBootHash(scratchPad));
2562     cert.verifiedBootKey(getBootKey(scratchPad));
2563     cert.verifiedBootState((byte) kmDataStore.getBootState());
2564     return cert;
2565   }
2566 
makeSelfSignedCert( short attPrivKey, short attPubKey, short mode, byte[] scratchPad)2567   private KMAttestationCert makeSelfSignedCert(
2568       short attPrivKey, short attPubKey, short mode, byte[] scratchPad) {
2569     KMAttestationCert cert = makeCommonCert(scratchPad);
2570     short alg = KMEnumTag.getValue(KMType.ALGORITHM, data[KEY_PARAMETERS]);
2571     short subject =
2572         KMKeyParameters.findTag(
2573             KMType.BYTES_TAG, KMType.CERTIFICATE_SUBJECT_NAME, data[KEY_PARAMETERS]);
2574     // If no subject name is specified then use the default subject name.
2575     if (subject == KMType.INVALID_VALUE || KMByteTag.cast(subject).length() == 0) {
2576       subject = KMByteBlob.instance(defaultSubject, (short) 0, (short) defaultSubject.length);
2577     } else {
2578       subject = KMByteTag.cast(subject).getValue();
2579     }
2580 
2581     if (alg == KMType.RSA) {
2582       cert.rsaAttestKey(attPrivKey, attPubKey, (byte) mode);
2583     } else {
2584       cert.ecAttestKey(attPrivKey, (byte) mode);
2585     }
2586     cert.issuer(subject);
2587     cert.subjectName(subject);
2588     cert.publicKey(attPubKey);
2589     return cert;
2590   }
2591 
getBootKey(byte[] scratchPad)2592   protected short getBootKey(byte[] scratchPad) {
2593     Util.arrayFillNonAtomic(scratchPad, (short) 0, VERIFIED_BOOT_KEY_SIZE, (byte) 0);
2594     short len = kmDataStore.getBootKey(scratchPad, (short) 0);
2595     if (len != VERIFIED_BOOT_KEY_SIZE) {
2596       KMException.throwIt(KMError.UNKNOWN_ERROR);
2597     }
2598     return KMByteBlob.instance(scratchPad, (short) 0, VERIFIED_BOOT_KEY_SIZE);
2599   }
2600 
getVerifiedBootHash(byte[] scratchPad)2601   protected short getVerifiedBootHash(byte[] scratchPad) {
2602     Util.arrayFillNonAtomic(scratchPad, (short) 0, VERIFIED_BOOT_HASH_SIZE, (byte) 0);
2603     short len = kmDataStore.getVerifiedBootHash(scratchPad, (short) 0);
2604     if (len != VERIFIED_BOOT_HASH_SIZE) {
2605       KMException.throwIt(KMError.UNKNOWN_ERROR);
2606     }
2607     return KMByteBlob.instance(scratchPad, (short) 0, VERIFIED_BOOT_HASH_SIZE);
2608   }
2609 
2610   // --------------------------------
2611   // Only add the Attestation ids which are requested in the attestation parameters.
2612   // If the requested attestation ids are not provisioned or deleted then
2613   // throw CANNOT_ATTEST_IDS error. If there is mismatch in the attestation
2614   // id values of both the requested parameters and the provisioned parameters
2615   // then throw INVALID_TAG error.
addAttestationIds(KMAttestationCert cert, byte[] scratchPad)2616   private void addAttestationIds(KMAttestationCert cert, byte[] scratchPad) {
2617     byte index = 0;
2618     short attIdTag;
2619     short attIdTagValue;
2620     short storedAttIdLen;
2621     while (index < (short) attTags.length) {
2622       attIdTag = KMKeyParameters.findTag(KMType.BYTES_TAG, attTags[index], data[KEY_PARAMETERS]);
2623       if (attIdTag != KMType.INVALID_VALUE) {
2624         attIdTagValue = KMByteTag.cast(attIdTag).getValue();
2625         storedAttIdLen = kmDataStore.getAttestationId(attTags[index], scratchPad, (short) 0);
2626         // Return CANNOT_ATTEST_IDS if Attestation IDs are not provisioned or
2627         // Attestation IDs are deleted.
2628         if (storedAttIdLen == 0) {
2629           KMException.throwIt(KMError.CANNOT_ATTEST_IDS);
2630         }
2631         // Return INVALID_TAG if Attestation IDs does not match.
2632         if ((storedAttIdLen != KMByteBlob.cast(attIdTagValue).length())
2633             || (0
2634                 != Util.arrayCompare(
2635                     scratchPad,
2636                     (short) 0,
2637                     KMByteBlob.cast(attIdTagValue).getBuffer(),
2638                     KMByteBlob.cast(attIdTagValue).getStartOff(),
2639                     storedAttIdLen))) {
2640           KMException.throwIt(KMError.CANNOT_ATTEST_IDS);
2641         }
2642         short blob = KMByteBlob.instance(scratchPad, (short) 0, storedAttIdLen);
2643         cert.extensionTag(KMByteTag.instance(attTags[index], blob), true);
2644       }
2645       index++;
2646     }
2647   }
2648 
processDestroyAttIdsCmd(APDU apdu)2649   private void processDestroyAttIdsCmd(APDU apdu) {
2650     kmDataStore.deleteAttestationIds();
2651     sendResponse(apdu, KMError.OK);
2652   }
2653 
processVerifyAuthorizationCmd(APDU apdu)2654   private void processVerifyAuthorizationCmd(APDU apdu) {
2655     sendResponse(apdu, KMError.UNIMPLEMENTED);
2656   }
2657 
abortOperationCmd(APDU apdu)2658   private short abortOperationCmd(APDU apdu) {
2659     short cmd = KMArray.instance((short) 1);
2660     KMArray.cast(cmd).add((short) 0, KMInteger.exp());
2661     return receiveIncoming(apdu, cmd);
2662   }
2663 
processAbortOperationCmd(APDU apdu)2664   private void processAbortOperationCmd(APDU apdu) {
2665     short cmd = abortOperationCmd(apdu);
2666     data[OP_HANDLE] = KMArray.cast(cmd).get((short) 0);
2667     KMOperationState op = findOperation(data[OP_HANDLE]);
2668     if (op == null) {
2669       sendResponse(apdu, KMError.INVALID_OPERATION_HANDLE);
2670     } else {
2671       releaseOperation(op);
2672       sendResponse(apdu, KMError.OK);
2673     }
2674   }
2675 
finishOperationCmd(APDU apdu)2676   private short finishOperationCmd(APDU apdu) {
2677     short cmd = KMArray.instance((short) 6);
2678     KMArray.cast(cmd).add((short) 0, KMInteger.exp()); // op handle
2679     KMArray.cast(cmd).add((short) 1, KMByteBlob.exp()); // input data
2680     KMArray.cast(cmd).add((short) 2, KMByteBlob.exp()); // signature
2681     short authToken = KMHardwareAuthToken.exp();
2682     KMArray.cast(cmd).add((short) 3, authToken); // auth token
2683     short verToken = KMVerificationToken.exp();
2684     KMArray.cast(cmd).add((short) 4, verToken); // time stamp token
2685     KMArray.cast(cmd).add((short) 5, KMByteBlob.exp()); // confirmation token
2686     return receiveIncoming(apdu, cmd);
2687   }
2688 
processFinishOperationCmd(APDU apdu)2689   private void processFinishOperationCmd(APDU apdu) {
2690     short cmd = finishOperationCmd(apdu);
2691     byte[] scratchPad = apdu.getBuffer();
2692     data[OP_HANDLE] = KMArray.cast(cmd).get((short) 0);
2693     data[INPUT_DATA] = KMArray.cast(cmd).get((short) 1);
2694     data[SIGNATURE] = KMArray.cast(cmd).get((short) 2);
2695     data[HW_TOKEN] = KMArray.cast(cmd).get((short) 3);
2696     data[VERIFICATION_TOKEN] = KMArray.cast(cmd).get((short) 4);
2697     data[CONFIRMATION_TOKEN] = KMArray.cast(cmd).get((short) 5);
2698     // Check Operation Handle
2699     KMOperationState op = findOperation(data[OP_HANDLE]);
2700     if (op == null) {
2701       KMException.throwIt(KMError.INVALID_OPERATION_HANDLE);
2702     }
2703     // Authorize the finish operation
2704     authorizeUpdateFinishOperation(op, scratchPad);
2705     switch (op.getPurpose()) {
2706       case KMType.SIGN:
2707         finishTrustedConfirmationOperation(op);
2708       case KMType.VERIFY:
2709         finishSigningVerifyingOperation(op, scratchPad);
2710         break;
2711       case KMType.ENCRYPT:
2712         finishEncryptOperation(op, scratchPad);
2713         break;
2714       case KMType.DECRYPT:
2715         finishDecryptOperation(op, scratchPad);
2716         break;
2717       case KMType.AGREE_KEY:
2718         finishKeyAgreementOperation(op, scratchPad);
2719         break;
2720     }
2721     if (data[OUTPUT_DATA] == KMType.INVALID_VALUE) {
2722       data[OUTPUT_DATA] = KMByteBlob.instance((short) 0);
2723     }
2724     // Remove the operation handle
2725     releaseOperation(op);
2726 
2727     // make response
2728     short resp = KMArray.instance((short) 2);
2729     KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK));
2730     KMArray.cast(resp).add((short) 1, data[OUTPUT_DATA]);
2731     sendOutgoing(apdu, resp);
2732   }
2733 
finishEncryptOperation(KMOperationState op, byte[] scratchPad)2734   private void finishEncryptOperation(KMOperationState op, byte[] scratchPad) {
2735     if (op.getAlgorithm() != KMType.AES && op.getAlgorithm() != KMType.DES) {
2736       KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM);
2737     }
2738     finishAesDesOperation(op);
2739   }
2740 
finishDecryptOperation(KMOperationState op, byte[] scratchPad)2741   private void finishDecryptOperation(KMOperationState op, byte[] scratchPad) {
2742     short len = KMByteBlob.cast(data[INPUT_DATA]).length();
2743     switch (op.getAlgorithm()) {
2744       case KMType.RSA:
2745         // Fill the scratch pad with zero
2746         Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0);
2747         if (op.getPadding() == KMType.PADDING_NONE && len != 256) {
2748           KMException.throwIt(KMError.INVALID_INPUT_LENGTH);
2749         }
2750         len =
2751             op.getOperation()
2752                 .finish(
2753                     KMByteBlob.cast(data[INPUT_DATA]).getBuffer(),
2754                     KMByteBlob.cast(data[INPUT_DATA]).getStartOff(),
2755                     len,
2756                     scratchPad,
2757                     (short) 0);
2758 
2759         data[OUTPUT_DATA] = KMByteBlob.instance(scratchPad, (short) 0, len);
2760         break;
2761       case KMType.AES:
2762       case KMType.DES:
2763         finishAesDesOperation(op);
2764         break;
2765     }
2766   }
2767 
finishAesDesOperation(KMOperationState op)2768   private void finishAesDesOperation(KMOperationState op) {
2769     short len = KMByteBlob.cast(data[INPUT_DATA]).length();
2770     short blockSize = AES_BLOCK_SIZE;
2771     if (op.getAlgorithm() == KMType.DES) {
2772       blockSize = DES_BLOCK_SIZE;
2773     }
2774 
2775     if (op.getPurpose() == KMType.DECRYPT
2776         && len > 0
2777         && (op.getBlockMode() == KMType.ECB || op.getBlockMode() == KMType.CBC)
2778         && ((short) (len % blockSize) != 0)) {
2779       KMException.throwIt(KMError.INVALID_INPUT_LENGTH);
2780     }
2781 
2782     if (op.getBlockMode() == KMType.GCM) {
2783       if (op.getPurpose() == KMType.DECRYPT && (len < (short) (op.getMacLength() / 8))) {
2784         KMException.throwIt(KMError.INVALID_INPUT_LENGTH);
2785       }
2786       if (op.isAesGcmUpdateAllowed()) {
2787         op.setAesGcmUpdateComplete();
2788       }
2789       // Get the output size
2790       len = op.getOperation().getAESGCMOutputSize(len, (short) (op.getMacLength() / 8));
2791     }
2792     // If padding i.e. pkcs7 then add padding to right
2793     // Output data can at most one block size more the input data in case of pkcs7 encryption
2794     // In case of gcm we will allocate extra memory of the size equal to blocksize.
2795     data[OUTPUT_DATA] = KMByteBlob.instance((short) (len + 2 * blockSize));
2796     try {
2797       len =
2798           op.getOperation()
2799               .finish(
2800                   KMByteBlob.cast(data[INPUT_DATA]).getBuffer(),
2801                   KMByteBlob.cast(data[INPUT_DATA]).getStartOff(),
2802                   KMByteBlob.cast(data[INPUT_DATA]).length(),
2803                   KMByteBlob.cast(data[OUTPUT_DATA]).getBuffer(),
2804                   KMByteBlob.cast(data[OUTPUT_DATA]).getStartOff());
2805     } catch (CryptoException e) {
2806       if (e.getReason() == CryptoException.ILLEGAL_USE) {
2807         // As per VTS, zero length input on AES/DES with PADDING_NONE Should return a zero length
2808         // output. But JavaCard fails with CryptoException.ILLEGAL_USE if no input data is
2809         // provided via update() method. So ignore this exception in case if all below conditions
2810         // are satisfied and simply return empty output.
2811         // 1. padding mode is PADDING_NONE.
2812         // 2. No input  message is processed in update().
2813         // 3. Zero length input data is passed in finish operation.
2814         if ((op.getPadding() == KMType.PADDING_NONE)
2815             && !op.isInputMsgProcessed()
2816             && (KMByteBlob.cast(data[INPUT_DATA]).length() == 0)) {
2817           len = 0;
2818         } else {
2819           KMException.throwIt(KMError.INVALID_INPUT_LENGTH);
2820         }
2821       }
2822     }
2823     KMByteBlob.cast(data[OUTPUT_DATA]).setLength(len);
2824   }
2825 
finishKeyAgreementOperation(KMOperationState op, byte[] scratchPad)2826   private void finishKeyAgreementOperation(KMOperationState op, byte[] scratchPad) {
2827     try {
2828       KMAsn1Parser pkcs8 = KMAsn1Parser.instance();
2829       short blob = pkcs8.decodeEcSubjectPublicKeyInfo(data[INPUT_DATA]);
2830       short len =
2831           op.getOperation()
2832               .finish(
2833                   KMByteBlob.cast(blob).getBuffer(),
2834                   KMByteBlob.cast(blob).getStartOff(),
2835                   KMByteBlob.cast(blob).length(),
2836                   scratchPad,
2837                   (short) 0);
2838       data[OUTPUT_DATA] = KMByteBlob.instance((short) 32);
2839       Util.arrayCopyNonAtomic(
2840           scratchPad,
2841           (short) 0,
2842           KMByteBlob.cast(data[OUTPUT_DATA]).getBuffer(),
2843           KMByteBlob.cast(data[OUTPUT_DATA]).getStartOff(),
2844           len);
2845     } catch (CryptoException e) {
2846       KMException.throwIt(KMError.INVALID_ARGUMENT);
2847     }
2848   }
2849 
finishSigningVerifyingOperation(KMOperationState op, byte[] scratchPad)2850   private void finishSigningVerifyingOperation(KMOperationState op, byte[] scratchPad) {
2851     Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0);
2852     switch (op.getAlgorithm()) {
2853       case KMType.RSA:
2854         // If there is no padding we can treat signing as a RSA decryption operation.
2855         try {
2856           if (op.getPurpose() == KMType.SIGN) {
2857             // len of signature will be 256 bytes - but it can be less then 256 bytes
2858             short len =
2859                 op.getOperation()
2860                     .sign(
2861                         KMByteBlob.cast(data[INPUT_DATA]).getBuffer(),
2862                         KMByteBlob.cast(data[INPUT_DATA]).getStartOff(),
2863                         KMByteBlob.cast(data[INPUT_DATA]).length(),
2864                         scratchPad,
2865                         (short) 0);
2866             // Maximum output size of signature is 256 bytes. - the signature will always be
2867             // positive
2868             data[OUTPUT_DATA] = KMByteBlob.instance((short) 256);
2869             Util.arrayCopyNonAtomic(
2870                 scratchPad,
2871                 (short) 0,
2872                 KMByteBlob.cast(data[OUTPUT_DATA]).getBuffer(),
2873                 (short) (KMByteBlob.cast(data[OUTPUT_DATA]).getStartOff() + 256 - len),
2874                 len);
2875           } else {
2876             KMException.throwIt(KMError.UNSUPPORTED_PURPOSE);
2877           }
2878         } catch (CryptoException e) {
2879           KMException.throwIt(KMError.INVALID_ARGUMENT);
2880         }
2881         break;
2882       case KMType.EC:
2883         short len = KMByteBlob.cast(data[INPUT_DATA]).length();
2884         // If DIGEST NONE then truncate the input data to 32 bytes.
2885         if (op.getDigest() == KMType.DIGEST_NONE && len > 32) {
2886           len = 32;
2887         }
2888         if (op.getPurpose() == KMType.SIGN) {
2889           // len of signature will be 512 bits i.e. 64 bytes
2890           len =
2891               op.getOperation()
2892                   .sign(
2893                       KMByteBlob.cast(data[INPUT_DATA]).getBuffer(),
2894                       KMByteBlob.cast(data[INPUT_DATA]).getStartOff(),
2895                       len,
2896                       scratchPad,
2897                       (short) 0);
2898           data[OUTPUT_DATA] = KMByteBlob.instance(scratchPad, (short) 0, len);
2899         } else {
2900           KMException.throwIt(KMError.UNSUPPORTED_PURPOSE);
2901         }
2902         break;
2903       case KMType.HMAC:
2904         // As per Keymaster HAL documentation, the length of the Hmac output can
2905         // be decided by using TAG_MAC_LENGTH in Keyparameters. But there is no
2906         // such provision to control the length of the Hmac output using JavaCard
2907         // crypto APIs and the current implementation always returns 32 bytes
2908         // length of Hmac output. So to provide support to TAG_MAC_LENGTH
2909         // feature, we truncate the output signature to TAG_MAC_LENGTH and return
2910         // the truncated signature back to the caller. At the time of verfication
2911         // we again compute the signature of the plain text input, truncate it to
2912         // TAG_MAC_LENGTH and compare it with the input signature for
2913         // verification.
2914         op.getOperation()
2915             .sign(
2916                 KMByteBlob.cast(data[INPUT_DATA]).getBuffer(),
2917                 KMByteBlob.cast(data[INPUT_DATA]).getStartOff(),
2918                 KMByteBlob.cast(data[INPUT_DATA]).length(),
2919                 scratchPad,
2920                 (short) 0);
2921         if (op.getPurpose() == KMType.SIGN) {
2922           // Copy only signature of mac length size.
2923           data[OUTPUT_DATA] =
2924               KMByteBlob.instance(scratchPad, (short) 0, (short) (op.getMacLength() / 8));
2925         } else if (op.getPurpose() == KMType.VERIFY) {
2926           if ((KMByteBlob.cast(data[SIGNATURE]).length() < (MIN_HMAC_LENGTH_BITS / 8))
2927               || KMByteBlob.cast(data[SIGNATURE]).length() > (SHA256_DIGEST_LEN_BITS / 8)) {
2928             KMException.throwIt(KMError.UNSUPPORTED_MAC_LENGTH);
2929           }
2930           if ((KMByteBlob.cast(data[SIGNATURE]).length() < (short) (op.getMinMacLength() / 8))) {
2931             KMException.throwIt(KMError.INVALID_MAC_LENGTH);
2932           }
2933 
2934           if (0
2935               != Util.arrayCompare(
2936                   scratchPad,
2937                   (short) 0,
2938                   KMByteBlob.cast(data[SIGNATURE]).getBuffer(),
2939                   KMByteBlob.cast(data[SIGNATURE]).getStartOff(),
2940                   KMByteBlob.cast(data[SIGNATURE]).length())) {
2941             KMException.throwIt(KMError.VERIFICATION_FAILED);
2942           }
2943           data[OUTPUT_DATA] = KMByteBlob.instance((short) 0);
2944         }
2945         break;
2946       default: // This is should never happen
2947         KMException.throwIt(KMError.OPERATION_CANCELLED);
2948         break;
2949     }
2950   }
2951 
authorizeUpdateFinishOperation(KMOperationState op, byte[] scratchPad)2952   private void authorizeUpdateFinishOperation(KMOperationState op, byte[] scratchPad) {
2953     // If one time user Authentication is required
2954     if (op.isSecureUserIdReqd() && !op.isAuthTimeoutValidated()) {
2955       // Validate Verification Token.
2956       validateVerificationToken(data[VERIFICATION_TOKEN], scratchPad);
2957       // validate operation handle.
2958       short ptr = KMVerificationToken.cast(data[VERIFICATION_TOKEN]).getChallenge();
2959       if (KMInteger.compare(ptr, op.getHandle()) != 0) {
2960         KMException.throwIt(KMError.KEY_USER_NOT_AUTHENTICATED);
2961       }
2962       tmpVariables[0] = op.getAuthTime();
2963       tmpVariables[2] = KMVerificationToken.cast(data[VERIFICATION_TOKEN]).getTimestamp();
2964       if (tmpVariables[2] == KMType.INVALID_VALUE) {
2965         KMException.throwIt(KMError.KEY_USER_NOT_AUTHENTICATED);
2966       }
2967       if (KMInteger.compare(tmpVariables[0], tmpVariables[2]) < 0) {
2968         KMException.throwIt(KMError.KEY_USER_NOT_AUTHENTICATED);
2969       }
2970       op.setAuthTimeoutValidated(true);
2971     } else if (op.isAuthPerOperationReqd()) { // If Auth per operation is required
2972       if (!validateHwToken(data[HW_TOKEN], scratchPad)) {
2973         KMException.throwIt(KMError.KEY_USER_NOT_AUTHENTICATED);
2974       }
2975       tmpVariables[0] = KMHardwareAuthToken.cast(data[HW_TOKEN]).getChallenge();
2976       if (KMInteger.compare(data[OP_HANDLE], tmpVariables[0]) != 0) {
2977         KMException.throwIt(KMError.KEY_USER_NOT_AUTHENTICATED);
2978       }
2979       short len = op.getAuthType(scratchPad, (short) 0);
2980       if (!authTokenMatches(op.getUserSecureId(), scratchPad, (short) 0, len, scratchPad, len)) {
2981         KMException.throwIt(KMError.KEY_USER_NOT_AUTHENTICATED);
2982       }
2983     }
2984   }
2985 
authorizeKeyUsageForCount(byte[] scratchPad)2986   private void authorizeKeyUsageForCount(byte[] scratchPad) {
2987     short scratchPadOff = 0;
2988     Util.arrayFillNonAtomic(scratchPad, scratchPadOff, (short) 12, (byte) 0);
2989 
2990     short usageLimitBufLen =
2991         KMIntegerTag.getValue(
2992             scratchPad,
2993             scratchPadOff,
2994             KMType.UINT_TAG,
2995             KMType.MAX_USES_PER_BOOT,
2996             data[HW_PARAMETERS]);
2997 
2998     if (usageLimitBufLen == KMType.INVALID_VALUE) {
2999       return;
3000     }
3001 
3002     if (usageLimitBufLen > 4) {
3003       KMException.throwIt(KMError.INVALID_ARGUMENT);
3004     }
3005 
3006     if (kmDataStore.isAuthTagPersisted(data[AUTH_TAG])) {
3007       // Get current counter, update and increment it.
3008       short len =
3009           kmDataStore.getRateLimitedKeyCount(
3010               data[AUTH_TAG], scratchPad, (short) (scratchPadOff + 4));
3011       if (len != 4) {
3012         KMException.throwIt(KMError.UNKNOWN_ERROR);
3013       }
3014       if (0
3015           >= KMInteger.unsignedByteArrayCompare(
3016               scratchPad, scratchPadOff, scratchPad, (short) (scratchPadOff + 4), (short) 4)) {
3017         KMException.throwIt(KMError.KEY_MAX_OPS_EXCEEDED);
3018       }
3019       // Increment the counter.
3020       Util.arrayFillNonAtomic(scratchPad, scratchPadOff, len, (byte) 0);
3021       Util.setShort(scratchPad, (short) (scratchPadOff + 2), (short) 1);
3022       KMUtils.add(
3023           scratchPad,
3024           scratchPadOff,
3025           (short) (scratchPadOff + len),
3026           (short) (scratchPadOff + len * 2));
3027 
3028       kmDataStore.setRateLimitedKeyCount(
3029           data[AUTH_TAG], scratchPad, (short) (scratchPadOff + len * 2), len);
3030     } else {
3031       // Persist auth tag.
3032       if (!kmDataStore.persistAuthTag(data[AUTH_TAG])) {
3033         KMException.throwIt(KMError.TOO_MANY_OPERATIONS);
3034       }
3035     }
3036   }
3037 
authorizeDeviceUnlock(byte[] scratchPad)3038   private void authorizeDeviceUnlock(byte[] scratchPad) {
3039     // If device is locked and key characteristics requires unlocked device then check whether
3040     // HW auth token has correct timestamp.
3041     short ptr =
3042         KMKeyParameters.findTag(
3043             KMType.BOOL_TAG, KMType.UNLOCKED_DEVICE_REQUIRED, data[HW_PARAMETERS]);
3044 
3045     if (ptr != KMType.INVALID_VALUE && kmDataStore.getDeviceLock()) {
3046       if (data[HW_TOKEN] == KMType.INVALID_VALUE) {
3047         KMException.throwIt(KMError.DEVICE_LOCKED);
3048       }
3049       ptr = KMHardwareAuthToken.cast(data[HW_TOKEN]).getTimestamp();
3050       // Check if the current auth time stamp is greater than device locked time stamp
3051       short ts = kmDataStore.getDeviceTimeStamp();
3052       if (KMInteger.compare(ptr, ts) <= 0) {
3053         KMException.throwIt(KMError.DEVICE_LOCKED);
3054       }
3055       // Now check if the device unlock requires password only authentication and whether
3056       // auth token is generated through password authentication or not.
3057       scratchPad[0] = KMType.PASSWORD;
3058       short authTypeLen = 1;
3059       if (kmDataStore.getDeviceLockPasswordOnly()) {
3060         if (!hwAuthTypeMatches(scratchPad, (short) 0, authTypeLen, scratchPad, authTypeLen)) {
3061           KMException.throwIt(KMError.DEVICE_LOCKED);
3062         }
3063       }
3064       // Unlock the device
3065       // repository.deviceLockedFlag = false;
3066       kmDataStore.setDeviceLock(false);
3067       kmDataStore.clearDeviceLockTimeStamp();
3068     }
3069   }
3070 
verifyVerificationTokenMacInBigEndian(short verToken, byte[] scratchPad)3071   private boolean verifyVerificationTokenMacInBigEndian(short verToken, byte[] scratchPad) {
3072     // concatenation length will be 37 + length of verified parameters list - which
3073     // is typically empty
3074     Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0);
3075     // Add "Auth Verification" - 17 bytes.
3076     Util.arrayCopyNonAtomic(
3077         authVerification, (short) 0, scratchPad, (short) 0, (short) authVerification.length);
3078     short len = (short) authVerification.length;
3079     // concatenate challenge - 8 bytes
3080     short ptr = KMVerificationToken.cast(verToken).getChallenge();
3081     KMInteger.cast(ptr)
3082         .value(
3083             scratchPad, (short) (len + (short) (KMInteger.UINT_64 - KMInteger.cast(ptr).length())));
3084     len += KMInteger.UINT_64;
3085     // concatenate timestamp -8 bytes
3086     ptr = KMVerificationToken.cast(verToken).getTimestamp();
3087     KMInteger.cast(ptr)
3088         .value(
3089             scratchPad, (short) (len + (short) (KMInteger.UINT_64 - KMInteger.cast(ptr).length())));
3090     len += KMInteger.UINT_64;
3091     // concatenate security level - 4 bytes
3092     scratchPad[(short) (len + 3)] = TRUSTED_ENVIRONMENT;
3093     len += KMInteger.UINT_32;
3094     // hmac the data
3095     ptr = KMVerificationToken.cast(verToken).getMac();
3096 
3097     return seProvider.hmacVerify(
3098         kmDataStore.getComputedHmacKey(),
3099         scratchPad,
3100         (short) 0,
3101         len,
3102         KMByteBlob.cast(ptr).getBuffer(),
3103         KMByteBlob.cast(ptr).getStartOff(),
3104         KMByteBlob.cast(ptr).length());
3105   }
3106 
validateVerificationToken(short verToken, byte[] scratchPad)3107   private void validateVerificationToken(short verToken, byte[] scratchPad) {
3108     short ptr = KMVerificationToken.cast(verToken).getMac();
3109     // If mac length is zero then token is empty.
3110     if (KMByteBlob.cast(ptr).length() == 0) {
3111       KMException.throwIt(KMError.KEY_USER_NOT_AUTHENTICATED);
3112     }
3113     if (!verifyVerificationTokenMacInBigEndian(verToken, scratchPad)) {
3114       // Throw Exception if none of the combination works.
3115       KMException.throwIt(KMError.KEY_USER_NOT_AUTHENTICATED);
3116     }
3117   }
3118 
updateOperationCmd(APDU apdu)3119   private short updateOperationCmd(APDU apdu) {
3120     short cmd = KMArray.instance((short) 4);
3121     // Arguments
3122     KMArray.cast(cmd).add((short) 0, KMInteger.exp());
3123     KMArray.cast(cmd).add((short) 1, KMByteBlob.exp());
3124     short authToken = KMHardwareAuthToken.exp();
3125     KMArray.cast(cmd).add((short) 2, authToken);
3126     short verToken = KMVerificationToken.exp();
3127     KMArray.cast(cmd).add((short) 3, verToken);
3128     return receiveIncoming(apdu, cmd);
3129   }
3130 
processUpdateOperationCmd(APDU apdu)3131   private void processUpdateOperationCmd(APDU apdu) {
3132     short cmd = updateOperationCmd(apdu);
3133     byte[] scratchPad = apdu.getBuffer();
3134     data[OP_HANDLE] = KMArray.cast(cmd).get((short) 0);
3135     data[INPUT_DATA] = KMArray.cast(cmd).get((short) 1);
3136     data[HW_TOKEN] = KMArray.cast(cmd).get((short) 2);
3137     data[VERIFICATION_TOKEN] = KMArray.cast(cmd).get((short) 3);
3138 
3139     // Input data must be present even if it is zero length.
3140     if (data[INPUT_DATA] == KMType.INVALID_VALUE) {
3141       KMException.throwIt(KMError.INVALID_ARGUMENT);
3142     }
3143 
3144     // Check Operation Handle and get op state
3145     // Check Operation Handle
3146     KMOperationState op = findOperation(data[OP_HANDLE]);
3147     if (op == null) {
3148       KMException.throwIt(KMError.INVALID_OPERATION_HANDLE);
3149     }
3150     // authorize the update operation
3151     authorizeUpdateFinishOperation(op, scratchPad);
3152 
3153     if (op.getPurpose() == KMType.SIGN || op.getPurpose() == KMType.VERIFY) {
3154       // update the data.
3155       op.getOperation()
3156           .update(
3157               KMByteBlob.cast(data[INPUT_DATA]).getBuffer(),
3158               KMByteBlob.cast(data[INPUT_DATA]).getStartOff(),
3159               KMByteBlob.cast(data[INPUT_DATA]).length());
3160       // update trusted confirmation operation
3161       updateTrustedConfirmationOperation(op);
3162 
3163       data[OUTPUT_DATA] = KMType.INVALID_VALUE;
3164     } else if (op.getPurpose() == KMType.ENCRYPT || op.getPurpose() == KMType.DECRYPT) {
3165       // Update for encrypt/decrypt using RSA will not be supported because to do this op state
3166       //  will have to buffer the data - so reject the update if it is rsa algorithm.
3167       if (op.getAlgorithm() == KMType.RSA) {
3168         KMException.throwIt(KMError.OPERATION_CANCELLED);
3169       }
3170       short len = KMByteBlob.cast(data[INPUT_DATA]).length();
3171       short blockSize = DES_BLOCK_SIZE;
3172       if (op.getAlgorithm() == KMType.AES) {
3173         blockSize = AES_BLOCK_SIZE;
3174         if (op.getBlockMode() == KMType.GCM) {
3175           // if input data present
3176           if (len > 0) {
3177             // no more future updateAAD allowed if input data present.
3178             if (op.isAesGcmUpdateAllowed()) {
3179               op.setAesGcmUpdateComplete();
3180             }
3181           }
3182         }
3183       }
3184       // Allocate output buffer as input data is already block aligned
3185       data[OUTPUT_DATA] = KMByteBlob.instance((short) (len + 2 * blockSize));
3186       // Otherwise just update the data.
3187       // HAL consumes all the input and maintains a buffered data inside it. So the
3188       // applet sends the inputConsumed length as same as the input length.
3189       try {
3190         len =
3191             op.getOperation()
3192                 .update(
3193                     KMByteBlob.cast(data[INPUT_DATA]).getBuffer(),
3194                     KMByteBlob.cast(data[INPUT_DATA]).getStartOff(),
3195                     KMByteBlob.cast(data[INPUT_DATA]).length(),
3196                     KMByteBlob.cast(data[OUTPUT_DATA]).getBuffer(),
3197                     KMByteBlob.cast(data[OUTPUT_DATA]).getStartOff());
3198       } catch (CryptoException e) {
3199         KMException.throwIt(KMError.INVALID_TAG);
3200       }
3201       if (KMByteBlob.cast(data[INPUT_DATA]).length() > 0) {
3202         // This flag is used to denote that an input data of length > 0 is received and processed
3203         // successfully in update command. This flag is later used in the finish operation
3204         // to handle a particular use case, where a zero length input data on AES/DES algorithm
3205         // with PADDING_NONE should return a zero length output with OK response.
3206         op.setProcessedInputMsg(true);
3207       }
3208       // Adjust the Output data if it is not equal to input data.
3209       // This happens in case of JCardSim provider.
3210       KMByteBlob.cast(data[OUTPUT_DATA]).setLength(len);
3211     }
3212 
3213     if (data[OUTPUT_DATA] == KMType.INVALID_VALUE) {
3214       data[OUTPUT_DATA] = KMByteBlob.instance((short) 0);
3215     }
3216     // Persist if there are any updates.
3217     // op.persist();
3218     // make response
3219     short resp = KMArray.instance((short) 2);
3220     KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK));
3221     KMArray.cast(resp).add((short) 1, data[OUTPUT_DATA]);
3222     sendOutgoing(apdu, resp);
3223   }
3224 
updateAadOperationCmd(APDU apdu)3225   private short updateAadOperationCmd(APDU apdu) {
3226     short cmd = KMArray.instance((short) 4);
3227     KMArray.cast(cmd).add((short) 0, KMInteger.exp());
3228     KMArray.cast(cmd).add((short) 1, KMByteBlob.exp());
3229     short authToken = KMHardwareAuthToken.exp();
3230     KMArray.cast(cmd).add((short) 2, authToken);
3231     short verToken = KMVerificationToken.exp();
3232     KMArray.cast(cmd).add((short) 3, verToken);
3233     return receiveIncoming(apdu, cmd);
3234   }
3235 
processUpdateAadOperationCmd(APDU apdu)3236   private void processUpdateAadOperationCmd(APDU apdu) {
3237     short cmd = updateAadOperationCmd(apdu);
3238     byte[] scratchPad = apdu.getBuffer();
3239     data[OP_HANDLE] = KMArray.cast(cmd).get((short) 0);
3240     data[INPUT_DATA] = KMArray.cast(cmd).get((short) 1);
3241     data[HW_TOKEN] = KMArray.cast(cmd).get((short) 2);
3242     data[VERIFICATION_TOKEN] = KMArray.cast(cmd).get((short) 3);
3243 
3244     // Input data must be present even if it is zero length.
3245     if (data[INPUT_DATA] == KMType.INVALID_VALUE) {
3246       KMException.throwIt(KMError.INVALID_ARGUMENT);
3247     }
3248     // Check Operation Handle and get op state
3249     // Check Operation Handle
3250     KMOperationState op = findOperation(data[OP_HANDLE]);
3251     if (op == null) {
3252       KMException.throwIt(KMError.INVALID_OPERATION_HANDLE);
3253     }
3254     if (op.getAlgorithm() != KMType.AES) {
3255       KMException.throwIt(KMError.INCOMPATIBLE_ALGORITHM);
3256     }
3257     if (op.getBlockMode() != KMType.GCM) {
3258       KMException.throwIt(KMError.INCOMPATIBLE_BLOCK_MODE);
3259     }
3260     if (!op.isAesGcmUpdateAllowed()) {
3261       KMException.throwIt(KMError.INVALID_TAG);
3262     }
3263     if (op.getPurpose() != KMType.ENCRYPT && op.getPurpose() != KMType.DECRYPT) {
3264       KMException.throwIt(KMError.INCOMPATIBLE_PURPOSE);
3265     }
3266     // authorize the update operation
3267     authorizeUpdateFinishOperation(op, scratchPad);
3268     try {
3269       op.getOperation()
3270           .updateAAD(
3271               KMByteBlob.cast(data[INPUT_DATA]).getBuffer(),
3272               KMByteBlob.cast(data[INPUT_DATA]).getStartOff(),
3273               KMByteBlob.cast(data[INPUT_DATA]).length());
3274     } catch (CryptoException exp) {
3275       KMException.throwIt(KMError.UNKNOWN_ERROR);
3276     }
3277     // make response
3278     short resp = KMArray.instance((short) 1);
3279     KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK));
3280     sendOutgoing(apdu, resp);
3281   }
3282 
beginOperationCmd(APDU apdu)3283   private short beginOperationCmd(APDU apdu) {
3284     short cmd = KMArray.instance((short) 4);
3285     // Arguments
3286     short params = KMKeyParameters.expAny();
3287     KMArray.cast(cmd).add((short) 0, KMEnum.instance(KMType.PURPOSE));
3288     KMArray.cast(cmd).add((short) 1, KMByteBlob.exp());
3289     KMArray.cast(cmd).add((short) 2, params);
3290     short authToken = KMHardwareAuthToken.exp();
3291     KMArray.cast(cmd).add((short) 3, authToken);
3292     return receiveIncoming(apdu, cmd);
3293   }
3294 
processBeginOperationCmd(APDU apdu)3295   private void processBeginOperationCmd(APDU apdu) {
3296     // Receive the incoming request fully from the host into buffer.
3297     short cmd = beginOperationCmd(apdu);
3298     byte[] scratchPad = apdu.getBuffer();
3299     short purpose = KMArray.cast(cmd).get((short) 0);
3300     data[KEY_BLOB] = KMArray.cast(cmd).get((short) 1);
3301     data[KEY_PARAMETERS] = KMArray.cast(cmd).get((short) 2);
3302     data[HW_TOKEN] = KMArray.cast(cmd).get((short) 3);
3303     purpose = KMEnum.cast(purpose).getVal();
3304     // Check for app id and app data.
3305     data[APP_ID] = getApplicationId(data[KEY_PARAMETERS]);
3306     data[APP_DATA] = getApplicationData(data[KEY_PARAMETERS]);
3307     // Check if key requires upgrade. The KeyBlob is parsed inside isKeyUpgradeRequired
3308     // function itself.
3309     if (isKeyUpgradeRequired(data[KEY_BLOB], data[APP_ID], data[APP_DATA], scratchPad)) {
3310       KMException.throwIt(KMError.KEY_REQUIRES_UPGRADE);
3311     }
3312     KMTag.assertPresence(
3313         data[SB_PARAMETERS], KMType.ENUM_TAG, KMType.ALGORITHM, KMError.UNSUPPORTED_ALGORITHM);
3314     short algorithm = KMEnumTag.getValue(KMType.ALGORITHM, data[SB_PARAMETERS]);
3315     // If Blob usage tag is present in key characteristics then it should be standalone.
3316     if (KMTag.isPresent(data[SB_PARAMETERS], KMType.ENUM_TAG, KMType.BLOB_USAGE_REQ)) {
3317       if (KMEnumTag.getValue(KMType.BLOB_USAGE_REQ, data[SB_PARAMETERS]) != KMType.STANDALONE) {
3318         KMException.throwIt(KMError.UNSUPPORTED_TAG);
3319       }
3320     }
3321 
3322     // Generate a random number for operation handle
3323     short buf = KMByteBlob.instance(KMOperationState.OPERATION_HANDLE_SIZE);
3324     generateUniqueOperationHandle(
3325         KMByteBlob.cast(buf).getBuffer(),
3326         KMByteBlob.cast(buf).getStartOff(),
3327         KMByteBlob.cast(buf).length());
3328     /* opHandle is a KMInteger and is encoded as KMInteger when it is returned back. */
3329     short opHandle =
3330         KMInteger.instance(
3331             KMByteBlob.cast(buf).getBuffer(),
3332             KMByteBlob.cast(buf).getStartOff(),
3333             KMByteBlob.cast(buf).length());
3334     KMOperationState op = reserveOperation(algorithm, opHandle);
3335     if (op == null) {
3336       KMException.throwIt(KMError.TOO_MANY_OPERATIONS);
3337     }
3338     data[OP_HANDLE] = op.getHandle();
3339     op.setPurpose((byte) purpose);
3340     op.setKeySize(KMByteBlob.cast(data[SECRET]).length());
3341     authorizeAndBeginOperation(op, scratchPad);
3342     switch (op.getPurpose()) {
3343       case KMType.SIGN:
3344         beginTrustedConfirmationOperation(op);
3345       case KMType.VERIFY:
3346         beginSignVerifyOperation(op);
3347         break;
3348       case KMType.ENCRYPT:
3349       case KMType.DECRYPT:
3350         beginCipherOperation(op);
3351         break;
3352       case KMType.AGREE_KEY:
3353         beginKeyAgreementOperation(op);
3354         break;
3355       default:
3356         KMException.throwIt(KMError.UNIMPLEMENTED);
3357         break;
3358     }
3359     short iv = KMType.INVALID_VALUE;
3360     // If the data[IV] is required to be returned.
3361     // As per VTS, for the decryption operation don't send the iv back.
3362     if (data[IV] != KMType.INVALID_VALUE
3363         && op.getPurpose() != KMType.DECRYPT
3364         && op.getBlockMode() != KMType.ECB) {
3365       iv = KMArray.instance((short) 1);
3366       if (op.getAlgorithm() == KMType.DES && op.getBlockMode() == KMType.CBC) {
3367         // For AES/DES we are generate an random iv of length 16 bytes.
3368         // While sending the iv back for DES/CBC mode of opeation only send
3369         // 8 bytes back.
3370         short ivBlob = KMByteBlob.instance((short) 8);
3371         Util.arrayCopy(
3372             KMByteBlob.cast(data[IV]).getBuffer(),
3373             KMByteBlob.cast(data[IV]).getStartOff(),
3374             KMByteBlob.cast(ivBlob).getBuffer(),
3375             KMByteBlob.cast(ivBlob).getStartOff(),
3376             (short) 8);
3377         data[IV] = ivBlob;
3378       }
3379       KMArray.cast(iv).add((short) 0, KMByteTag.instance(KMType.NONCE, data[IV]));
3380     } else {
3381       iv = KMArray.instance((short) 0);
3382     }
3383     short macLen = 0;
3384     if (op.getMacLength() != KMType.INVALID_VALUE) {
3385       macLen = (short) (op.getMacLength() / 8);
3386     }
3387     short params = KMKeyParameters.instance(iv);
3388     short resp = KMArray.instance((short) 5);
3389     KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK));
3390     KMArray.cast(resp).add((short) 1, params);
3391     KMArray.cast(resp).add((short) 2, data[OP_HANDLE]);
3392     KMArray.cast(resp).add((short) 3, KMInteger.uint_8(op.getBufferingMode()));
3393     KMArray.cast(resp).add((short) 4, KMInteger.uint_16(macLen));
3394     sendOutgoing(apdu, resp);
3395   }
3396 
authorizePurpose(KMOperationState op)3397   private void authorizePurpose(KMOperationState op) {
3398     switch (op.getAlgorithm()) {
3399       case KMType.AES:
3400       case KMType.DES:
3401         if (op.getPurpose() == KMType.SIGN
3402             || op.getPurpose() == KMType.VERIFY
3403             || op.getPurpose() == KMType.AGREE_KEY) {
3404           KMException.throwIt(KMError.UNSUPPORTED_PURPOSE);
3405         }
3406         break;
3407       case KMType.EC:
3408         if (op.getPurpose() == KMType.ENCRYPT || op.getPurpose() == KMType.DECRYPT) {
3409           KMException.throwIt(KMError.UNSUPPORTED_PURPOSE);
3410         }
3411         break;
3412       case KMType.HMAC:
3413         if (op.getPurpose() == KMType.ENCRYPT
3414             || op.getPurpose() == KMType.DECRYPT
3415             || op.getPurpose() == KMType.AGREE_KEY) {
3416           KMException.throwIt(KMError.UNSUPPORTED_PURPOSE);
3417         }
3418         break;
3419       case KMType.RSA:
3420         if (op.getPurpose() == KMType.AGREE_KEY) {
3421           KMException.throwIt(KMError.UNSUPPORTED_PURPOSE);
3422         }
3423         break;
3424       default:
3425         break;
3426     }
3427     if (!KMEnumArrayTag.contains(KMType.PURPOSE, op.getPurpose(), data[HW_PARAMETERS])) {
3428       KMException.throwIt(KMError.INCOMPATIBLE_PURPOSE);
3429     }
3430   }
3431 
authorizeDigest(KMOperationState op)3432   private void authorizeDigest(KMOperationState op) {
3433     short digests =
3434         KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.DIGEST, data[HW_PARAMETERS]);
3435     op.setDigest(KMType.DIGEST_NONE);
3436     short param =
3437         KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.DIGEST, data[KEY_PARAMETERS]);
3438     if (param != KMType.INVALID_VALUE) {
3439       if (KMEnumArrayTag.cast(param).length() != 1) {
3440         KMException.throwIt(KMError.UNSUPPORTED_DIGEST);
3441       }
3442       param = KMEnumArrayTag.cast(param).get((short) 0);
3443       if (!KMEnumArrayTag.cast(digests).contains(param)) {
3444         KMException.throwIt(KMError.INCOMPATIBLE_DIGEST);
3445       }
3446       op.setDigest((byte) param);
3447     } else if (KMEnumArrayTag.contains(
3448         KMType.PADDING, KMType.RSA_PKCS1_1_5_SIGN, data[KEY_PARAMETERS])) {
3449       KMException.throwIt(KMError.UNSUPPORTED_DIGEST);
3450     }
3451     short paramPadding =
3452         KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PADDING, data[KEY_PARAMETERS]);
3453     if (paramPadding != KMType.INVALID_VALUE) {
3454       if (KMEnumArrayTag.cast(paramPadding).length() != 1) {
3455         // TODO vts fails because it expects UNSUPPORTED_PADDING_MODE
3456         KMException.throwIt(KMError.UNSUPPORTED_PADDING_MODE);
3457       }
3458       paramPadding = KMEnumArrayTag.cast(paramPadding).get((short) 0);
3459     }
3460     switch (op.getAlgorithm()) {
3461       case KMType.RSA:
3462         if ((paramPadding == KMType.RSA_OAEP || paramPadding == KMType.RSA_PSS)
3463             && param == KMType.INVALID_VALUE) {
3464           KMException.throwIt(KMError.UNSUPPORTED_DIGEST);
3465         }
3466         break;
3467       case KMType.EC:
3468       case KMType.HMAC:
3469         if ((param == KMType.INVALID_VALUE && op.getPurpose() != KMType.AGREE_KEY)
3470             || !isDigestSupported(op.getAlgorithm(), op.getDigest())) {
3471           KMException.throwIt(KMError.UNSUPPORTED_DIGEST);
3472         }
3473         break;
3474       default:
3475         break;
3476     }
3477   }
3478 
authorizePadding(KMOperationState op)3479   private void authorizePadding(KMOperationState op) {
3480     short paddings =
3481         KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PADDING, data[HW_PARAMETERS]);
3482     op.setPadding(KMType.PADDING_NONE);
3483     short param =
3484         KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PADDING, data[KEY_PARAMETERS]);
3485     if (param != KMType.INVALID_VALUE) {
3486       if (KMEnumArrayTag.cast(param).length() != 1) {
3487         KMException.throwIt(KMError.UNSUPPORTED_PADDING_MODE);
3488       }
3489       param = KMEnumArrayTag.cast(param).get((short) 0);
3490       if (!KMEnumArrayTag.cast(paddings).contains(param)) {
3491         KMException.throwIt(KMError.INCOMPATIBLE_PADDING_MODE);
3492       }
3493     }
3494     switch (op.getAlgorithm()) {
3495       case KMType.RSA:
3496         if (param == KMType.INVALID_VALUE) {
3497           KMException.throwIt(KMError.UNSUPPORTED_PADDING_MODE);
3498         }
3499         if ((op.getPurpose() == KMType.SIGN || op.getPurpose() == KMType.VERIFY)
3500             && param != KMType.PADDING_NONE
3501             && param != KMType.RSA_PSS
3502             && param != KMType.RSA_PKCS1_1_5_SIGN) {
3503           KMException.throwIt(KMError.UNSUPPORTED_PADDING_MODE);
3504         }
3505         if ((op.getPurpose() == KMType.ENCRYPT || op.getPurpose() == KMType.DECRYPT)
3506             && param != KMType.PADDING_NONE
3507             && param != KMType.RSA_OAEP
3508             && param != KMType.RSA_PKCS1_1_5_ENCRYPT) {
3509           KMException.throwIt(KMError.UNSUPPORTED_PADDING_MODE);
3510         }
3511 
3512         if (param == KMType.PADDING_NONE && op.getDigest() != KMType.DIGEST_NONE) {
3513           KMException.throwIt(KMError.INCOMPATIBLE_DIGEST);
3514         }
3515         if ((param == KMType.RSA_OAEP || param == KMType.RSA_PSS)
3516             && op.getDigest() == KMType.DIGEST_NONE) {
3517           KMException.throwIt(KMError.INCOMPATIBLE_DIGEST);
3518         }
3519         if (op.getPurpose() == KMType.SIGN
3520             || op.getPurpose() == KMType.VERIFY
3521             || param == KMType.RSA_OAEP) {
3522           // Digest is mandatory in these cases.
3523           if (!isDigestSupported(op.getAlgorithm(), op.getDigest())) {
3524             KMException.throwIt(KMError.UNSUPPORTED_DIGEST);
3525           }
3526         }
3527         if (param == KMType.RSA_OAEP) {
3528           short mgfDigest =
3529               KMKeyParameters.findTag(
3530                   KMType.ENUM_ARRAY_TAG, KMType.RSA_OAEP_MGF_DIGEST, data[KEY_PARAMETERS]);
3531           if (mgfDigest != KMType.INVALID_VALUE) {
3532             if (KMEnumArrayTag.cast(mgfDigest).length() != 1) {
3533               KMException.throwIt(KMError.INVALID_ARGUMENT);
3534             }
3535             mgfDigest = KMEnumArrayTag.cast(mgfDigest).get((short) 0);
3536             if (mgfDigest == KMType.DIGEST_NONE) {
3537               KMException.throwIt(KMError.UNSUPPORTED_MGF_DIGEST);
3538             }
3539 
3540           } else {
3541             mgfDigest = KMType.SHA1;
3542           }
3543           short mgfDigestHwParams =
3544               KMKeyParameters.findTag(
3545                   KMType.ENUM_ARRAY_TAG, KMType.RSA_OAEP_MGF_DIGEST, data[HW_PARAMETERS]);
3546           if ((mgfDigestHwParams != KMType.INVALID_VALUE)
3547               && (!KMEnumArrayTag.cast(mgfDigestHwParams).contains(mgfDigest))) {
3548             KMException.throwIt(KMError.INCOMPATIBLE_MGF_DIGEST);
3549           }
3550           if (mgfDigest != KMType.SHA1 && mgfDigest != KMType.SHA2_256) {
3551             KMException.throwIt(KMError.UNSUPPORTED_MGF_DIGEST);
3552           }
3553           op.setMgfDigest((byte) mgfDigest);
3554         }
3555         op.setPadding((byte) param);
3556         break;
3557       case KMType.DES:
3558       case KMType.AES:
3559         if (param == KMType.INVALID_VALUE) {
3560           KMException.throwIt(KMError.UNSUPPORTED_PADDING_MODE);
3561         }
3562         op.setPadding((byte) param);
3563         break;
3564       default:
3565         break;
3566     }
3567   }
3568 
authorizeBlockModeAndMacLength(KMOperationState op)3569   private void authorizeBlockModeAndMacLength(KMOperationState op) {
3570     short param =
3571         KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.BLOCK_MODE, data[KEY_PARAMETERS]);
3572     if (param != KMType.INVALID_VALUE) {
3573       if (KMEnumArrayTag.cast(param).length() != 1) {
3574         KMException.throwIt(KMError.UNSUPPORTED_BLOCK_MODE);
3575       }
3576       param = KMEnumArrayTag.cast(param).get((short) 0);
3577     }
3578     if (KMType.AES == op.getAlgorithm() || KMType.DES == op.getAlgorithm()) {
3579       if (!KMEnumArrayTag.contains(KMType.BLOCK_MODE, param, data[HW_PARAMETERS])) {
3580         KMException.throwIt(KMError.INCOMPATIBLE_BLOCK_MODE);
3581       }
3582     }
3583     short macLen =
3584         KMIntegerTag.getShortValue(KMType.UINT_TAG, KMType.MAC_LENGTH, data[KEY_PARAMETERS]);
3585     switch (op.getAlgorithm()) {
3586       case KMType.AES:
3587         // Validate the block mode.
3588         switch (param) {
3589           case KMType.ECB:
3590           case KMType.CBC:
3591           case KMType.CTR:
3592           case KMType.GCM:
3593             break;
3594           default:
3595             KMException.throwIt(KMError.UNSUPPORTED_BLOCK_MODE);
3596         }
3597         if (param == KMType.GCM) {
3598           if (op.getPadding() != KMType.PADDING_NONE || op.getPadding() == KMType.PKCS7) {
3599             KMException.throwIt(KMError.INCOMPATIBLE_PADDING_MODE);
3600           }
3601           if (macLen == KMType.INVALID_VALUE) {
3602             KMException.throwIt(KMError.MISSING_MAC_LENGTH);
3603           }
3604           short minMacLen =
3605               KMIntegerTag.getShortValue(
3606                   KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, data[HW_PARAMETERS]);
3607           if (minMacLen == KMType.INVALID_VALUE) {
3608             KMException.throwIt(KMError.INVALID_KEY_BLOB);
3609           }
3610           if (macLen % 8 != 0
3611               || macLen > MAX_GCM_TAG_LENGTH_BITS
3612               || macLen < MIN_GCM_TAG_LENGTH_BITS) {
3613             KMException.throwIt(KMError.UNSUPPORTED_MAC_LENGTH);
3614           }
3615           if (macLen < minMacLen) {
3616             KMException.throwIt(KMError.INVALID_MAC_LENGTH);
3617           }
3618           op.setMacLength(macLen);
3619         }
3620         if (param == KMType.CTR) {
3621           if (op.getPadding() != KMType.PADDING_NONE || op.getPadding() == KMType.PKCS7) {
3622             KMException.throwIt(KMError.INCOMPATIBLE_PADDING_MODE);
3623           }
3624         }
3625         break;
3626       case KMType.DES:
3627         // Validate the block mode.
3628         switch (param) {
3629           case KMType.ECB:
3630           case KMType.CBC:
3631             break;
3632           default:
3633             KMException.throwIt(KMError.UNSUPPORTED_BLOCK_MODE);
3634         }
3635         if (param == KMType.INVALID_VALUE) {
3636           KMException.throwIt(KMError.INVALID_ARGUMENT);
3637         }
3638         break;
3639       case KMType.HMAC:
3640         short minMacLen =
3641             KMIntegerTag.getShortValue(KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, data[HW_PARAMETERS]);
3642         if (minMacLen == KMType.INVALID_VALUE) {
3643           KMException.throwIt(KMError.INVALID_KEY_BLOB);
3644         }
3645         op.setMinMacLength(minMacLen);
3646         if (macLen == KMType.INVALID_VALUE) {
3647           if (op.getPurpose() == KMType.SIGN) {
3648             KMException.throwIt(KMError.MISSING_MAC_LENGTH);
3649           }
3650         } else {
3651           // MAC length may not be specified for verify.
3652           if (op.getPurpose() == KMType.VERIFY) {
3653             KMException.throwIt(KMError.INVALID_ARGUMENT);
3654           }
3655           if (macLen % 8 != 0 || macLen > SHA256_DIGEST_LEN_BITS || macLen < MIN_HMAC_LENGTH_BITS) {
3656             KMException.throwIt(KMError.UNSUPPORTED_MAC_LENGTH);
3657           }
3658           if (macLen < minMacLen) {
3659             KMException.throwIt(KMError.INVALID_MAC_LENGTH);
3660           }
3661           op.setMacLength(macLen);
3662         }
3663         break;
3664       default:
3665         break;
3666     }
3667     op.setBlockMode((byte) param);
3668   }
3669 
authorizeAndBeginOperation(KMOperationState op, byte[] scratchPad)3670   private void authorizeAndBeginOperation(KMOperationState op, byte[] scratchPad) {
3671     authorizePurpose(op);
3672     authorizeDigest(op);
3673     authorizePadding(op);
3674     authorizeBlockModeAndMacLength(op);
3675     if (!validateHwToken(data[HW_TOKEN], scratchPad)) {
3676       data[HW_TOKEN] = KMType.INVALID_VALUE;
3677     }
3678     authorizeUserSecureIdAuthTimeout(op, scratchPad);
3679     authorizeDeviceUnlock(scratchPad);
3680     authorizeKeyUsageForCount(scratchPad);
3681 
3682     KMTag.assertAbsence(
3683         data[HW_PARAMETERS], KMType.BOOL_TAG, KMType.BOOTLOADER_ONLY, KMError.INVALID_KEY_BLOB);
3684 
3685     // Validate early boot
3686     // VTS expects error code EARLY_BOOT_ONLY during begin operation if early boot ended tag is
3687     // present
3688     if (kmDataStore.getEarlyBootEndedStatus()) {
3689       KMTag.assertAbsence(
3690           data[HW_PARAMETERS], KMType.BOOL_TAG, KMType.EARLY_BOOT_ONLY, KMError.EARLY_BOOT_ENDED);
3691     }
3692 
3693     // Authorize Caller Nonce - if caller nonce absent in key char and nonce present in
3694     // key params then fail if it is not a Decrypt operation
3695     data[IV] = KMType.INVALID_VALUE;
3696 
3697     if (!KMTag.isPresent(data[HW_PARAMETERS], KMType.BOOL_TAG, KMType.CALLER_NONCE)
3698         && KMTag.isPresent(data[KEY_PARAMETERS], KMType.BYTES_TAG, KMType.NONCE)
3699         && op.getPurpose() != KMType.DECRYPT) {
3700       KMException.throwIt(KMError.CALLER_NONCE_PROHIBITED);
3701     }
3702 
3703     short nonce = KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.NONCE, data[KEY_PARAMETERS]);
3704     // If Nonce is present then check whether the size of nonce is correct.
3705     if (nonce != KMType.INVALID_VALUE) {
3706       data[IV] = KMByteTag.cast(nonce).getValue();
3707       // For CBC mode - iv must be 8 bytes
3708       if (op.getBlockMode() == KMType.CBC
3709           && op.getAlgorithm() == KMType.DES
3710           && KMByteBlob.cast(data[IV]).length() != 8) {
3711         KMException.throwIt(KMError.INVALID_NONCE);
3712       }
3713 
3714       // For GCM mode - IV must be 12 bytes
3715       if (KMByteBlob.cast(data[IV]).length() != 12 && op.getBlockMode() == KMType.GCM) {
3716         KMException.throwIt(KMError.INVALID_NONCE);
3717       }
3718 
3719       // For AES CBC and CTR modes IV must be 16 bytes
3720       if ((op.getBlockMode() == KMType.CBC || op.getBlockMode() == KMType.CTR)
3721           && op.getAlgorithm() == KMType.AES
3722           && KMByteBlob.cast(data[IV]).length() != 16) {
3723         KMException.throwIt(KMError.INVALID_NONCE);
3724       }
3725     } else if (op.getAlgorithm() == KMType.AES || op.getAlgorithm() == KMType.DES) {
3726 
3727       // For symmetric decryption iv is required
3728       if (op.getPurpose() == KMType.DECRYPT
3729           && (op.getBlockMode() == KMType.CBC
3730               || op.getBlockMode() == KMType.GCM
3731               || op.getBlockMode() == KMType.CTR)) {
3732         KMException.throwIt(KMError.MISSING_NONCE);
3733       } else if (op.getBlockMode() == KMType.ECB) {
3734         // For ECB we create zero length nonce
3735         data[IV] = KMByteBlob.instance((short) 0);
3736       } else if (op.getPurpose() == KMType.ENCRYPT) {
3737 
3738         // For encrypt mode if nonce is absent then create random nonce of correct length
3739         byte ivLen = 16;
3740         if (op.getBlockMode() == KMType.GCM) {
3741           ivLen = 12;
3742         } else if (op.getAlgorithm() == KMType.DES) {
3743           ivLen = 8;
3744         }
3745         data[IV] = KMByteBlob.instance(ivLen);
3746         seProvider.newRandomNumber(
3747             KMByteBlob.cast(data[IV]).getBuffer(),
3748             KMByteBlob.cast(data[IV]).getStartOff(),
3749             KMByteBlob.cast(data[IV]).length());
3750       }
3751     }
3752   }
3753 
beginKeyAgreementOperation(KMOperationState op)3754   private void beginKeyAgreementOperation(KMOperationState op) {
3755     if (op.getAlgorithm() != KMType.EC) {
3756       KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM);
3757     }
3758 
3759     op.setOperation(
3760         seProvider.initAsymmetricOperation(
3761             (byte) op.getPurpose(),
3762             (byte) op.getAlgorithm(),
3763             (byte) op.getPadding(),
3764             (byte) op.getDigest(),
3765             KMType.DIGEST_NONE, /* No MGF1 Digest */
3766             KMByteBlob.cast(data[SECRET]).getBuffer(),
3767             KMByteBlob.cast(data[SECRET]).getStartOff(),
3768             KMByteBlob.cast(data[SECRET]).length(),
3769             null,
3770             (short) 0,
3771             (short) 0));
3772   }
3773 
beginCipherOperation(KMOperationState op)3774   private void beginCipherOperation(KMOperationState op) {
3775     switch (op.getAlgorithm()) {
3776       case KMType.RSA:
3777         try {
3778           if (op.getPurpose() == KMType.DECRYPT) {
3779             op.setOperation(
3780                 seProvider.initAsymmetricOperation(
3781                     (byte) op.getPurpose(),
3782                     (byte) op.getAlgorithm(),
3783                     (byte) op.getPadding(),
3784                     (byte) op.getDigest(),
3785                     (byte) op.getMgfDigest(),
3786                     KMByteBlob.cast(data[SECRET]).getBuffer(),
3787                     KMByteBlob.cast(data[SECRET]).getStartOff(),
3788                     KMByteBlob.cast(data[SECRET]).length(),
3789                     KMByteBlob.cast(data[PUB_KEY]).getBuffer(),
3790                     KMByteBlob.cast(data[PUB_KEY]).getStartOff(),
3791                     KMByteBlob.cast(data[PUB_KEY]).length()));
3792           } else {
3793             KMException.throwIt(KMError.UNSUPPORTED_PURPOSE);
3794           }
3795         } catch (CryptoException exp) {
3796           KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM);
3797         }
3798         break;
3799       case KMType.AES:
3800       case KMType.DES:
3801         if (op.getBlockMode() == KMType.GCM) {
3802           op.setAesGcmUpdateStart();
3803         }
3804         try {
3805           op.setOperation(
3806               seProvider.initSymmetricOperation(
3807                   (byte) op.getPurpose(),
3808                   (byte) op.getAlgorithm(),
3809                   (byte) op.getDigest(),
3810                   (byte) op.getPadding(),
3811                   (byte) op.getBlockMode(),
3812                   KMByteBlob.cast(data[SECRET]).getBuffer(),
3813                   KMByteBlob.cast(data[SECRET]).getStartOff(),
3814                   KMByteBlob.cast(data[SECRET]).length(),
3815                   KMByteBlob.cast(data[IV]).getBuffer(),
3816                   KMByteBlob.cast(data[IV]).getStartOff(),
3817                   KMByteBlob.cast(data[IV]).length(),
3818                   op.getMacLength()));
3819         } catch (CryptoException exception) {
3820           if (exception.getReason() == CryptoException.ILLEGAL_VALUE) {
3821             KMException.throwIt(KMError.INVALID_ARGUMENT);
3822           } else if (exception.getReason() == CryptoException.NO_SUCH_ALGORITHM) {
3823             KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM);
3824           }
3825         }
3826     }
3827   }
3828 
beginTrustedConfirmationOperation(KMOperationState op)3829   private void beginTrustedConfirmationOperation(KMOperationState op) {
3830     // Check for trusted confirmation - if required then set the signer in op state.
3831     if (KMKeyParameters.findTag(
3832             KMType.BOOL_TAG, KMType.TRUSTED_CONFIRMATION_REQUIRED, data[HW_PARAMETERS])
3833         != KMType.INVALID_VALUE) {
3834 
3835       op.setTrustedConfirmationSigner(
3836           seProvider.initTrustedConfirmationSymmetricOperation(kmDataStore.getComputedHmacKey()));
3837 
3838       op.getTrustedConfirmationSigner()
3839           .update(confirmationToken, (short) 0, (short) confirmationToken.length);
3840     }
3841   }
3842 
beginSignVerifyOperation(KMOperationState op)3843   private void beginSignVerifyOperation(KMOperationState op) {
3844     switch (op.getAlgorithm()) {
3845       case KMType.RSA:
3846         try {
3847           if (op.getPurpose() == KMType.SIGN) {
3848             op.setOperation(
3849                 seProvider.initAsymmetricOperation(
3850                     (byte) op.getPurpose(),
3851                     (byte) op.getAlgorithm(),
3852                     (byte) op.getPadding(),
3853                     (byte) op.getDigest(),
3854                     KMType.DIGEST_NONE, /* No MGF Digest */
3855                     KMByteBlob.cast(data[SECRET]).getBuffer(),
3856                     KMByteBlob.cast(data[SECRET]).getStartOff(),
3857                     KMByteBlob.cast(data[SECRET]).length(),
3858                     KMByteBlob.cast(data[PUB_KEY]).getBuffer(),
3859                     KMByteBlob.cast(data[PUB_KEY]).getStartOff(),
3860                     KMByteBlob.cast(data[PUB_KEY]).length()));
3861           } else {
3862             KMException.throwIt(KMError.UNSUPPORTED_PURPOSE);
3863           }
3864         } catch (CryptoException exp) {
3865           KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM);
3866         }
3867         break;
3868       case KMType.EC:
3869         try {
3870           if (op.getPurpose() == KMType.SIGN) {
3871             op.setOperation(
3872                 seProvider.initAsymmetricOperation(
3873                     (byte) op.getPurpose(),
3874                     (byte) op.getAlgorithm(),
3875                     (byte) op.getPadding(),
3876                     (byte) op.getDigest(),
3877                     KMType.DIGEST_NONE, /* No MGF Digest */
3878                     KMByteBlob.cast(data[SECRET]).getBuffer(),
3879                     KMByteBlob.cast(data[SECRET]).getStartOff(),
3880                     KMByteBlob.cast(data[SECRET]).length(),
3881                     null,
3882                     (short) 0,
3883                     (short) 0));
3884           } else {
3885             KMException.throwIt(KMError.UNSUPPORTED_PURPOSE);
3886           }
3887         } catch (CryptoException exp) {
3888           // Javacard does not support NO digest based signing.
3889           KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM);
3890         }
3891         break;
3892       case KMType.HMAC:
3893         // As per Keymaster HAL documentation, the length of the Hmac output can
3894         // be decided by using TAG_MAC_LENGTH in Keyparameters. But there is no
3895         // such provision to control the length of the Hmac output using JavaCard
3896         // crypto APIs and the current implementation always returns 32 bytes
3897         // length of Hmac output. So to provide support to TAG_MAC_LENGTH
3898         // feature, we truncate the output signature to TAG_MAC_LENGTH and return
3899         // the truncated signature back to the caller. At the time of verfication
3900         // we again compute the signature of the plain text input, truncate it to
3901         // TAG_MAC_LENGTH and compare it with the input signature for
3902         // verification. So this is the reason we are using KMType.SIGN directly
3903         // instead of using op.getPurpose().
3904         try {
3905           op.setOperation(
3906               seProvider.initSymmetricOperation(
3907                   (byte) KMType.SIGN,
3908                   (byte) op.getAlgorithm(),
3909                   (byte) op.getDigest(),
3910                   (byte) op.getPadding(),
3911                   (byte) op.getBlockMode(),
3912                   KMByteBlob.cast(data[SECRET]).getBuffer(),
3913                   KMByteBlob.cast(data[SECRET]).getStartOff(),
3914                   KMByteBlob.cast(data[SECRET]).length(),
3915                   null,
3916                   (short) 0,
3917                   (short) 0,
3918                   (short) 0));
3919         } catch (CryptoException exp) {
3920           KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM);
3921         }
3922         break;
3923       default:
3924         KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM);
3925         break;
3926     }
3927   }
3928 
isHwAuthTokenContainsMatchingSecureId(short hwAuthToken, short secureUserIdsObj)3929   private boolean isHwAuthTokenContainsMatchingSecureId(short hwAuthToken, short secureUserIdsObj) {
3930     short secureUserId = KMHardwareAuthToken.cast(hwAuthToken).getUserId();
3931     if (!KMInteger.cast(secureUserId).isZero()) {
3932       if (KMIntegerArrayTag.cast(secureUserIdsObj).contains(secureUserId)) {
3933         return true;
3934       }
3935     }
3936 
3937     short authenticatorId = KMHardwareAuthToken.cast(hwAuthToken).getAuthenticatorId();
3938     if (!KMInteger.cast(authenticatorId).isZero()) {
3939       if (KMIntegerArrayTag.cast(secureUserIdsObj).contains(authenticatorId)) {
3940         return true;
3941       }
3942     }
3943     return false;
3944   }
3945 
hwAuthTypeMatches( byte[] buf, short off, short len, byte[] scratchPad, short scratchOff)3946   public boolean hwAuthTypeMatches(
3947       byte[] buf, short off, short len, byte[] scratchPad, short scratchOff) {
3948     Util.arrayFillNonAtomic(scratchPad, scratchOff, (short) (2 * KMInteger.UINT_32), (byte) 0);
3949     short enumPtr = KMHardwareAuthToken.cast(data[HW_TOKEN]).getHwAuthenticatorType();
3950     if (KMInteger.UINT_32 != KMEnum.cast(enumPtr).value(scratchPad, scratchOff)) {
3951       return false;
3952     }
3953     Util.arrayCopyNonAtomic(
3954         buf, off, scratchPad, (short) (scratchOff + 2 * KMInteger.UINT_32 - len), len);
3955     short highShort = Util.getShort(scratchPad, scratchOff);
3956     short lowShort = Util.getShort(scratchPad, (short) (scratchOff + 2));
3957     short otherHighShort = Util.getShort(scratchPad, (short) (scratchOff + KMInteger.UINT_32));
3958     short otherLowShort = Util.getShort(scratchPad, (short) (scratchOff + KMInteger.UINT_32 + 2));
3959     return (0 != (lowShort & otherLowShort) || 0 != (highShort & otherHighShort));
3960   }
3961 
authTokenMatches( short userSecureIdsPtr, byte[] buf, short off, short len, byte[] scratchPad, short scratchOff)3962   private boolean authTokenMatches(
3963       short userSecureIdsPtr,
3964       byte[] buf,
3965       short off,
3966       short len,
3967       byte[] scratchPad,
3968       short scratchOff) {
3969     if (data[HW_TOKEN] == KMType.INVALID_VALUE) {
3970       return false;
3971     }
3972     if (!isHwAuthTokenContainsMatchingSecureId(data[HW_TOKEN], userSecureIdsPtr)) {
3973       return false;
3974     }
3975     // check auth type
3976     return hwAuthTypeMatches(buf, off, len, scratchPad, scratchOff);
3977   }
3978 
authorizeUserSecureIdAuthTimeout(KMOperationState op, byte[] scratchPad)3979   private void authorizeUserSecureIdAuthTimeout(KMOperationState op, byte[] scratchPad) {
3980     short authTime;
3981     short authType;
3982     // Authorize User Secure Id and Auth timeout
3983     short userSecureIdPtr =
3984         KMKeyParameters.findTag(KMType.ULONG_ARRAY_TAG, KMType.USER_SECURE_ID, data[HW_PARAMETERS]);
3985     if (userSecureIdPtr != KMType.INVALID_VALUE) {
3986       // Authentication required.
3987       if (KMType.INVALID_VALUE
3988           != KMKeyParameters.findTag(
3989               KMType.BOOL_TAG, KMType.NO_AUTH_REQUIRED, data[HW_PARAMETERS])) {
3990         // Key has both USER_SECURE_ID and NO_AUTH_REQUIRED
3991         KMException.throwIt(KMError.INVALID_KEY_BLOB);
3992       }
3993       // authenticator type must be provided.
3994       if (KMType.INVALID_VALUE
3995           == (authType =
3996               KMKeyParameters.findTag(
3997                   KMType.ENUM_TAG, KMType.USER_AUTH_TYPE, data[HW_PARAMETERS]))) {
3998         // Authentication required, but no auth type found.
3999         KMException.throwIt(KMError.KEY_USER_NOT_AUTHENTICATED);
4000       }
4001       short len = KMEnumTag.cast(authType).value(scratchPad, (short) 0);
4002 
4003       short authTimeoutTagPtr =
4004           KMKeyParameters.findTag(KMType.UINT_TAG, KMType.AUTH_TIMEOUT, data[HW_PARAMETERS]);
4005       if (authTimeoutTagPtr != KMType.INVALID_VALUE) {
4006         // authenticate user
4007         if (!authTokenMatches(userSecureIdPtr, scratchPad, (short) 0, len, scratchPad, len)) {
4008           KMException.throwIt(KMError.KEY_USER_NOT_AUTHENTICATED);
4009         }
4010 
4011         authTimeoutTagPtr =
4012             KMKeyParameters.findTag(
4013                 KMType.ULONG_TAG, KMType.AUTH_TIMEOUT_MILLIS, data[CUSTOM_TAGS]);
4014         if (authTimeoutTagPtr == KMType.INVALID_VALUE) {
4015           KMException.throwIt(KMError.INVALID_KEY_BLOB);
4016         }
4017         authTime = KMIntegerTag.cast(authTimeoutTagPtr).getValue();
4018         // set the one time auth
4019         op.setOneTimeAuthReqd(true);
4020         // set the authentication time stamp in operation state
4021         authTime =
4022             addIntegers(
4023                 authTime, KMHardwareAuthToken.cast(data[HW_TOKEN]).getTimestamp(), scratchPad);
4024         op.setAuthTime(
4025             KMInteger.cast(authTime).getBuffer(), KMInteger.cast(authTime).getStartOff());
4026         // auth time validation will happen in update or finish
4027         op.setAuthTimeoutValidated(false);
4028       } else {
4029         // auth per operation required
4030         // store user secure id and authType in OperationState.
4031         op.setUserSecureId(userSecureIdPtr);
4032         op.setAuthType(scratchPad, (short) 0, len);
4033         // set flags
4034         op.setOneTimeAuthReqd(false);
4035         op.setAuthPerOperationReqd(true);
4036       }
4037     }
4038   }
4039 
verifyHwTokenMacInBigEndian(short hwToken, byte[] scratchPad)4040   private boolean verifyHwTokenMacInBigEndian(short hwToken, byte[] scratchPad) {
4041     // The challenge, userId and authenticatorId, authenticatorType and timestamp
4042     // are in network order (big-endian).
4043     short len = 0;
4044     // add 0
4045     Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0);
4046     len = 1;
4047     // concatenate challenge - 8 bytes
4048     short ptr = KMHardwareAuthToken.cast(hwToken).getChallenge();
4049     KMInteger.cast(ptr)
4050         .value(
4051             scratchPad, (short) (len + (short) (KMInteger.UINT_64 - KMInteger.cast(ptr).length())));
4052     len += KMInteger.UINT_64;
4053     // concatenate user id - 8 bytes
4054     ptr = KMHardwareAuthToken.cast(hwToken).getUserId();
4055     KMInteger.cast(ptr)
4056         .value(
4057             scratchPad, (short) (len + (short) (KMInteger.UINT_64 - KMInteger.cast(ptr).length())));
4058     len += KMInteger.UINT_64;
4059     // concatenate authenticator id - 8 bytes
4060     ptr = KMHardwareAuthToken.cast(hwToken).getAuthenticatorId();
4061     KMInteger.cast(ptr)
4062         .value(
4063             scratchPad, (short) (len + (short) (KMInteger.UINT_64 - KMInteger.cast(ptr).length())));
4064     len += KMInteger.UINT_64;
4065     // concatenate authenticator type - 4 bytes
4066     ptr = KMHardwareAuthToken.cast(hwToken).getHwAuthenticatorType();
4067     KMEnum.cast(ptr).value(scratchPad, len);
4068     len += KMInteger.UINT_32;
4069     // concatenate timestamp -8 bytes
4070     ptr = KMHardwareAuthToken.cast(hwToken).getTimestamp();
4071     KMInteger.cast(ptr)
4072         .value(
4073             scratchPad, (short) (len + (short) (KMInteger.UINT_64 - KMInteger.cast(ptr).length())));
4074     len += KMInteger.UINT_64;
4075 
4076     ptr = KMHardwareAuthToken.cast(hwToken).getMac();
4077 
4078     return seProvider.hmacVerify(
4079         kmDataStore.getComputedHmacKey(),
4080         scratchPad,
4081         (short) 0,
4082         len,
4083         KMByteBlob.cast(ptr).getBuffer(),
4084         KMByteBlob.cast(ptr).getStartOff(),
4085         KMByteBlob.cast(ptr).length());
4086   }
4087 
verifyHwTokenMacInLittleEndian(short hwToken, byte[] scratchPad)4088   private boolean verifyHwTokenMacInLittleEndian(short hwToken, byte[] scratchPad) {
4089     // The challenge, userId and authenticatorId values are in little endian order,
4090     // but authenticatorType and timestamp are in network order (big-endian).
4091     short len = 0;
4092     // add 0
4093     Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0);
4094     len = 1;
4095     // concatenate challenge - 8 bytes
4096     short ptr = KMHardwareAuthToken.cast(hwToken).getChallenge();
4097     KMInteger.cast(ptr).toLittleEndian(scratchPad, len);
4098     len += KMInteger.UINT_64;
4099     // concatenate user id - 8 bytes
4100     ptr = KMHardwareAuthToken.cast(hwToken).getUserId();
4101     KMInteger.cast(ptr).toLittleEndian(scratchPad, len);
4102     len += KMInteger.UINT_64;
4103     // concatenate authenticator id - 8 bytes
4104     ptr = KMHardwareAuthToken.cast(hwToken).getAuthenticatorId();
4105     KMInteger.cast(ptr).toLittleEndian(scratchPad, len);
4106     len += KMInteger.UINT_64;
4107     // concatenate authenticator type - 4 bytes
4108     ptr = KMHardwareAuthToken.cast(hwToken).getHwAuthenticatorType();
4109     KMEnum.cast(ptr).value(scratchPad, len);
4110     len += KMInteger.UINT_32;
4111     // concatenate timestamp - 8 bytes
4112     ptr = KMHardwareAuthToken.cast(hwToken).getTimestamp();
4113     KMInteger.cast(ptr)
4114         .value(scratchPad, (short) (len + (short) (8 - KMInteger.cast(ptr).length())));
4115     len += KMInteger.UINT_64;
4116 
4117     ptr = KMHardwareAuthToken.cast(hwToken).getMac();
4118 
4119     return seProvider.hmacVerify(
4120         kmDataStore.getComputedHmacKey(),
4121         scratchPad,
4122         (short) 0,
4123         len,
4124         KMByteBlob.cast(ptr).getBuffer(),
4125         KMByteBlob.cast(ptr).getStartOff(),
4126         KMByteBlob.cast(ptr).length());
4127   }
4128 
validateHwToken(short hwToken, byte[] scratchPad)4129   private boolean validateHwToken(short hwToken, byte[] scratchPad) {
4130     // CBOR Encoding is always big endian
4131     short ptr = KMHardwareAuthToken.cast(hwToken).getMac();
4132     // If mac length is zero then token is empty.
4133     if (KMByteBlob.cast(ptr).length() == 0) {
4134       return false;
4135     }
4136     if (KMConfigurations.TEE_MACHINE_TYPE == KMConfigurations.LITTLE_ENDIAN) {
4137       return verifyHwTokenMacInLittleEndian(hwToken, scratchPad);
4138     } else {
4139       return verifyHwTokenMacInBigEndian(hwToken, scratchPad);
4140     }
4141   }
4142 
importKeyCmd(APDU apdu)4143   private short importKeyCmd(APDU apdu) {
4144     short cmd = KMArray.instance((short) 6);
4145     // Arguments
4146     short params = KMKeyParameters.expAny();
4147     KMArray.cast(cmd).add((short) 0, params);
4148     KMArray.cast(cmd).add((short) 1, KMEnum.instance(KMType.KEY_FORMAT));
4149     KMArray.cast(cmd).add((short) 2, KMByteBlob.exp());
4150     KMArray.cast(cmd).add((short) 3, KMByteBlob.exp()); // attest key
4151     KMArray.cast(cmd).add((short) 4, params); // attest key params
4152     KMArray.cast(cmd).add((short) 5, KMByteBlob.exp()); // issuer
4153     return receiveIncoming(apdu, cmd);
4154   }
4155 
processImportKeyCmd(APDU apdu)4156   private void processImportKeyCmd(APDU apdu) {
4157     // Receive the incoming request fully from the host into buffer.
4158     short cmd = importKeyCmd(apdu);
4159     byte[] scratchPad = apdu.getBuffer();
4160     data[KEY_PARAMETERS] = KMArray.cast(cmd).get((short) 0);
4161     short keyFmt = KMArray.cast(cmd).get((short) 1);
4162     data[IMPORTED_KEY_BLOB] = KMArray.cast(cmd).get((short) 2);
4163     data[ATTEST_KEY_BLOB] = KMArray.cast(cmd).get((short) 3);
4164     data[ATTEST_KEY_PARAMS] = KMArray.cast(cmd).get((short) 4);
4165     data[ATTEST_KEY_ISSUER] = KMArray.cast(cmd).get((short) 5);
4166     keyFmt = KMEnum.cast(keyFmt).getVal();
4167 
4168     data[CERTIFICATE] = KMArray.instance((short) 0); // by default the cert is empty.
4169     data[ORIGIN] = KMType.IMPORTED;
4170     importKey(apdu, keyFmt, scratchPad);
4171   }
4172 
validateImportKey(short params, short keyFmt)4173   private void validateImportKey(short params, short keyFmt) {
4174     short attKeyPurpose = KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PURPOSE, params);
4175     // ATTEST_KEY cannot be combined with any other purpose.
4176     if (attKeyPurpose != KMType.INVALID_VALUE
4177         && KMEnumArrayTag.cast(attKeyPurpose).contains(KMType.ATTEST_KEY)
4178         && KMEnumArrayTag.cast(attKeyPurpose).length() > 1) {
4179       KMException.throwIt(KMError.INCOMPATIBLE_PURPOSE);
4180     }
4181     // Rollback protection not supported
4182     KMTag.assertAbsence(
4183         params,
4184         KMType.BOOL_TAG,
4185         KMType.ROLLBACK_RESISTANCE,
4186         KMError.ROLLBACK_RESISTANCE_UNAVAILABLE);
4187     // As per specification, Early boot keys may not be imported at all, if Tag::EARLY_BOOT_ONLY is
4188     // provided to IKeyMintDevice::importKey
4189     KMTag.assertAbsence(params, KMType.BOOL_TAG, KMType.EARLY_BOOT_ONLY, KMError.EARLY_BOOT_ENDED);
4190     // Check if the tags are supported.
4191     if (KMKeyParameters.hasUnsupportedTags(params)) {
4192       KMException.throwIt(KMError.UNSUPPORTED_TAG);
4193     }
4194     // Algorithm must be present
4195     KMTag.assertPresence(params, KMType.ENUM_TAG, KMType.ALGORITHM, KMError.INVALID_ARGUMENT);
4196     short alg = KMEnumTag.getValue(KMType.ALGORITHM, params);
4197     // key format must be raw if aes, des or hmac and pkcs8 for rsa and ec.
4198     if ((alg == KMType.AES || alg == KMType.DES || alg == KMType.HMAC) && keyFmt != KMType.RAW) {
4199       KMException.throwIt(KMError.UNIMPLEMENTED);
4200     }
4201     if ((alg == KMType.RSA || alg == KMType.EC) && keyFmt != KMType.PKCS8) {
4202       KMException.throwIt(KMError.UNIMPLEMENTED);
4203     }
4204   }
4205 
importKey(APDU apdu, short keyFmt, byte[] scratchPad)4206   private void importKey(APDU apdu, short keyFmt, byte[] scratchPad) {
4207     validateImportKey(data[KEY_PARAMETERS], keyFmt);
4208     // Check algorithm and dispatch to appropriate handler.
4209     short alg = KMEnumTag.getValue(KMType.ALGORITHM, data[KEY_PARAMETERS]);
4210     switch (alg) {
4211       case KMType.RSA:
4212         importRSAKey(scratchPad);
4213         break;
4214       case KMType.AES:
4215         importAESKey(scratchPad);
4216         break;
4217       case KMType.DES:
4218         importTDESKey(scratchPad);
4219         break;
4220       case KMType.HMAC:
4221         importHmacKey(scratchPad);
4222         break;
4223       case KMType.EC:
4224         importECKeys(scratchPad);
4225         break;
4226       default:
4227         KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM);
4228         break;
4229     }
4230     makeKeyCharacteristics(scratchPad);
4231     KMAttestationCert cert =
4232         generateAttestation(data[ATTEST_KEY_BLOB], data[ATTEST_KEY_PARAMS], scratchPad);
4233     createEncryptedKeyBlob(scratchPad);
4234     sendOutgoing(apdu, cert, data[CERTIFICATE], data[KEY_BLOB], data[KEY_CHARACTERISTICS]);
4235   }
4236 
importECKeys(byte[] scratchPad)4237   private void importECKeys(byte[] scratchPad) {
4238     // Decode key material
4239     KMAsn1Parser pkcs8 = KMAsn1Parser.instance();
4240     short keyBlob = pkcs8.decodeEc(data[IMPORTED_KEY_BLOB]);
4241     data[PUB_KEY] = KMArray.cast(keyBlob).get((short) 0);
4242     data[SECRET] = KMArray.cast(keyBlob).get((short) 1);
4243     // initialize 256 bit p256 key for given private key and public key.
4244     short index = 0;
4245     // check whether the key size tag is present in key parameters.
4246     short SecretLen = (short) (KMByteBlob.length(data[SECRET]) * 8);
4247     short keySize =
4248         KMIntegerTag.getShortValue(KMType.UINT_TAG, KMType.KEYSIZE, data[KEY_PARAMETERS]);
4249     if (keySize != KMType.INVALID_VALUE) {
4250       // As per NIST.SP.800-186 page 9,  secret for 256 curve should be between
4251       // 256-383
4252       if (((256 <= SecretLen) && (383 >= SecretLen)) ^ keySize == 256) {
4253         KMException.throwIt(KMError.IMPORT_PARAMETER_MISMATCH);
4254       }
4255       if (keySize != 256) {
4256         KMException.throwIt(KMError.UNSUPPORTED_KEY_SIZE);
4257       }
4258     } else {
4259       if ((256 > SecretLen) || (383 < SecretLen)) {
4260         KMException.throwIt(KMError.UNSUPPORTED_KEY_SIZE);
4261       }
4262       // add the key size to scratchPad
4263       keySize = KMInteger.uint_16((short) 256);
4264       keySize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, keySize);
4265       Util.setShort(scratchPad, index, keySize);
4266       index += 2;
4267     }
4268     // check the curve if present in key parameters.
4269     short curve = KMEnumTag.getValue(KMType.ECCURVE, data[KEY_PARAMETERS]);
4270     if (curve != KMType.INVALID_VALUE) {
4271       // As per NIST.SP.800-186 page 9,  secret length for 256 curve should be between
4272       // 256-383
4273       if (((256 <= SecretLen) && (383 >= SecretLen)) ^ curve == KMType.P_256) {
4274         KMException.throwIt(KMError.IMPORT_PARAMETER_MISMATCH);
4275       }
4276       if (curve != KMType.P_256) {
4277         KMException.throwIt(KMError.UNSUPPORTED_EC_CURVE);
4278       }
4279     } else {
4280       if ((256 > SecretLen) || (383 < SecretLen)) {
4281         KMException.throwIt(KMError.UNSUPPORTED_KEY_SIZE);
4282       }
4283       // add the curve to scratchPad
4284       curve = KMEnumTag.instance(KMType.ECCURVE, KMType.P_256);
4285       Util.setShort(scratchPad, index, curve);
4286       index += 2;
4287     }
4288 
4289     // Check whether key can be created
4290     seProvider.importAsymmetricKey(
4291         KMType.EC,
4292         KMByteBlob.cast(data[SECRET]).getBuffer(),
4293         KMByteBlob.cast(data[SECRET]).getStartOff(),
4294         KMByteBlob.cast(data[SECRET]).length(),
4295         KMByteBlob.cast(data[PUB_KEY]).getBuffer(),
4296         KMByteBlob.cast(data[PUB_KEY]).getStartOff(),
4297         KMByteBlob.cast(data[PUB_KEY]).length());
4298 
4299     // add scratch pad to key parameters
4300     updateKeyParameters(scratchPad, index);
4301     data[KEY_BLOB] = createKeyBlobInstance(ASYM_KEY_TYPE);
4302     KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_PUB_KEY, data[PUB_KEY]);
4303   }
4304 
importHmacKey(byte[] scratchPad)4305   private void importHmacKey(byte[] scratchPad) {
4306     // Get Key
4307     data[SECRET] = data[IMPORTED_KEY_BLOB];
4308     // create HMAC key of up to 512 bit
4309     short index = 0; // index in scratchPad for update params
4310     // check the keysize tag if present in key parameters.
4311     short keysize =
4312         KMIntegerTag.getShortValue(KMType.UINT_TAG, KMType.KEYSIZE, data[KEY_PARAMETERS]);
4313     if (keysize != KMType.INVALID_VALUE) {
4314       if (!(keysize >= 64 && keysize <= 512 && keysize % 8 == 0)) {
4315         KMException.throwIt(KMError.UNSUPPORTED_KEY_SIZE);
4316       }
4317       if (keysize != (short) (KMByteBlob.length(data[SECRET]) * 8)) {
4318         KMException.throwIt(KMError.IMPORT_PARAMETER_MISMATCH);
4319       }
4320     } else {
4321       // add the key size to scratchPad
4322       keysize = (short) (KMByteBlob.length(data[SECRET]) * 8);
4323       if (!(keysize >= 64 && keysize <= 512 && keysize % 8 == 0)) {
4324         KMException.throwIt(KMError.UNSUPPORTED_KEY_SIZE);
4325       }
4326       keysize = KMInteger.uint_16(keysize);
4327       short keySizeTag = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, keysize);
4328       Util.setShort(scratchPad, index, keySizeTag);
4329       index += 2;
4330     }
4331     // Check whether key can be created
4332     seProvider.importSymmetricKey(
4333         KMType.HMAC,
4334         keysize,
4335         KMByteBlob.cast(data[SECRET]).getBuffer(),
4336         KMByteBlob.cast(data[SECRET]).getStartOff(),
4337         KMByteBlob.cast(data[SECRET]).length());
4338 
4339     // update the key parameters list
4340     updateKeyParameters(scratchPad, index);
4341     // validate HMAC Key parameters
4342     validateHmacKey();
4343     data[KEY_BLOB] = createKeyBlobInstance(SYM_KEY_TYPE);
4344   }
4345 
importTDESKey(byte[] scratchPad)4346   private void importTDESKey(byte[] scratchPad) {
4347     // Decode Key Material
4348     data[SECRET] = data[IMPORTED_KEY_BLOB];
4349     short index = 0; // index in scratchPad for update params
4350     // check the keysize tag if present in key parameters.
4351     short keysize =
4352         KMIntegerTag.getShortValue(KMType.UINT_TAG, KMType.KEYSIZE, data[KEY_PARAMETERS]);
4353     if (keysize != KMType.INVALID_VALUE) {
4354       if (keysize != 168) {
4355         KMException.throwIt(KMError.UNSUPPORTED_KEY_SIZE);
4356       }
4357       if (192 != (short) (8 * KMByteBlob.length(data[SECRET]))) {
4358         KMException.throwIt(KMError.IMPORT_PARAMETER_MISMATCH);
4359       }
4360     } else {
4361       keysize = (short) (KMByteBlob.length(data[SECRET]) * 8);
4362       if (keysize != 192) {
4363         KMException.throwIt(KMError.UNSUPPORTED_KEY_SIZE);
4364       }
4365       // add the key size to scratchPad
4366       keysize = KMInteger.uint_16((short) 168);
4367       short keysizeTag = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, keysize);
4368       Util.setShort(scratchPad, index, keysizeTag);
4369       index += 2;
4370     }
4371     // Read Minimum Mac length - it must not be present
4372     KMTag.assertAbsence(
4373         data[KEY_PARAMETERS], KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, KMError.INVALID_TAG);
4374     // Check whether key can be created
4375     seProvider.importSymmetricKey(
4376         KMType.DES,
4377         keysize,
4378         KMByteBlob.cast(data[SECRET]).getBuffer(),
4379         KMByteBlob.cast(data[SECRET]).getStartOff(),
4380         KMByteBlob.cast(data[SECRET]).length());
4381     // update the key parameters list
4382     updateKeyParameters(scratchPad, index);
4383     data[KEY_BLOB] = createKeyBlobInstance(SYM_KEY_TYPE);
4384   }
4385 
validateAesKeySize(short keySizeBits)4386   private void validateAesKeySize(short keySizeBits) {
4387     if (keySizeBits != 128 && keySizeBits != 256) {
4388       KMException.throwIt(KMError.UNSUPPORTED_KEY_SIZE);
4389     }
4390   }
4391 
importAESKey(byte[] scratchPad)4392   private void importAESKey(byte[] scratchPad) {
4393     // Get Key
4394     data[SECRET] = data[IMPORTED_KEY_BLOB];
4395     // create 128 or 256 bit AES key
4396     short index = 0; // index in scratchPad for update params
4397     // check the keysize tag if present in key parameters.
4398     short keysize =
4399         KMIntegerTag.getShortValue(KMType.UINT_TAG, KMType.KEYSIZE, data[KEY_PARAMETERS]);
4400     if (keysize != KMType.INVALID_VALUE) {
4401       if (keysize != (short) (8 * KMByteBlob.length(data[SECRET]))) {
4402         KMException.throwIt(KMError.IMPORT_PARAMETER_MISMATCH);
4403       }
4404       validateAesKeySize(keysize);
4405     } else {
4406       // add the key size to scratchPad
4407       keysize = (short) (8 * KMByteBlob.cast(data[SECRET]).length());
4408       validateAesKeySize(keysize);
4409       keysize = KMInteger.uint_16(keysize);
4410       short keysizeTag = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, keysize);
4411       Util.setShort(scratchPad, index, keysizeTag);
4412       index += 2;
4413     }
4414     // Check whether key can be created
4415     seProvider.importSymmetricKey(
4416         KMType.AES,
4417         keysize,
4418         KMByteBlob.cast(data[SECRET]).getBuffer(),
4419         KMByteBlob.cast(data[SECRET]).getStartOff(),
4420         KMByteBlob.cast(data[SECRET]).length());
4421 
4422     // update the key parameters list
4423     updateKeyParameters(scratchPad, index);
4424     // validate AES Key parameters
4425     validateAESKey();
4426     data[KEY_BLOB] = createKeyBlobInstance(SYM_KEY_TYPE);
4427   }
4428 
importRSAKey(byte[] scratchPad)4429   private void importRSAKey(byte[] scratchPad) {
4430     // Decode key material
4431     KMAsn1Parser pkcs8 = KMAsn1Parser.instance();
4432     short keyblob = pkcs8.decodeRsa(data[IMPORTED_KEY_BLOB]);
4433     data[PUB_KEY] = KMArray.cast(keyblob).get((short) 0);
4434     short pubKeyExp = KMArray.cast(keyblob).get((short) 1);
4435     data[SECRET] = KMArray.cast(keyblob).get((short) 2);
4436     if (F4.length != KMByteBlob.cast(pubKeyExp).length()) {
4437       KMException.throwIt(KMError.INVALID_KEY_BLOB);
4438     }
4439     if (Util.arrayCompare(
4440             F4,
4441             (short) 0,
4442             KMByteBlob.cast(pubKeyExp).getBuffer(),
4443             KMByteBlob.cast(pubKeyExp).getStartOff(),
4444             (short) F4.length)
4445         != 0) {
4446       KMException.throwIt(KMError.IMPORT_PARAMETER_MISMATCH);
4447     }
4448     short index = 0; // index in scratchPad for update parameters.
4449     // validate public exponent if present in key params - it must be 0x010001
4450     short len =
4451         KMIntegerTag.getValue(
4452             scratchPad,
4453             (short) 10, // using offset 10 as first 10 bytes reserved for update params
4454             KMType.ULONG_TAG,
4455             KMType.RSA_PUBLIC_EXPONENT,
4456             data[KEY_PARAMETERS]);
4457     if (len != KMTag.INVALID_VALUE) {
4458       if (len != 4
4459           || Util.getShort(scratchPad, (short) 10) != 0x01
4460           || Util.getShort(scratchPad, (short) 12) != 0x01) {
4461         KMException.throwIt(KMError.IMPORT_PARAMETER_MISMATCH);
4462       }
4463     } else {
4464       // add public exponent to scratchPad
4465       Util.setShort(scratchPad, (short) 10, (short) 0x01);
4466       Util.setShort(scratchPad, (short) 12, (short) 0x01);
4467       pubKeyExp = KMInteger.uint_32(scratchPad, (short) 10);
4468       pubKeyExp = KMIntegerTag.instance(KMType.ULONG_TAG, KMType.RSA_PUBLIC_EXPONENT, pubKeyExp);
4469       Util.setShort(scratchPad, index, pubKeyExp);
4470       index += 2;
4471     }
4472 
4473     // check the keysize tag if present in key parameters.
4474     short keysize =
4475         KMIntegerTag.getShortValue(KMType.UINT_TAG, KMType.KEYSIZE, data[KEY_PARAMETERS]);
4476     short kSize = (short) (KMByteBlob.length(data[PUB_KEY]) * 8);
4477     if (keysize != KMType.INVALID_VALUE) {
4478       if (keysize != 2048 || (keysize != kSize)) {
4479         KMException.throwIt(KMError.IMPORT_PARAMETER_MISMATCH);
4480       }
4481     } else {
4482       if (2048 != kSize) {
4483         KMException.throwIt(KMError.IMPORT_PARAMETER_MISMATCH);
4484       }
4485       // add the key size to scratchPad
4486       keysize = KMInteger.uint_16((short) 2048);
4487       keysize = KMIntegerTag.instance(KMType.UINT_TAG, KMType.KEYSIZE, keysize);
4488       Util.setShort(scratchPad, index, keysize);
4489       index += 2;
4490     }
4491 
4492     // Check whether key can be created
4493     seProvider.importAsymmetricKey(
4494         KMType.RSA,
4495         KMByteBlob.cast(data[SECRET]).getBuffer(),
4496         KMByteBlob.cast(data[SECRET]).getStartOff(),
4497         KMByteBlob.cast(data[SECRET]).length(),
4498         KMByteBlob.cast(data[PUB_KEY]).getBuffer(),
4499         KMByteBlob.cast(data[PUB_KEY]).getStartOff(),
4500         KMByteBlob.cast(data[PUB_KEY]).length());
4501 
4502     // update the key parameters list
4503     updateKeyParameters(scratchPad, index);
4504     // validate RSA Key parameters
4505     validateRSAKey(scratchPad);
4506     data[KEY_BLOB] = createKeyBlobInstance(ASYM_KEY_TYPE);
4507     KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_PUB_KEY, data[PUB_KEY]);
4508   }
4509 
updateKeyParameters(byte[] newParams, short len)4510   private void updateKeyParameters(byte[] newParams, short len) {
4511     if (len == 0) {
4512       return; // nothing to update
4513     }
4514     // Create Update Param array and copy current params
4515     short params = KMKeyParameters.cast(data[KEY_PARAMETERS]).getVals();
4516     len = (short) (KMArray.cast(params).length() + (short) (len / 2));
4517     short updatedParams = KMArray.instance(len); // update params
4518 
4519     len = KMArray.cast(params).length();
4520     short index = 0;
4521 
4522     // copy the existing key parameters to updated array
4523     while (index < len) {
4524       short tag = KMArray.cast(params).get(index);
4525       KMArray.cast(updatedParams).add(index, tag);
4526       index++;
4527     }
4528 
4529     // copy new parameters to updated array
4530     len = KMArray.cast(updatedParams).length();
4531     short newParamIndex = 0; // index in ptrArr
4532     while (index < len) {
4533       short tag = Util.getShort(newParams, newParamIndex);
4534       KMArray.cast(updatedParams).add(index, tag);
4535       index++;
4536       newParamIndex += 2;
4537     }
4538     // replace with updated key parameters.
4539     data[KEY_PARAMETERS] = KMKeyParameters.instance(updatedParams);
4540   }
4541 
initStrongBoxCmd(APDU apdu)4542   private short initStrongBoxCmd(APDU apdu) {
4543     short cmd = KMArray.instance((short) 3);
4544     KMArray.cast(cmd).add((short) 0, KMInteger.exp()); // OS version
4545     KMArray.cast(cmd).add((short) 1, KMInteger.exp()); // OS patch level
4546     KMArray.cast(cmd).add((short) 2, KMInteger.exp()); // Vendor patch level
4547     return receiveIncoming(apdu, cmd);
4548   }
4549 
4550   // This command is executed to set the boot parameters.
4551   // releaseAllOperations has to be called on every boot, so
4552   // it is called from inside initStrongBoxCmd. Later in future if
4553   // initStrongBoxCmd is removed, then make sure that releaseAllOperations
4554   // is moved to a place where it is called on every boot.
processInitStrongBoxCmd(APDU apdu)4555   private void processInitStrongBoxCmd(APDU apdu) {
4556     short cmd = initStrongBoxCmd(apdu);
4557 
4558     short osVersion = KMArray.cast(cmd).get((short) 0);
4559     short osPatchLevel = KMArray.cast(cmd).get((short) 1);
4560     short vendorPatchLevel = KMArray.cast(cmd).get((short) 2);
4561     setOsVersion(osVersion);
4562     setOsPatchLevel(osPatchLevel);
4563     setVendorPatchLevel(vendorPatchLevel);
4564     kmDataStore.setDeviceBootStatus(KMKeymintDataStore.SET_SYSTEM_PROPERTIES_SUCCESS);
4565   }
4566 
reboot()4567   public void reboot() {
4568     // flag to maintain early boot ended state
4569     kmDataStore.setEarlyBootEndedStatus(false);
4570     // Clear all the operation state.
4571     releaseAllOperations();
4572     // Hmac is cleared, so generate a new Hmac nonce.
4573     initHmacNonceAndSeed();
4574     // Clear all auth tags.
4575     kmDataStore.removeAllAuthTags();
4576   }
4577 
setOsVersion(short version)4578   protected void setOsVersion(short version) {
4579     kmDataStore.setOsVersion(
4580         KMInteger.cast(version).getBuffer(),
4581         KMInteger.cast(version).getStartOff(),
4582         KMInteger.cast(version).length());
4583   }
4584 
setOsPatchLevel(short patch)4585   protected void setOsPatchLevel(short patch) {
4586     kmDataStore.setOsPatch(
4587         KMInteger.cast(patch).getBuffer(),
4588         KMInteger.cast(patch).getStartOff(),
4589         KMInteger.cast(patch).length());
4590   }
4591 
setVendorPatchLevel(short patch)4592   protected void setVendorPatchLevel(short patch) {
4593     kmDataStore.setVendorPatchLevel(
4594         KMInteger.cast(patch).getBuffer(),
4595         KMInteger.cast(patch).getStartOff(),
4596         KMInteger.cast(patch).length());
4597   }
4598 
generateKeyCmd(APDU apdu)4599   private short generateKeyCmd(APDU apdu) {
4600     short params = KMKeyParameters.expAny();
4601     short blob = KMByteBlob.exp();
4602     // Array of expected arguments
4603     short cmd = KMArray.instance((short) 4);
4604     KMArray.cast(cmd).add((short) 0, params); // key params
4605     KMArray.cast(cmd).add((short) 1, blob); // attest key
4606     KMArray.cast(cmd).add((short) 2, params); // attest key params
4607     KMArray.cast(cmd).add((short) 3, blob); // issuer
4608     return receiveIncoming(apdu, cmd);
4609   }
4610 
processGenerateKey(APDU apdu)4611   private void processGenerateKey(APDU apdu) {
4612     // Receive the incoming request fully from the host into buffer.
4613     short cmd = generateKeyCmd(apdu);
4614     // Re-purpose the apdu buffer as scratch pad.
4615     byte[] scratchPad = apdu.getBuffer();
4616     data[KEY_PARAMETERS] = KMArray.cast(cmd).get((short) 0);
4617     data[ATTEST_KEY_BLOB] = KMArray.cast(cmd).get((short) 1);
4618     data[ATTEST_KEY_PARAMS] = KMArray.cast(cmd).get((short) 2);
4619     data[ATTEST_KEY_ISSUER] = KMArray.cast(cmd).get((short) 3);
4620     data[CERTIFICATE] = KMType.INVALID_VALUE; // by default the cert is empty.
4621     // ROLLBACK_RESISTANCE not supported.
4622     KMTag.assertAbsence(
4623         data[KEY_PARAMETERS],
4624         KMType.BOOL_TAG,
4625         KMType.ROLLBACK_RESISTANCE,
4626         KMError.ROLLBACK_RESISTANCE_UNAVAILABLE);
4627 
4628     // Algorithm must be present
4629     KMTag.assertPresence(
4630         data[KEY_PARAMETERS], KMType.ENUM_TAG, KMType.ALGORITHM, KMError.INVALID_ARGUMENT);
4631 
4632     // Check if the tags are supported.
4633     if (KMKeyParameters.hasUnsupportedTags(data[KEY_PARAMETERS])) {
4634       KMException.throwIt(KMError.UNSUPPORTED_TAG);
4635     }
4636     short attKeyPurpose =
4637         KMKeyParameters.findTag(KMType.ENUM_ARRAY_TAG, KMType.PURPOSE, data[KEY_PARAMETERS]);
4638     // ATTEST_KEY cannot be combined with any other purpose.
4639     if (attKeyPurpose != KMType.INVALID_VALUE
4640         && KMEnumArrayTag.cast(attKeyPurpose).contains(KMType.ATTEST_KEY)
4641         && KMEnumArrayTag.cast(attKeyPurpose).length() > 1) {
4642       KMException.throwIt(KMError.INCOMPATIBLE_PURPOSE);
4643     }
4644     short alg = KMEnumTag.getValue(KMType.ALGORITHM, data[KEY_PARAMETERS]);
4645     // Check algorithm and dispatch to appropriate handler.
4646     switch (alg) {
4647       case KMType.RSA:
4648         generateRSAKey(scratchPad);
4649         break;
4650       case KMType.AES:
4651         generateAESKey(scratchPad);
4652         break;
4653       case KMType.DES:
4654         generateTDESKey(scratchPad);
4655         break;
4656       case KMType.HMAC:
4657         generateHmacKey(scratchPad);
4658         break;
4659       case KMType.EC:
4660         generateECKeys(scratchPad);
4661         break;
4662       default:
4663         KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM);
4664         break;
4665     }
4666     // create key blob and associated attestation.
4667     data[ORIGIN] = KMType.GENERATED;
4668     makeKeyCharacteristics(scratchPad);
4669     // construct the certificate and place the encoded data in data[CERTIFICATE]
4670     KMAttestationCert cert =
4671         generateAttestation(data[ATTEST_KEY_BLOB], data[ATTEST_KEY_PARAMS], scratchPad);
4672     createEncryptedKeyBlob(scratchPad);
4673     sendOutgoing(apdu, cert, data[CERTIFICATE], data[KEY_BLOB], data[KEY_CHARACTERISTICS]);
4674   }
4675 
getApplicationId(short params)4676   private short getApplicationId(short params) {
4677     short appId = KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_ID, params);
4678     if (appId != KMTag.INVALID_VALUE) {
4679       appId = KMByteTag.cast(appId).getValue();
4680       if (KMByteBlob.cast(appId).length() == 0) {
4681         // Treat empty as INVALID.
4682         return KMType.INVALID_VALUE;
4683       }
4684     }
4685     return appId;
4686   }
4687 
getApplicationData(short params)4688   private short getApplicationData(short params) {
4689     short appData = KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_DATA, params);
4690     if (appData != KMTag.INVALID_VALUE) {
4691       appData = KMByteTag.cast(appData).getValue();
4692       if (KMByteBlob.cast(appData).length() == 0) {
4693         // Treat empty as INVALID.
4694         return KMType.INVALID_VALUE;
4695       }
4696     }
4697     return appData;
4698   }
4699 
getAttestationMode(short attKeyBlob, short attChallenge)4700   private short getAttestationMode(short attKeyBlob, short attChallenge) {
4701     short alg = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, data[KEY_PARAMETERS]);
4702     short mode = KMType.NO_CERT;
4703     if (KMEnumTag.cast(alg).getValue() != KMType.RSA
4704         && KMEnumTag.cast(alg).getValue() != KMType.EC) {
4705       return mode;
4706     }
4707     // If attestation keyblob preset
4708     if (attKeyBlob != KMType.INVALID_VALUE && KMByteBlob.cast(attKeyBlob).length() > 0) {
4709       // No attestation challenge present then it is an error
4710       if (attChallenge == KMType.INVALID_VALUE || KMByteBlob.cast(attChallenge).length() <= 0) {
4711         KMException.throwIt(KMError.ATTESTATION_CHALLENGE_MISSING);
4712       } else {
4713         mode = KMType.ATTESTATION_CERT;
4714       }
4715     } else { // no attestation key blob
4716       // Attestation challenge present then it is an error because no factory provisioned attest key
4717       if (attChallenge != KMType.INVALID_VALUE && KMByteBlob.cast(attChallenge).length() > 0) {
4718         KMException.throwIt(KMError.ATTESTATION_KEYS_NOT_PROVISIONED);
4719       } else if (KMEnumArrayTag.contains(KMType.PURPOSE, KMType.ATTEST_KEY, data[HW_PARAMETERS])
4720           || KMEnumArrayTag.contains(KMType.PURPOSE, KMType.SIGN, data[HW_PARAMETERS])) {
4721         // The Purpose value can be read from either data[HW_PARAMETERS] or data[KEY_PARAMETERS]
4722         // as the values will be same, and they are cryptographically bound.
4723         mode = KMType.SELF_SIGNED_CERT;
4724       } else {
4725         mode = KMType.FAKE_CERT;
4726       }
4727     }
4728     return mode;
4729   }
4730 
generateAttestation( short attKeyBlob, short attKeyParam, byte[] scratchPad)4731   private KMAttestationCert generateAttestation(
4732       short attKeyBlob, short attKeyParam, byte[] scratchPad) {
4733     // 1) If attestation key is present and attestation challenge is absent then it is an error.
4734     // 2) If attestation key is absent and attestation challenge is present then it is an error as
4735     // factory provisioned attestation key is not supported.
4736     // 3) If both are present and issuer is absent or attest key purpose is not ATTEST_KEY then it
4737     // is an error.
4738     // 4) If the generated/imported keys are RSA or EC then validity period must be specified.
4739     // Device Unique Attestation is not supported.
4740     short heapStart = repository.getHeapIndex();
4741     KMTag.assertAbsence(
4742         data[KEY_PARAMETERS],
4743         KMType.BOOL_TAG,
4744         KMType.DEVICE_UNIQUE_ATTESTATION,
4745         KMError.CANNOT_ATTEST_IDS);
4746     // Read attestation challenge if present
4747     short attChallenge =
4748         KMKeyParameters.findTag(
4749             KMType.BYTES_TAG, KMType.ATTESTATION_CHALLENGE, data[KEY_PARAMETERS]);
4750     if (attChallenge != KMType.INVALID_VALUE) {
4751       attChallenge = KMByteTag.cast(attChallenge).getValue();
4752     }
4753     // No attestation required for symmetric keys
4754     short mode = getAttestationMode(attKeyBlob, attChallenge);
4755     KMAttestationCert cert = null;
4756 
4757     switch (mode) {
4758       case KMType.ATTESTATION_CERT:
4759         cert =
4760             makeAttestationCert(
4761                 attKeyBlob, attKeyParam, attChallenge, data[ATTEST_KEY_ISSUER], scratchPad);
4762         break;
4763       case KMType.SELF_SIGNED_CERT:
4764         cert = makeSelfSignedCert(data[SECRET], data[PUB_KEY], mode, scratchPad);
4765         break;
4766       case KMType.FAKE_CERT:
4767         // Generate certificate with no signature.
4768         cert = makeSelfSignedCert(KMType.INVALID_VALUE, data[PUB_KEY], mode, scratchPad);
4769         break;
4770       default:
4771         data[CERTIFICATE] = KMType.INVALID_VALUE;
4772         return null;
4773     }
4774     // Certificate Data is converted to cbor and written to the end of the stack.
4775     short certData = repository.allocReclaimableMemory(MAX_CERT_SIZE);
4776     // Leave first 4 bytes for Array header and ByteBlob header.
4777     cert.buffer(repository.getHeap(), (short) (certData + 4), (short) (MAX_CERT_SIZE - 4));
4778     // Build the certificate - this will sign the cert
4779     cert.build();
4780     // Certificate is now built so the data in the heap starting from heapStart to the current
4781     // heap index can be reused. So resetting the heap index to heapStart.
4782     repository.setHeapIndex(heapStart);
4783     data[CERTIFICATE] = certData;
4784     return cert;
4785   }
4786 
4787   // Encodes KeyCharacteristics at the end of the heap
encodeKeyCharacteristics(short keyChars)4788   private void encodeKeyCharacteristics(short keyChars) {
4789     byte[] buffer = repository.getHeap();
4790     short prevReclaimIndex = repository.getHeapReclaimIndex();
4791     short ptr = repository.allocReclaimableMemory(MAX_KEY_CHARS_SIZE);
4792     short len = encoder.encode(keyChars, buffer, ptr, prevReclaimIndex, MAX_KEY_CHARS_SIZE);
4793     // shift the encoded KeyCharacteristics data towards the right till the data[CERTIFICATE]
4794     // offset.
4795     Util.arrayCopyNonAtomic(buffer, ptr, buffer, (short) (ptr + (MAX_KEY_CHARS_SIZE - len)), len);
4796     // Reclaim the unused memory.
4797     repository.reclaimMemory((short) (MAX_KEY_CHARS_SIZE - len));
4798   }
4799 
4800   // Encodes KeyBlob at the end of the heap
encodeKeyBlob(short keyBlobPtr)4801   private void encodeKeyBlob(short keyBlobPtr) {
4802     // allocate reclaimable memory.
4803     byte[] buffer = repository.getHeap();
4804     short prevReclaimIndex = repository.getHeapReclaimIndex();
4805     short top = repository.allocReclaimableMemory(MAX_KEYBLOB_SIZE);
4806     short keyBlob = encoder.encode(keyBlobPtr, buffer, top, prevReclaimIndex, MAX_KEYBLOB_SIZE);
4807     Util.arrayCopyNonAtomic(
4808         repository.getHeap(),
4809         top,
4810         repository.getHeap(),
4811         (short) (top + MAX_KEYBLOB_SIZE - keyBlob),
4812         keyBlob);
4813     short newTop = (short) (top + MAX_KEYBLOB_SIZE - keyBlob);
4814     // Encode the KeyBlob array inside a ByteString. Get the length of
4815     // the ByteString header.
4816     short encodedBytesLength = encoder.getEncodedBytesLength(keyBlob);
4817     newTop -= encodedBytesLength;
4818     encoder.encodeByteBlobHeader(keyBlob, buffer, newTop, encodedBytesLength);
4819     // Reclaim unused memory.
4820     repository.reclaimMemory((short) (newTop - top));
4821   }
4822 
readKeyBlobVersion(short keyBlob)4823   private short readKeyBlobVersion(short keyBlob) {
4824     short version = KMType.INVALID_VALUE;
4825     try {
4826       version =
4827           decoder.readKeyblobVersion(
4828               KMByteBlob.cast(keyBlob).getBuffer(),
4829               KMByteBlob.cast(keyBlob).getStartOff(),
4830               KMByteBlob.cast(keyBlob).length());
4831       if (version == KMType.INVALID_VALUE) {
4832         // If Version is not present. Then it is either an old KeyBlob or
4833         // corrupted KeyBlob.
4834         version = 0;
4835       } else {
4836         version = KMInteger.cast(version).getShort();
4837         if (version > KEYBLOB_CURRENT_VERSION || version < 0) {
4838           KMException.throwIt(KMError.INVALID_KEY_BLOB);
4839         }
4840       }
4841     } catch (Exception e) {
4842       KMException.throwIt(KMError.INVALID_KEY_BLOB);
4843     }
4844     return version;
4845   }
4846 
readKeyBlobParams(short version, short parsedKeyBlob)4847   private void readKeyBlobParams(short version, short parsedKeyBlob) {
4848     data[KEY_BLOB] = parsedKeyBlob;
4849     // initialize data
4850     switch (version) {
4851       case (short) 0:
4852         data[SECRET] = KMArray.cast(parsedKeyBlob).get((short) 0);
4853         data[NONCE] = KMArray.cast(parsedKeyBlob).get((short) 1);
4854         data[AUTH_TAG] = KMArray.cast(parsedKeyBlob).get((short) 2);
4855         data[KEY_CHARACTERISTICS] = KMArray.cast(parsedKeyBlob).get((short) 3);
4856         data[PUB_KEY] = KMType.INVALID_VALUE;
4857         if (KMArray.cast(parsedKeyBlob).length() == ASYM_KEY_BLOB_SIZE_V0) {
4858           data[PUB_KEY] = KMArray.cast(parsedKeyBlob).get((short) 4);
4859         }
4860         // Set the data[KEY_BLOB_VERSION_DATA_OFFSET] with integer value of 0 so
4861         // that it will used at later point of time.
4862         data[KEY_BLOB_VERSION_DATA_OFFSET] = KMInteger.uint_8((byte) 0);
4863         break;
4864       case (short) 1:
4865         data[KEY_BLOB_VERSION_DATA_OFFSET] = KMArray.cast(parsedKeyBlob).get((short) 0);
4866         data[SECRET] = KMArray.cast(parsedKeyBlob).get((short) 1);
4867         data[NONCE] = KMArray.cast(parsedKeyBlob).get((short) 2);
4868         data[AUTH_TAG] = KMArray.cast(parsedKeyBlob).get((short) 3);
4869         data[KEY_CHARACTERISTICS] = KMArray.cast(parsedKeyBlob).get((short) 4);
4870         data[PUB_KEY] = KMType.INVALID_VALUE;
4871         if (KMArray.cast(parsedKeyBlob).length() == ASYM_KEY_BLOB_SIZE_V1) {
4872           data[PUB_KEY] = KMArray.cast(parsedKeyBlob).get((short) 5);
4873         }
4874         break;
4875       case (short) 2:
4876       case (short) 3:
4877         data[SECRET] = KMArray.cast(parsedKeyBlob).get(KEY_BLOB_SECRET);
4878         data[NONCE] = KMArray.cast(parsedKeyBlob).get(KEY_BLOB_NONCE);
4879         data[AUTH_TAG] = KMArray.cast(parsedKeyBlob).get(KEY_BLOB_AUTH_TAG);
4880         data[KEY_CHARACTERISTICS] = KMArray.cast(parsedKeyBlob).get(KEY_BLOB_PARAMS);
4881         data[KEY_BLOB_VERSION_DATA_OFFSET] =
4882             KMArray.cast(parsedKeyBlob).get(KEY_BLOB_VERSION_OFFSET);
4883         data[CUSTOM_TAGS] = KMArray.cast(parsedKeyBlob).get(KEY_BLOB_CUSTOM_TAGS);
4884         data[PUB_KEY] = KMType.INVALID_VALUE;
4885         if (KMArray.cast(parsedKeyBlob).length() == ASYM_KEY_BLOB_SIZE_V2_V3) {
4886           data[PUB_KEY] = KMArray.cast(parsedKeyBlob).get(KEY_BLOB_PUB_KEY);
4887         }
4888         break;
4889       default:
4890         KMException.throwIt(KMError.INVALID_KEY_BLOB);
4891     }
4892   }
4893 
4894   // Decode the KeyBlob from CBOR structures to the sub types of KMType.
decodeKeyBlob(short version, short keyBlob)4895   private void decodeKeyBlob(short version, short keyBlob) {
4896     // Decode KeyBlob and read the KeyBlob params based on the version.
4897     short parsedBlob =
4898         decoder.decodeArray(
4899             createKeyBlobExp(version),
4900             KMByteBlob.cast(keyBlob).getBuffer(),
4901             KMByteBlob.cast(keyBlob).getStartOff(),
4902             KMByteBlob.cast(keyBlob).length());
4903     short minArraySize = 0;
4904     switch (version) {
4905       case 0:
4906         minArraySize = SYM_KEY_BLOB_SIZE_V0;
4907         break;
4908       case 1:
4909         minArraySize = SYM_KEY_BLOB_SIZE_V1;
4910         break;
4911       case 2:
4912       case 3:
4913         minArraySize = SYM_KEY_BLOB_SIZE_V2_V3;
4914         break;
4915       default:
4916         KMException.throwIt(KMError.INVALID_KEY_BLOB);
4917     }
4918     ;
4919     // KeyBlob size should not be less than the minimum KeyBlob size.
4920     if (KMArray.cast(parsedBlob).length() < minArraySize) {
4921       KMException.throwIt(KMError.INVALID_KEY_BLOB);
4922     }
4923     readKeyBlobParams(version, parsedBlob);
4924   }
4925 
4926   // Decrypts the secret key in the KeyBlob. The secret can be a Symmetric or Asymmetric key.
processDecryptSecret(short version, short appId, short appData, byte[] scratchPad)4927   private void processDecryptSecret(short version, short appId, short appData, byte[] scratchPad) {
4928     data[TEE_PARAMETERS] = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getTeeEnforced();
4929     data[SB_PARAMETERS] =
4930         KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getStrongboxEnforced();
4931     data[SW_PARAMETERS] =
4932         KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getKeystoreEnforced();
4933     data[HW_PARAMETERS] = KMKeyParameters.makeHwEnforced(data[SB_PARAMETERS], data[TEE_PARAMETERS]);
4934 
4935     data[HIDDEN_PARAMETERS] = KMKeyParameters.makeHidden(appId, appData, data[ROT], scratchPad);
4936     // Decrypt Secret and verify auth tag
4937     decryptSecret(scratchPad, version);
4938     short keyBlobSecretOff = 0;
4939     switch (version) {
4940       case 0:
4941         // V0 KeyBlob
4942         // KEY_BLOB = [
4943         //     SECRET,
4944         //     NONCE,
4945         //     AUTH_TAG,
4946         //     KEY_CHARACTERISTICS,
4947         //     PUBKEY
4948         // ]
4949         keyBlobSecretOff = (short) 0;
4950         break;
4951       case 1:
4952         // V1 KeyBlob
4953         // KEY_BLOB = [
4954         //     VERSION,
4955         //     SECRET,
4956         //     NONCE,
4957         //     AUTH_TAG,
4958         //     KEY_CHARACTERISTICS,
4959         //     PUBKEY
4960         // ]
4961         keyBlobSecretOff = (short) 1;
4962         break;
4963       case 2:
4964       case 3:
4965         // V2 KeyBlob
4966         // KEY_BLOB = [
4967         //     VERSION,
4968         //     SECRET,
4969         //     NONCE,
4970         //     AUTH_TAG,
4971         //     KEY_CHARACTERISTICS,
4972         //     CUSTOM_TAGS,
4973         //     PUBKEY
4974         // ]
4975         keyBlobSecretOff = KEY_BLOB_SECRET;
4976         break;
4977       default:
4978         KMException.throwIt(KMError.INVALID_KEY_BLOB);
4979     }
4980     ;
4981     KMArray.cast(data[KEY_BLOB]).add(keyBlobSecretOff, data[SECRET]);
4982   }
4983 
parseEncryptedKeyBlob( short keyBlob, short appId, short appData, byte[] scratchPad, short version)4984   private void parseEncryptedKeyBlob(
4985       short keyBlob, short appId, short appData, byte[] scratchPad, short version) {
4986     // make root of trust blob
4987     data[ROT] = readROT(scratchPad, version);
4988     if (data[ROT] == KMType.INVALID_VALUE) {
4989       KMException.throwIt(KMError.UNKNOWN_ERROR);
4990     }
4991     try {
4992       decodeKeyBlob(version, keyBlob);
4993       processDecryptSecret(version, appId, appData, scratchPad);
4994     } catch (Exception e) {
4995       KMException.throwIt(KMError.INVALID_KEY_BLOB);
4996     }
4997   }
4998 
decryptSecret(byte[] scratchPad, short version)4999   private void decryptSecret(byte[] scratchPad, short version) {
5000     // derive master key - stored in derivedKey
5001     short len;
5002     short authDataOff = 0;
5003     short authDataLen = 0;
5004     byte[] authDataBuff = null;
5005     switch (version) {
5006       case 3:
5007         len = deriveKey(scratchPad);
5008         break;
5009 
5010       case 2:
5011       case 1:
5012       case 0:
5013         makeAuthData(version, scratchPad);
5014         len = deriveKeyForOldKeyBlobs(scratchPad);
5015         authDataBuff = repository.getHeap();
5016         authDataOff = data[AUTH_DATA];
5017         authDataLen = data[AUTH_DATA_LENGTH];
5018         break;
5019       default:
5020         KMException.throwIt(KMError.INVALID_KEY_BLOB);
5021     }
5022     if (!seProvider.aesGCMDecrypt(
5023         KMByteBlob.cast(data[DERIVED_KEY]).getBuffer(),
5024         KMByteBlob.cast(data[DERIVED_KEY]).getStartOff(),
5025         KMByteBlob.cast(data[DERIVED_KEY]).length(),
5026         KMByteBlob.cast(data[SECRET]).getBuffer(),
5027         KMByteBlob.cast(data[SECRET]).getStartOff(),
5028         KMByteBlob.cast(data[SECRET]).length(),
5029         scratchPad,
5030         (short) 0,
5031         KMByteBlob.cast(data[NONCE]).getBuffer(),
5032         KMByteBlob.cast(data[NONCE]).getStartOff(),
5033         KMByteBlob.cast(data[NONCE]).length(),
5034         authDataBuff,
5035         authDataOff,
5036         authDataLen,
5037         KMByteBlob.cast(data[AUTH_TAG]).getBuffer(),
5038         KMByteBlob.cast(data[AUTH_TAG]).getStartOff(),
5039         KMByteBlob.cast(data[AUTH_TAG]).length())) {
5040       KMException.throwIt(KMError.INVALID_KEY_BLOB);
5041     }
5042     // Copy the decrypted secret
5043     data[SECRET] =
5044         KMByteBlob.instance(scratchPad, (short) 0, KMByteBlob.cast(data[SECRET]).length());
5045   }
5046 
addIntegers(short authTime, short timeStamp, byte[] scratchPad)5047   private short addIntegers(short authTime, short timeStamp, byte[] scratchPad) {
5048     Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 24, (byte) 0);
5049     Util.arrayCopyNonAtomic(
5050         KMInteger.cast(authTime).getBuffer(),
5051         KMInteger.cast(authTime).getStartOff(),
5052         scratchPad,
5053         (short) (8 - KMInteger.cast(timeStamp).length()),
5054         KMInteger.cast(timeStamp).length());
5055 
5056     // Copy timestamp to scratchpad
5057     Util.arrayCopyNonAtomic(
5058         KMInteger.cast(timeStamp).getBuffer(),
5059         KMInteger.cast(timeStamp).getStartOff(),
5060         scratchPad,
5061         (short) (16 - KMInteger.cast(timeStamp).length()),
5062         KMInteger.cast(timeStamp).length());
5063 
5064     // add authTime in millis to timestamp.
5065     KMUtils.add(scratchPad, (short) 0, (short) 8, (short) 16);
5066     return KMInteger.uint_64(scratchPad, (short) 16);
5067   }
5068 
powerReset()5069   public void powerReset() {
5070     // TODO handle power reset signal.
5071     releaseAllOperations();
5072     resetWrappingKey();
5073   }
5074 
updateTrustedConfirmationOperation(KMOperationState op)5075   private void updateTrustedConfirmationOperation(KMOperationState op) {
5076     if (op.isTrustedConfirmationRequired()) {
5077       op.getTrustedConfirmationSigner()
5078           .update(
5079               KMByteBlob.cast(data[INPUT_DATA]).getBuffer(),
5080               KMByteBlob.cast(data[INPUT_DATA]).getStartOff(),
5081               KMByteBlob.cast(data[INPUT_DATA]).length());
5082     }
5083   }
5084 
finishTrustedConfirmationOperation(KMOperationState op)5085   private void finishTrustedConfirmationOperation(KMOperationState op) {
5086     // Perform trusted confirmation if required
5087     if (op.isTrustedConfirmationRequired()) {
5088       if (0 == KMByteBlob.cast(data[CONFIRMATION_TOKEN]).length()) {
5089         KMException.throwIt(KMError.NO_USER_CONFIRMATION);
5090       }
5091 
5092       boolean verified =
5093           op.getTrustedConfirmationSigner()
5094               .verify(
5095                   KMByteBlob.cast(data[INPUT_DATA]).getBuffer(),
5096                   KMByteBlob.cast(data[INPUT_DATA]).getStartOff(),
5097                   KMByteBlob.cast(data[INPUT_DATA]).length(),
5098                   KMByteBlob.cast(data[CONFIRMATION_TOKEN]).getBuffer(),
5099                   KMByteBlob.cast(data[CONFIRMATION_TOKEN]).getStartOff(),
5100                   KMByteBlob.cast(data[CONFIRMATION_TOKEN]).length());
5101       if (!verified) {
5102         KMException.throwIt(KMError.NO_USER_CONFIRMATION);
5103       }
5104     }
5105   }
5106 
isDigestSupported(short alg, short digest)5107   private boolean isDigestSupported(short alg, short digest) {
5108     switch (alg) {
5109       case KMType.RSA:
5110       case KMType.EC:
5111         if (digest != KMType.DIGEST_NONE && digest != KMType.SHA2_256) {
5112           return false;
5113         }
5114         break;
5115       case KMType.HMAC:
5116         if (digest != KMType.SHA2_256) {
5117           return false;
5118         }
5119         break;
5120       default:
5121         break;
5122     }
5123     return true;
5124   }
5125 }
5126