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