From fa7df9cf05d40b59de9a9dd18226fcd8b2ce9384 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Fri, 23 Apr 2021 23:32:10 +0530 Subject: [PATCH 1/6] separate os_version, os_patchlevel and vendor_patchlevel from other bootparamters --- HAL/keymaster/4.1/CommonUtils.cpp | 75 +++++++++++++++++++ .../4.1/JavacardKeymaster4Device.cpp | 33 +++++++- HAL/keymaster/include/CommonUtils.h | 2 + 3 files changed, 109 insertions(+), 1 deletion(-) diff --git a/HAL/keymaster/4.1/CommonUtils.cpp b/HAL/keymaster/4.1/CommonUtils.cpp index a6d2b7ab..090c8d0d 100644 --- a/HAL/keymaster/4.1/CommonUtils.cpp +++ b/HAL/keymaster/4.1/CommonUtils.cpp @@ -16,11 +16,15 @@ */ #include +#include +#include +#include #include #include #include #include #include +#include #include #include #include @@ -35,6 +39,13 @@ namespace keymaster { namespace V4_1 { namespace javacard { +constexpr char kVendorPatchlevelProp[] = "ro.vendor.build.security_patch"; +constexpr char kVendorPatchlevelRegex[] = "^([0-9]{4})-([0-9]{2})-([0-9]{2})$"; +constexpr size_t kYearMatch = 1; +constexpr size_t kMonthMatch = 2; +constexpr size_t kDayMatch = 3; +constexpr size_t kVendorPatchlevelMatchCount = kDayMatch + 1; + hidl_vec kmParamSet2Hidl(const keymaster_key_param_set_t& set) { hidl_vec result; if (set.length == 0 || set.params == nullptr) @@ -272,6 +283,70 @@ ErrorCode getCertificateChain(std::vector& chainBuffer, std::vector 12) { + LOG(ERROR) << "Invalid patch month " << month; + return 0; + } + bool isLeapYear = (0 == year % 4) ? true : false; + int maxDaysForMonth = 31; + switch(month) { + case 4: case 6: case 9: case 11: + maxDaysForMonth = 30; + break; + case 2: + maxDaysForMonth = isLeapYear ? 29 : 28; + break; + } + if (day < 1 || day > maxDaysForMonth) { + LOG(ERROR) << "Invalid patch day " << day; + return 0; + } + return year * 10000 + month * 100 + day; +} + +uint32_t GetVendorPatchlevel() { + std::string patchlevel = wait_and_get_property(kVendorPatchlevelProp); + return GetVendorPatchlevel(patchlevel.c_str()); +} + } // namespace javacard } // namespace V4_1 diff --git a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp index eb8ccdd8..d0b3a060 100644 --- a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp +++ b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp @@ -92,6 +92,7 @@ enum class Instruction { INS_EARLY_BOOT_ENDED_CMD = INS_END_KM_PROVISION_CMD+21, INS_GET_CERT_CHAIN_CMD = INS_END_KM_PROVISION_CMD+22, INS_GET_PROVISION_STATUS_CMD = INS_BEGIN_KM_CMD+8, + INS_SET_VERSION_PATCHLEVEL_CMD = INS_BEGIN_KM_CMD+9, }; enum ProvisionStatus { @@ -519,15 +520,45 @@ Return JavacardKeymaster4Device::getHmacSharingParameters(getHmacSharingPa return Void(); } +static ErrorCode setAndroidSystemProperties(CborConverter cborConverter_) { + ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + cppbor::Array array; + std::unique_ptr item; + std::vector cborOutData; + + array.add(GetOsVersion()). + add(GetOsPatchlevel()). + add(GetVendorPatchlevel()); + + std::vector cborData = array.encode(); + errorCode = sendData(Instruction::INS_SET_VERSION_PATCHLEVEL_CMD, cborData, cborOutData); + if (ErrorCode::OK == errorCode) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = decodeData(cborConverter_, std::vector(cborOutData.begin(), cborOutData.end()-2), + true); + } + return errorCode; +} + Return JavacardKeymaster4Device::computeSharedHmac(const hidl_vec& params, computeSharedHmac_cb _hidl_cb) { cppbor::Array array; std::unique_ptr item; std::vector cborOutData; hidl_vec sharingCheck; - ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; std::vector tempVec; cppbor::Array outerArray; + + // The Android system properties like OS_VERSION, OS_PATCHLEVEL and VENDOR_PATCHLEVEL are to + // be delivered to the Applet when the HAL is first loaded. This is one of the ideal places + // to send this information to the Applet as computeSharedHmac is called everytime when Android + // device boots. + if (ErrorCode::OK != (errorCode = setAndroidSystemProperties(cborConverter_))) { + LOG(ERROR) << " Failed to set os_version, os_patchlevel and vendor_patchlevel err: " << (int32_t)errorCode; + return Void(); + } + + for(size_t i = 0; i < params.size(); ++i) { cppbor::Array innerArray; innerArray.add(static_cast>(params[i].seed)); diff --git a/HAL/keymaster/include/CommonUtils.h b/HAL/keymaster/include/CommonUtils.h index f08a60c3..b6612741 100644 --- a/HAL/keymaster/include/CommonUtils.h +++ b/HAL/keymaster/include/CommonUtils.h @@ -88,6 +88,8 @@ publicKey, EcCurve& eccurve); ErrorCode getCertificateChain(std::vector& chainBuffer, std::vector>& certChain); +uint32_t GetVendorPatchlevel(); + class KmParamSet : public keymaster_key_param_set_t { public: explicit KmParamSet(const hidl_vec& keyParams) From ae3b68b6893af7179aa67eab65463c0688ff46c2 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Fri, 23 Apr 2021 23:32:10 +0530 Subject: [PATCH 2/6] separate os_version, os_patchlevel and vendor_patchlevel from other bootparamters --- .../javacard/test/KMFunctionalTest.java | 76 +++++++----- .../javacard/keymaster/KMKeymasterApplet.java | 115 ++++++++++-------- 2 files changed, 113 insertions(+), 78 deletions(-) diff --git a/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java b/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java index 9e9c2c6c..517afb7f 100644 --- a/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java +++ b/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java @@ -92,6 +92,7 @@ public class KMFunctionalTest { private static final byte INS_SET_BOOT_PARAMS_CMD = INS_BEGIN_KM_CMD + 6; //0x06 private static final byte INS_LOCK_PROVISIONING_CMD = INS_BEGIN_KM_CMD + 7; //0x07 private static final byte INS_GET_PROVISION_STATUS_CMD = INS_BEGIN_KM_CMD + 8; //0x08 + private static final byte INS_SET_VERSION_PATCHLEVEL_CMD = INS_BEGIN_KM_CMD + 9; //0x09 // Top 32 commands are reserved for provisioning. private static final byte INS_END_KM_PROVISION_CMD = 0x20; @@ -473,8 +474,8 @@ private void init() { provisionCmd(simulator); } - private void setBootParams(CardSimulator simulator, short osVersion, - short osPatchLevel, short vendorPatchLevel, short bootPatchLevel) { + private void setAndroidOSSystemProperties(CardSimulator simulator, short osVersion, + short osPatchLevel, short vendorPatchLevel) { // Argument 1 OS Version short versionPtr = KMInteger.uint_16(osVersion); // short versionTagPtr = KMIntegerTag.instance(KMType.UINT_TAG, @@ -482,31 +483,43 @@ private void setBootParams(CardSimulator simulator, short osVersion, // Argument 2 OS Patch level short patchPtr = KMInteger.uint_16(osPatchLevel); short vendorpatchPtr = KMInteger.uint_16((short) vendorPatchLevel); + // Arguments + short arrPtr = KMArray.instance((short) 3); + KMArray vals = KMArray.cast(arrPtr); + vals.add((short) 0, versionPtr); + vals.add((short) 1, patchPtr); + vals.add((short) 2, vendorpatchPtr); + CommandAPDU apdu = encodeApdu((byte) INS_SET_VERSION_PATCHLEVEL_CMD, arrPtr); + // print(commandAPDU.getBytes()); + ResponseAPDU response = simulator.transmitCommand(apdu); + Assert.assertEquals(0x9000, response.getSW()); + + } + + private void setBootParams(CardSimulator simulator, short bootPatchLevel) { + // Argument 0 boot patch level short bootpatchPtr = KMInteger.uint_16((short) bootPatchLevel); - // Argument 3 Verified Boot Key + // Argument 1 Verified Boot Key byte[] bootKeyHash = "00011122233344455566677788899900".getBytes(); short bootKeyPtr = KMByteBlob.instance(bootKeyHash, (short) 0, (short) bootKeyHash.length); - // Argument 4 Verified Boot Hash + // Argument 2 Verified Boot Hash short bootHashPtr = KMByteBlob.instance(bootKeyHash, (short) 0, (short) bootKeyHash.length); - // Argument 5 Verified Boot State + // Argument 3 Verified Boot State short bootStatePtr = KMEnum.instance(KMType.VERIFIED_BOOT_STATE, KMType.VERIFIED_BOOT); - // Argument 6 Device Locked + // Argument 4 Device Locked short deviceLockedPtr = KMEnum.instance(KMType.DEVICE_LOCKED, KMType.DEVICE_LOCKED_FALSE); // Arguments - short arrPtr = KMArray.instance((short) 8); + short arrPtr = KMArray.instance((short) 5); KMArray vals = KMArray.cast(arrPtr); - vals.add((short) 0, versionPtr); - vals.add((short) 1, patchPtr); - vals.add((short) 2, vendorpatchPtr); - vals.add((short) 3, bootpatchPtr); - vals.add((short) 4, bootKeyPtr); - vals.add((short) 5, bootHashPtr); - vals.add((short) 6, bootStatePtr); - vals.add((short) 7, deviceLockedPtr); + vals.add((short) 0, bootpatchPtr); + vals.add((short) 1, bootKeyPtr); + vals.add((short) 2, bootHashPtr); + vals.add((short) 3, bootStatePtr); + vals.add((short) 4, deviceLockedPtr); CommandAPDU apdu = encodeApdu((byte) INS_SET_BOOT_PARAMS_CMD, arrPtr); // print(commandAPDU.getBytes()); ResponseAPDU response = simulator.transmitCommand(apdu); @@ -661,8 +674,10 @@ private void provisionCmd(CardSimulator simulator) { provisionSharedSecret(simulator); provisionAttestIds(simulator); // set bootup parameters - setBootParams(simulator, (short) OS_VERSION, (short) OS_PATCH_LEVEL, - (short) VENDOR_PATCH_LEVEL, (short) BOOT_PATCH_LEVEL); + setBootParams(simulator, (short) BOOT_PATCH_LEVEL); + // set android system properties + setAndroidOSSystemProperties(simulator, (short) OS_VERSION, (short) OS_PATCH_LEVEL, + (short) VENDOR_PATCH_LEVEL); provisionLocked(simulator); } @@ -2722,11 +2737,12 @@ public void testUpgradeKey() { {0, OS_PATCH_LEVEL+1, VENDOR_PATCH_LEVEL-1, BOOT_PATCH_LEVEL+1, NO_UPGRADE, KMError.INVALID_ARGUMENT }, }; for (int i = 0; i < test_data.length; i++) { - setBootParams(simulator, (short) test_data[i][0], (short) test_data[i][1], - (short) test_data[i][2], (short) test_data[i][3]); + setAndroidOSSystemProperties(simulator, (short) test_data[i][0], (short) test_data[i][1], + (short) test_data[i][2]); + setBootParams(simulator, (short) test_data[i][3]); ret = upgradeKey( - KMByteBlob.instance(keyBlob, (short) 0, (short) keyBlob.length), - null, null, test_data[i][5]); + KMByteBlob.instance(keyBlob, (short) 0, (short) keyBlob.length), + null, null, test_data[i][5]); if (test_data[i][5] != KMError.OK) continue; keyBlobPtr = KMArray.cast(ret).get((short) 1); @@ -2738,27 +2754,27 @@ public void testUpgradeKey() { ret = getKeyCharacteristics(keyBlobPtr); keyCharacteristics = KMArray.cast(ret).get((short) 1); hwParams = KMKeyCharacteristics.cast(keyCharacteristics) - .getHardwareEnforced(); + .getHardwareEnforced(); osVersion = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.OS_VERSION, - hwParams); + hwParams); osVersion = KMIntegerTag.cast(osVersion).getValue(); osPatch = KMKeyParameters.findTag(KMType.UINT_TAG, - KMType.OS_PATCH_LEVEL, hwParams); + KMType.OS_PATCH_LEVEL, hwParams); osPatch = KMIntegerTag.cast(osPatch).getValue(); short ptr = KMKeyParameters.findTag(KMType.UINT_TAG, - KMType.VENDOR_PATCH_LEVEL, hwParams); + KMType.VENDOR_PATCH_LEVEL, hwParams); short vendorPatchLevel = KMIntegerTag.cast(ptr).getValue(); ptr = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.BOOT_PATCH_LEVEL, - hwParams); + hwParams); short bootPatchLevel = KMIntegerTag.cast(ptr).getValue(); Assert.assertEquals(KMInteger.cast(osVersion).getShort(), - test_data[i][0]); + test_data[i][0]); Assert.assertEquals(KMInteger.cast(osPatch).getShort(), - test_data[i][1]); + test_data[i][1]); Assert.assertEquals(KMInteger.cast(vendorPatchLevel).getShort(), - test_data[i][2]); + test_data[i][2]); Assert.assertEquals(KMInteger.cast(bootPatchLevel).getShort(), - test_data[i][3]); + test_data[i][3]); } } cleanUp(); diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index b1a78178..4caa9d51 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -85,6 +85,7 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe private static final byte INS_SET_BOOT_PARAMS_CMD = INS_BEGIN_KM_CMD + 6; //0x06 private static final byte INS_LOCK_PROVISIONING_CMD = INS_BEGIN_KM_CMD + 7; //0x07 private static final byte INS_GET_PROVISION_STATUS_CMD = INS_BEGIN_KM_CMD + 8; //0x08 + private static final byte INS_SET_VERSION_PATCHLEVEL_CMD = INS_BEGIN_KM_CMD + 9; //0x09 // Top 32 commands are reserved for provisioning. private static final byte INS_END_KM_PROVISION_CMD = 0x20; @@ -467,6 +468,9 @@ && isProvisioningComplete())) { case INS_GET_CERT_CHAIN_CMD: processGetCertChainCmd(apdu); break; + case INS_SET_VERSION_PATCHLEVEL_CMD: + processSetVersionAndPatchLevels(apdu); + break; default: ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); } @@ -641,6 +645,47 @@ private void processAddRngEntropyCmd(APDU apdu) { sendError(apdu, KMError.OK); } + private void processSetVersionAndPatchLevels(APDU apdu) { + receiveIncoming(apdu); + byte[] scratchPad = apdu.getBuffer(); + // Argument 1 OS Version + tmpVariables[0] = KMInteger.exp(); + // Argument 2 OS Patch level + tmpVariables[1] = KMInteger.exp(); + // Argument 3 Vendor Patch level + tmpVariables[2] = KMInteger.exp(); + // Array of expected arguments + short argsProto = KMArray.instance((short) 3); + KMArray.cast(argsProto).add((short) 0, tmpVariables[0]); + KMArray.cast(argsProto).add((short) 1, tmpVariables[1]); + KMArray.cast(argsProto).add((short) 2, tmpVariables[2]); + // Decode the arguments + short args = decoder.decode(argsProto, (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], bufferProp[BUF_LEN_OFFSET]); + //reclaim memory + repository.reclaimMemory(bufferProp[BUF_LEN_OFFSET]); + + tmpVariables[0] = KMArray.cast(args).get((short) 0); + tmpVariables[1] = KMArray.cast(args).get((short) 1); + tmpVariables[2] = KMArray.cast(args).get((short) 2); + + repository.setOsVersion( + KMInteger.cast(tmpVariables[0]).getBuffer(), + KMInteger.cast(tmpVariables[0]).getStartOff(), + KMInteger.cast(tmpVariables[0]).length()); + + repository.setOsPatch( + KMInteger.cast(tmpVariables[1]).getBuffer(), + KMInteger.cast(tmpVariables[1]).getStartOff(), + KMInteger.cast(tmpVariables[1]).length()); + + repository.setVendorPatchLevel( + KMInteger.cast(tmpVariables[2]).getBuffer(), + KMInteger.cast(tmpVariables[2]).getStartOff(), + KMInteger.cast(tmpVariables[2]).length()); + + sendError(apdu, KMError.OK); + } + private void processGetCertChainCmd(APDU apdu) { // Make the response tmpVariables[0] = seProvider.getCertificateChainLength(); @@ -3135,32 +3180,23 @@ private void updateKeyParameters(byte[] ptrArr, short len) { private void processSetBootParamsCmd(APDU apdu) { receiveIncoming(apdu); byte[] scratchPad = apdu.getBuffer(); - // Argument 1 OS Version + // Argument 0 Boot Patch level tmpVariables[0] = KMInteger.exp(); - // Argument 2 OS Patch level - tmpVariables[1] = KMInteger.exp(); - // Argument 3 Vendor Patch level - tmpVariables[2] = KMInteger.exp(); - // Argument 4 Boot Patch level - tmpVariables[3] = KMInteger.exp(); - // Argument 5 Verified Boot Key - tmpVariables[4] = KMByteBlob.exp(); - // Argument 6 Verified Boot Hash - tmpVariables[5] = KMByteBlob.exp(); - // Argument 7 Verified Boot State - tmpVariables[6] = KMEnum.instance(KMType.VERIFIED_BOOT_STATE); - // Argument 8 Device Locked - tmpVariables[7] = KMEnum.instance(KMType.DEVICE_LOCKED); - // Array of expected arguments - short argsProto = KMArray.instance((short) 8); + // Argument 1 Verified Boot Key + tmpVariables[1] = KMByteBlob.exp(); + // Argument 2 Verified Boot Hash + tmpVariables[2] = KMByteBlob.exp(); + // Argument 3 Verified Boot State + tmpVariables[3] = KMEnum.instance(KMType.VERIFIED_BOOT_STATE); + // Argument 4 Device Locked + tmpVariables[4] = KMEnum.instance(KMType.DEVICE_LOCKED); + // Array of e4pected arguments + short argsProto = KMArray.instance((short) 5); KMArray.cast(argsProto).add((short) 0, tmpVariables[0]); KMArray.cast(argsProto).add((short) 1, tmpVariables[1]); KMArray.cast(argsProto).add((short) 2, tmpVariables[2]); KMArray.cast(argsProto).add((short) 3, tmpVariables[3]); KMArray.cast(argsProto).add((short) 4, tmpVariables[4]); - KMArray.cast(argsProto).add((short) 5, tmpVariables[5]); - KMArray.cast(argsProto).add((short) 6, tmpVariables[6]); - KMArray.cast(argsProto).add((short) 7, tmpVariables[7]); // Decode the arguments short args = decoder.decode(argsProto, (byte[]) bufferRef[0], bufferProp[BUF_START_OFFSET], bufferProp[BUF_LEN_OFFSET]); //reclaim memory @@ -3171,49 +3207,32 @@ private void processSetBootParamsCmd(APDU apdu) { tmpVariables[2] = KMArray.cast(args).get((short) 2); tmpVariables[3] = KMArray.cast(args).get((short) 3); tmpVariables[4] = KMArray.cast(args).get((short) 4); - tmpVariables[5] = KMArray.cast(args).get((short) 5); - tmpVariables[6] = KMArray.cast(args).get((short) 6); - tmpVariables[7] = KMArray.cast(args).get((short) 7); - if (KMByteBlob.cast(tmpVariables[4]).length() > KMRepository.BOOT_KEY_MAX_SIZE) { + if (KMByteBlob.cast(tmpVariables[1]).length() > KMRepository.BOOT_KEY_MAX_SIZE) { KMException.throwIt(KMError.INVALID_ARGUMENT); } - if (KMByteBlob.cast(tmpVariables[5]).length() > KMRepository.BOOT_HASH_MAX_SIZE) { + if (KMByteBlob.cast(tmpVariables[2]).length() > KMRepository.BOOT_HASH_MAX_SIZE) { KMException.throwIt(KMError.INVALID_ARGUMENT); } - repository.setOsVersion( + repository.setBootPatchLevel( KMInteger.cast(tmpVariables[0]).getBuffer(), KMInteger.cast(tmpVariables[0]).getStartOff(), KMInteger.cast(tmpVariables[0]).length()); - repository.setOsPatch( - KMInteger.cast(tmpVariables[1]).getBuffer(), - KMInteger.cast(tmpVariables[1]).getStartOff(), - KMInteger.cast(tmpVariables[1]).length()); - - repository.setVendorPatchLevel( - KMInteger.cast(tmpVariables[2]).getBuffer(), - KMInteger.cast(tmpVariables[2]).getStartOff(), - KMInteger.cast(tmpVariables[2]).length()); - - repository.setBootPatchLevel( - KMInteger.cast(tmpVariables[3]).getBuffer(), - KMInteger.cast(tmpVariables[3]).getStartOff(), - KMInteger.cast(tmpVariables[3]).length()); repository.setVerifiedBootKey( - KMByteBlob.cast(tmpVariables[4]).getBuffer(), - KMByteBlob.cast(tmpVariables[4]).getStartOff(), - KMByteBlob.cast(tmpVariables[4]).length()); + KMByteBlob.cast(tmpVariables[1]).getBuffer(), + KMByteBlob.cast(tmpVariables[1]).getStartOff(), + KMByteBlob.cast(tmpVariables[1]).length()); repository.setVerifiedBootHash( - KMByteBlob.cast(tmpVariables[5]).getBuffer(), - KMByteBlob.cast(tmpVariables[5]).getStartOff(), - KMByteBlob.cast(tmpVariables[5]).length()); + KMByteBlob.cast(tmpVariables[2]).getBuffer(), + KMByteBlob.cast(tmpVariables[2]).getStartOff(), + KMByteBlob.cast(tmpVariables[2]).length()); - byte enumVal = KMEnum.cast(tmpVariables[6]).getVal(); + byte enumVal = KMEnum.cast(tmpVariables[3]).getVal(); repository.setBootState(enumVal); - enumVal = KMEnum.cast(tmpVariables[7]).getVal(); + enumVal = KMEnum.cast(tmpVariables[4]).getVal(); repository.setBootloaderLocked(enumVal == KMType.DEVICE_LOCKED_TRUE); // Clear the Computed SharedHmac and Hmac nonce from persistent memory. From 678214e7c2b66b97126e9c5ae8f130f742778b36 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Fri, 23 Apr 2021 22:07:31 +0100 Subject: [PATCH 3/6] send systemproperties at initialization time if it fails then try to set again in computeSharedHmac. --- .../4.1/JavacardKeymaster4Device.cpp | 63 +++++++++++-------- .../include/JavacardKeymaster4Device.h | 1 + 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp index d0b3a060..65a0fda7 100644 --- a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp +++ b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp @@ -439,13 +439,39 @@ ErrorCode sendData(Instruction ins, std::vector& inData, std::vector item; + std::vector cborOutData; + + array.add(GetOsVersion()). + add(GetOsPatchlevel()). + add(GetVendorPatchlevel()); + + std::vector cborData = array.encode(); + errorCode = sendData(Instruction::INS_SET_VERSION_PATCHLEVEL_CMD, cborData, cborOutData); + if (ErrorCode::OK == errorCode) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = decodeData(cborConverter_, std::vector(cborOutData.begin(), cborOutData.end()-2), + true); + } + if (ErrorCode::OK != errorCode) + LOG(ERROR) << "Failed to set os_version, os_patchlevel and vendor_patchlevel err: " << (int32_t) errorCode; + + return errorCode; +} + JavacardKeymaster4Device::JavacardKeymaster4Device(): softKm_(new ::keymaster::AndroidKeymaster( []() -> auto { auto context = new JavaCardSoftKeymasterContext(); context->SetSystemVersion(GetOsVersion(), GetOsPatchlevel()); return context; }(), - kOperationTableSize)), oprCtx_(new OperationContext()) { + kOperationTableSize)), oprCtx_(new OperationContext()), isEachSystemPropertySet(false) { + if (ErrorCode::OK == setAndroidSystemProperties(cborConverter_)) { + isEachSystemPropertySet = true; + } } @@ -520,26 +546,6 @@ Return JavacardKeymaster4Device::getHmacSharingParameters(getHmacSharingPa return Void(); } -static ErrorCode setAndroidSystemProperties(CborConverter cborConverter_) { - ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; - cppbor::Array array; - std::unique_ptr item; - std::vector cborOutData; - - array.add(GetOsVersion()). - add(GetOsPatchlevel()). - add(GetVendorPatchlevel()); - - std::vector cborData = array.encode(); - errorCode = sendData(Instruction::INS_SET_VERSION_PATCHLEVEL_CMD, cborData, cborOutData); - if (ErrorCode::OK == errorCode) { - //Skip last 2 bytes in cborData, it contains status. - std::tie(item, errorCode) = decodeData(cborConverter_, std::vector(cborOutData.begin(), cborOutData.end()-2), - true); - } - return errorCode; -} - Return JavacardKeymaster4Device::computeSharedHmac(const hidl_vec& params, computeSharedHmac_cb _hidl_cb) { cppbor::Array array; std::unique_ptr item; @@ -550,12 +556,15 @@ Return JavacardKeymaster4Device::computeSharedHmac(const hidl_vec softKm_; std::unique_ptr oprCtx_; + bool isEachSystemPropertySet; }; } // namespace javacard From f3891fdba0a802bf93cc750c6d105b80ddf550f9 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Mon, 26 Apr 2021 16:00:09 +0530 Subject: [PATCH 4/6] 1. Removed VTS_EMULATOR and instead used USE_OMAPI and USE_SEHAL 2. Add systemproperties inside provision tool --- .../4.1/JavacardKeymaster4Device.cpp | 17 +++++--- HAL/keymaster/Android.bp | 7 ---- ProvisioningTool/Provision.cpp | 24 +++++++++-- ProvisioningTool/Provision.h | 10 ++++- ProvisioningTool/ProvisionTool.cpp | 40 ++++++++++++------- ProvisioningTool/sample_json.txt | 3 -- 6 files changed, 65 insertions(+), 36 deletions(-) diff --git a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp index 65a0fda7..ae21ce94 100644 --- a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp +++ b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp @@ -469,6 +469,9 @@ JavacardKeymaster4Device::JavacardKeymaster4Device(): softKm_(new ::keymaster::A return context; }(), kOperationTableSize)), oprCtx_(new OperationContext()), isEachSystemPropertySet(false) { + // Send Android system properties like os_version, os_patchlevel and vendor_patchlevel + // to the Applet. Incase if setting system properties fails here, again try setting + // it from computeSharedHmac. if (ErrorCode::OK == setAndroidSystemProperties(cborConverter_)) { isEachSystemPropertySet = true; } @@ -528,7 +531,7 @@ Return JavacardKeymaster4Device::getHmacSharingParameters(getHmacSharingPa } } } -#ifdef VTS_EMULATOR +#if (!defined(USE_OMAPI) && !defined(USE_SEHAL)) /* TODO temporary fix: vold daemon calls performHmacKeyAgreement. At that time when vold calls this API there is no * network connectivity and socket cannot be connected. So as a hack we are calling softkeymaster to getHmacSharing * parameters. @@ -554,19 +557,21 @@ Return JavacardKeymaster4Device::computeSharedHmac(const hidl_vec tempVec; cppbor::Array outerArray; - // The Android system properties like OS_VERSION, OS_PATCHLEVEL and VENDOR_PATCHLEVEL are to // be delivered to the Applet when the HAL is first loaded. Incase if settting system properties - // failed at construction time then set this is one of the ideal places to send this information + // failed at construction time then this is one of the ideal places to send this information // to the Applet as computeSharedHmac is called everytime when Android device boots. +#if (defined(USE_OMAPI) || defined(USE_SEHAL)) if (!isEachSystemPropertySet) { - if (ErrorCode::OK != (errorCode = setAndroidSystemProperties(cborConverter_))) { + errorCode = setAndroidSystemProperties(cborConverter_); + if (ErrorCode::OK != errorCode) { LOG(ERROR) << " Failed to set os_version, os_patchlevel and vendor_patchlevel err: " << (int32_t)errorCode; + _hidl_cb(errorCode, sharingCheck); return Void(); } isEachSystemPropertySet = true; } - +#endif for(size_t i = 0; i < params.size(); ++i) { cppbor::Array innerArray; @@ -595,7 +600,7 @@ Return JavacardKeymaster4Device::computeSharedHmac(const hidl_vec& preSharedSec return errorCode; } -ErrorCode Provision::provisionBootParameters(BootParams& bootParams) { +ErrorCode Provision::setAndroidSystemProperties() { ErrorCode errorCode = ErrorCode::OK; cppbor::Array array; std::vector apdu; std::vector response; - Instruction ins = Instruction::INS_SET_BOOT_PARAMS_CMD; + Instruction ins = Instruction::INS_SET_VERSION_PATCHLEVEL_CMD; array.add(GetOsVersion()). add(GetOsPatchlevel()). - add(bootParams.vendorPatchLevel). - add(bootParams.bootPatchLevel). + add(GetVendorPatchlevel()); + std::vector cborData = array.encode(); + + if(ErrorCode::OK != (errorCode = sendProvisionData(pTransportFactory, ins, cborData, response))) { + return errorCode; + } + return errorCode; +} + +ErrorCode Provision::provisionBootParameters(BootParams& bootParams) { + ErrorCode errorCode = ErrorCode::OK; + cppbor::Array array; + std::vector apdu; + std::vector response; + Instruction ins = Instruction::INS_SET_BOOT_PARAMS_CMD; + + array.add(bootParams.bootPatchLevel). /* Verified Boot Key */ add(bootParams.verifiedBootKey). /* Verified Boot Hash */ diff --git a/ProvisioningTool/Provision.h b/ProvisioningTool/Provision.h index e541c496..68a7f1d1 100644 --- a/ProvisioningTool/Provision.h +++ b/ProvisioningTool/Provision.h @@ -25,10 +25,13 @@ namespace keymaster { namespace V4_1 { namespace javacard { -typedef struct BootParams_ { +typedef struct SystemProperties__ { uint32_t osVersion; uint32_t osPatchLevel; uint32_t vendorPatchLevel; +} SystemProperties; + +typedef struct BootParams_ { uint32_t bootPatchLevel; std::vector verifiedBootKey; std::vector verifiedBootKeyHash; @@ -77,6 +80,11 @@ class Provision { * Provision the boot parameters. */ ErrorCode provisionBootParameters(BootParams& bootParams ); + /** + * Set system properties. + */ + ErrorCode setAndroidSystemProperties(); + /** * Locks the provision. After this no more provision commanands are allowed. */ diff --git a/ProvisioningTool/ProvisionTool.cpp b/ProvisioningTool/ProvisionTool.cpp index 0f240b3c..3ff242f5 100644 --- a/ProvisioningTool/ProvisionTool.cpp +++ b/ProvisioningTool/ProvisionTool.cpp @@ -136,8 +136,9 @@ void usage() { printf("-c, --cert_chain jsonFile \t Provision attestation certificate chain \n"); printf("-p, --cert_params jsonFile \t Provision attestation certificate parameters \n"); printf("-i, --attest_ids jsonFile \t Provision attestation IDs \n"); - printf("-r, --shared_secret jsonFile \t Provion shared secret \n"); - printf("-b, --set_boot_params jsonFile \t Provion boot parameters \n"); + printf("-r, --shared_secret jsonFile \t Provision shared secret \n"); + printf("-b, --set_boot_params jsonFile \t Set boot parameters \n"); + printf("-e, --set_system_properties \t Set system properties \n"); printf("-s, --provision_status \t Prints the provision status.\n"); printf("-l, --lock_provision \t Locks the provision commands.\n"); } @@ -174,6 +175,18 @@ bool getBootParameterBlobValue(Json::Value& bootParamsObj, const char* key, std: return true; } +bool setAndroidSystemProperties() { + ErrorCode err = ErrorCode::OK; + bool ret = false; + if (ErrorCode::OK != (err = mProvision.setAndroidSystemProperties())) { + printf("\n set boot parameters failed with err:%d \n", (int32_t)err); + return ret; + } + printf("\n SE successfully accepted system properties.\n"); + return true; + +} + bool setBootParameters(const char* filename) { Json::Value bootParamsObj; bool ret = false; @@ -186,18 +199,6 @@ bool setBootParameters(const char* filename) { bootParamsObj = root.get("set_boot_params", bootParamsObj); if (!bootParamsObj.isNull()) { - if(!getBootParameterIntValue(bootParamsObj, "os_version", &bootParams.osVersion)) { - printf("\n Invalid value for os_version or os_version tag missing\n"); - return ret; - } - if(!getBootParameterIntValue(bootParamsObj, "os_patch_level", &bootParams.osPatchLevel)) { - printf("\n Invalid value for os_patch_level or os_patch_level tag missing\n"); - return ret; - } - if(!getBootParameterIntValue(bootParamsObj, "vendor_patch_level", &bootParams.vendorPatchLevel)) { - printf("\n Invalid value for vendor_patch_level or vendor_patch_level tag missing\n"); - return ret; - } if(!getBootParameterIntValue(bootParamsObj, "boot_patch_level", &bootParams.bootPatchLevel)) { printf("\n Invalid value for boot_patch_level or boot_patch_level tag missing\n"); return ret; @@ -492,6 +493,9 @@ bool provision(const char* filename) { if(!setBootParameters(filename)) { return false; } + if(!setAndroidSystemProperties()) { + return false; + } return true; } @@ -525,6 +529,7 @@ int main(int argc, char* argv[]) {"attest_ids", required_argument, NULL, 'i'}, {"shared_secret", required_argument, NULL, 'r'}, {"set_boot_params", required_argument, NULL, 'b'}, + {"set_system_properties", no_argument, NULL, 'e'}, {"provision_status", no_argument, NULL, 's'}, {"lock_provision", no_argument, NULL, 'l'}, {"help", no_argument, NULL, 'h'}, @@ -539,7 +544,7 @@ int main(int argc, char* argv[]) mProvision.init(); /* getopt_long stores the option index here. */ - while ((c = getopt_long(argc, argv, ":slha:k:c:p:i:r:b:", longOpts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, ":slhea:k:c:p:i:r:b:", longOpts, NULL)) != -1) { switch(c) { case 'a': //all @@ -576,6 +581,11 @@ int main(int argc, char* argv[]) if(!setBootParameters(optarg)) printf("\n Failed to set boot parameters.\n"); break; + case 'e': + //set Android system properties + if(!setAndroidSystemProperties()) + printf("\n Failed to set android system properties.\n"); + break; case 's': if(!getProvisionStatus()) printf("\n Failed to get provision status \n"); diff --git a/ProvisioningTool/sample_json.txt b/ProvisioningTool/sample_json.txt index fbfd71de..7885b2aa 100644 --- a/ProvisioningTool/sample_json.txt +++ b/ProvisioningTool/sample_json.txt @@ -11,9 +11,6 @@ }, "shared_secret": "0000000000000000000000000000000000000000000000000000000000000000", "set_boot_params": { - "os_version": 100, - "os_patch_level": 100, - "vendor_patch_level": 0, "boot_patch_level": 0, "verified_boot_key": "0000000000000000000000000000000000000000000000000000000000000000", "verified_boot_key_hash": "0000000000000000000000000000000000000000000000000000000000000000", From d489672214d0a4f9f74c1a902e0c1e66b89d5b08 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Tue, 27 Apr 2021 15:40:14 +0530 Subject: [PATCH 5/6] Enable VTS_EMULATOR for x86 and x86_64 builds --- HAL/keymaster/4.1/JavacardKeymaster4Device.cpp | 6 +++--- HAL/keymaster/Android.bp | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp index ae21ce94..845071eb 100644 --- a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp +++ b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp @@ -531,7 +531,7 @@ Return JavacardKeymaster4Device::getHmacSharingParameters(getHmacSharingPa } } } -#if (!defined(USE_OMAPI) && !defined(USE_SEHAL)) +#ifdef VTS_EMULATOR /* TODO temporary fix: vold daemon calls performHmacKeyAgreement. At that time when vold calls this API there is no * network connectivity and socket cannot be connected. So as a hack we are calling softkeymaster to getHmacSharing * parameters. @@ -557,11 +557,11 @@ Return JavacardKeymaster4Device::computeSharedHmac(const hidl_vec tempVec; cppbor::Array outerArray; +#ifndef VTS_EMULATOR // The Android system properties like OS_VERSION, OS_PATCHLEVEL and VENDOR_PATCHLEVEL are to // be delivered to the Applet when the HAL is first loaded. Incase if settting system properties // failed at construction time then this is one of the ideal places to send this information // to the Applet as computeSharedHmac is called everytime when Android device boots. -#if (defined(USE_OMAPI) || defined(USE_SEHAL)) if (!isEachSystemPropertySet) { errorCode = setAndroidSystemProperties(cborConverter_); if (ErrorCode::OK != errorCode) { @@ -600,7 +600,7 @@ Return JavacardKeymaster4Device::computeSharedHmac(const hidl_vec Date: Tue, 27 Apr 2021 11:35:13 +0100 Subject: [PATCH 6/6] clear system properties in setBootParameters --- .../javacard/keymaster/KMKeymasterApplet.java | 4 ++++ .../android/javacard/keymaster/KMRepository.java | 14 +++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 4caa9d51..2f3e187f 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -3235,6 +3235,10 @@ private void processSetBootParamsCmd(APDU apdu) { enumVal = KMEnum.cast(tmpVariables[4]).getVal(); repository.setBootloaderLocked(enumVal == KMType.DEVICE_LOCKED_TRUE); + // Clear Android system properties expect boot patch level as it is + // already set. + repository.clearAndroidSystemProperties(); + // Clear the Computed SharedHmac and Hmac nonce from persistent memory. repository.clearComputedHmac(); repository.clearHmacNonce(); diff --git a/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/src/com/android/javacard/keymaster/KMRepository.java index 07caec72..c9fe8398 100644 --- a/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/Applet/src/com/android/javacard/keymaster/KMRepository.java @@ -57,7 +57,7 @@ public class KMRepository implements KMUpgradable { public static final byte CERT_ISSUER = 10; public static final byte CERT_EXPIRY_TIME = 11; public static final byte BOOT_OS_VERSION = 12; - public static final byte BOOT_OS_PATCH = 13; + public static final byte BOOT_OS_PATCH_LEVEL = 13; public static final byte VENDOR_PATCH_LEVEL = 14; public static final byte BOOT_PATCH_LEVEL = 15; public static final byte BOOT_VERIFIED_BOOT_KEY = 16; @@ -532,7 +532,7 @@ public short getBootPatchLevel() { } public short getOsPatch() { - short blob = readData(BOOT_OS_PATCH); + short blob = readData(BOOT_OS_PATCH_LEVEL); if (blob != 0) { return KMInteger.uint_32( KMByteBlob.cast(blob).getBuffer(), KMByteBlob.cast(blob).getStartOff()); @@ -638,6 +638,14 @@ public void setBootPatchLevel(byte[] buf, short start, short len) { writeDataEntry(BOOT_PATCH_LEVEL, buf, start, len); } + public void clearAndroidSystemProperties() { + clearDataEntry(BOOT_OS_VERSION); + clearDataEntry(BOOT_OS_PATCH_LEVEL); + clearDataEntry(VENDOR_PATCH_LEVEL); + // Don't clear BOOT_PATCH_LEVEL as it is part of + // boot parameters. + } + public void setBootloaderLocked(boolean flag) { short start = alloc(DEVICE_LOCK_FLAG_SIZE); if (flag) { @@ -683,7 +691,7 @@ public void setOsPatch(byte[] buf, short start, short len) { if (len != OS_PATCH_SIZE) { KMException.throwIt(KMError.INVALID_INPUT_LENGTH); } - writeDataEntry(BOOT_OS_PATCH, buf, start, len); + writeDataEntry(BOOT_OS_PATCH_LEVEL, buf, start, len); } public void setVerifiedBootKey(byte[] buf, short start, short len) {