diff --git a/HAL/keymaster/4.1/CborConverter.cpp b/HAL/keymaster/4.1/CborConverter.cpp index b54b9337..c0643ed8 100644 --- a/HAL/keymaster/4.1/CborConverter.cpp +++ b/HAL/keymaster/4.1/CborConverter.cpp @@ -297,22 +297,26 @@ bool CborConverter::getHmacSharingParameters(const std::unique_ptr& item, bool CborConverter::addVerificationToken(Array& array, const VerificationToken& verificationToken) { - array.add(verificationToken.challenge); - array.add(verificationToken.timestamp); - addKeyparameters(array, verificationToken.parametersVerified); - array.add(static_cast(verificationToken.securityLevel)); - array.add((std::vector(verificationToken.mac))); + Array vToken; + vToken.add(verificationToken.challenge); + vToken.add(verificationToken.timestamp); + addKeyparameters(vToken, verificationToken.parametersVerified); + vToken.add(static_cast(verificationToken.securityLevel)); + vToken.add((std::vector(verificationToken.mac))); + array.add(std::move(vToken)); return true; } bool CborConverter::addHardwareAuthToken(Array& array, const HardwareAuthToken& authToken) { - array.add(authToken.challenge); - array.add(authToken.userId); - array.add(authToken.authenticatorId); - array.add(static_cast(authToken.authenticatorType)); - array.add(authToken.timestamp); - array.add((std::vector(authToken.mac))); + Array hwAuthToken; + hwAuthToken.add(authToken.challenge); + hwAuthToken.add(authToken.userId); + hwAuthToken.add(authToken.authenticatorId); + hwAuthToken.add(static_cast(authToken.authenticatorType)); + hwAuthToken.add(authToken.timestamp); + hwAuthToken.add((std::vector(authToken.mac))); + array.add(std::move(hwAuthToken)); return true; } diff --git a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp index 98b81074..ef1e4f04 100644 --- a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp +++ b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp @@ -24,8 +24,12 @@ #include #include #include +#include +#include +#include #include +#include //#define JAVACARD_KEYMASTER_NAME "JavacardKeymaster4.1Device v0.1" //#define JAVACARD_KEYMASTER_AUTHOR "Android Open Source Project" @@ -61,14 +65,19 @@ enum class Instruction { INS_FINISH_OPERATION_CMD = 0x21, INS_ABORT_OPERATION_CMD = 0x22, INS_PROVISION_CMD = 0x23, - INS_DEVICE_LOCKED_CMD = 0x24, - INS_EARLY_BOOT_ENDED_CMD = 0x25 + INS_SET_BOOT_PARAMS_CMD = 0x24, + INS_DEVICE_LOCKED_CMD = 0x25, + INS_EARLY_BOOT_ENDED_CMD = 0x26, }; inline ErrorCode legacy_enum_conversion(const keymaster_error_t value) { return static_cast(value); } +inline keymaster_purpose_t legacy_enum_conversion(const KeyPurpose value) { + return static_cast(value); +} + inline keymaster_key_format_t legacy_enum_conversion(const KeyFormat value) { return static_cast(value); } @@ -143,16 +152,102 @@ class KmParamSet : public keymaster_key_param_set_t { ~KmParamSet() { delete[] params; } }; +static inline hidl_vec kmParamSet2Hidl(const keymaster_key_param_set_t& set) { + hidl_vec result; + if (set.length == 0 || set.params == nullptr) + return result; + + result.resize(set.length); + keymaster_key_param_t* params = set.params; + for (size_t i = 0; i < set.length; ++i) { + auto tag = params[i].tag; + result[i].tag = legacy_enum_conversion(tag); + switch (typeFromTag(tag)) { + case KM_ENUM: + case KM_ENUM_REP: + result[i].f.integer = params[i].enumerated; + break; + case KM_UINT: + case KM_UINT_REP: + result[i].f.integer = params[i].integer; + break; + case KM_ULONG: + case KM_ULONG_REP: + result[i].f.longInteger = params[i].long_integer; + break; + case KM_DATE: + result[i].f.dateTime = params[i].date_time; + break; + case KM_BOOL: + result[i].f.boolValue = params[i].boolean; + break; + case KM_BIGNUM: + case KM_BYTES: + result[i].blob.setToExternal(const_cast(params[i].blob.data), + params[i].blob.data_length); + break; + case KM_INVALID: + default: + params[i].tag = KM_TAG_INVALID; + /* just skip */ + break; + } + } + return result; +} + +inline hidl_vec kmBuffer2hidlVec(const ::keymaster::Buffer& buf) { + hidl_vec result; + result.setToExternal(const_cast(buf.peek_read()), buf.available_read()); + return result; +} + +static inline void blob2Vec(const uint8_t *from, size_t size, std::vector& to) { + for(int i = 0; i < size; ++i) { + to.push_back(from[i]); + } +} + +static inline ErrorCode parseWrappedKey(const hidl_vec& wrappedKeyData, std::vector& iv, std::vector& transitKey, +std::vector& secureKey, std::vector& tag, hidl_vec& authList, KeyFormat& +keyFormat, std::vector& wrappedKeyDescription) { + KeymasterBlob kmIv; + KeymasterKeyBlob kmTransitKey; + KeymasterKeyBlob kmSecureKey; + KeymasterBlob kmTag; + AuthorizationSet authSet; + keymaster_key_format_t kmKeyFormat; + KeymasterBlob kmWrappedKeyDescription; + KeymasterKeyBlob kmWrappedKeyData; + + kmWrappedKeyData.key_material = dup_buffer(wrappedKeyData.data(), wrappedKeyData.size()); + + keymaster_error_t error = parse_wrapped_key(kmWrappedKeyData, &kmIv, &kmTransitKey, + &kmSecureKey, &kmTag, &authSet, + &kmKeyFormat, &kmWrappedKeyDescription); + if (error != KM_ERROR_OK) return legacy_enum_conversion(error); + blob2Vec(kmIv.data, kmIv.data_length, iv); + blob2Vec(kmTransitKey.key_material, kmTransitKey.key_material_size, transitKey); + blob2Vec(kmSecureKey.key_material, kmSecureKey.key_material_size, secureKey); + blob2Vec(kmTag.data, kmTag.data_length, tag); + authList = kmParamSet2Hidl(authSet); + keyFormat = static_cast(kmKeyFormat); + blob2Vec(kmWrappedKeyDescription.data, kmWrappedKeyDescription.data_length, wrappedKeyDescription); + + return ErrorCode::OK; +} + + JavacardKeymaster4Device::JavacardKeymaster4Device(): softKm_(new ::keymaster::AndroidKeymaster( []() -> auto { - auto context = new PureSoftKeymasterContext(); + auto context = new JavaCardSoftKeymasterContext(); context->SetSystemVersion(GetOsVersion(), GetOsPatchlevel()); return context; }(), - kOperationTableSize)) { + kOperationTableSize)), oprCtx_(new OperationContext()), setUpBootParams(false) { pTransportFactory = std::unique_ptr(new se_transport::TransportFactory( android::base::GetBoolProperty("ro.kernel.qemu", false))); - assert(pTransportFactory->openConnection() && "Failed to open connection with secure element"); + pTransportFactory->openConnection(); } JavacardKeymaster4Device::~JavacardKeymaster4Device() {} @@ -195,15 +290,53 @@ uint16_t getStatus(std::vector& inputData) { return (inputData.at(inputData.size()-2) << 8) | (inputData.at(inputData.size()-1)); } -inline ErrorCode sendData(std::unique_ptr& transport, Instruction ins, std::vector& inData, -std::vector& response) { +/* This method should be called at the time when HAL is initialized for the first time */ +Return setBootParams(std::unique_ptr& transport) { + cppbor::Array array; std::vector apdu; - ErrorCode ret = constructApduMessage(ins, inData, apdu); + std::vector response; + Instruction ins = Instruction::INS_SET_BOOT_PARAMS_CMD; + std::vector verifiedBootKey(32, 0); + std::vector verifiedBootKeyHash(32, 0); + array.add(GetOsVersion()). + add(GetOsPatchlevel()). + /* Verified Boot Key */ + add(verifiedBootKey). + /* Verified Boot Hash */ + add(verifiedBootKeyHash). + /* boot state */ + add(static_cast(KM_VERIFIED_BOOT_UNVERIFIED)). + /* device locked */ + add(0); /* false */ + std::vector cborData = array.encode(); + + ErrorCode ret = constructApduMessage(ins, cborData, apdu); if(ret != ErrorCode::OK) return ret; - //if(!transport->openConnection()) { - // return (ErrorCode::SECURE_HW_COMMUNICATION_FAILED); - //} + if(!transport->sendData(apdu.data(), apdu.size(), response)) { + return (ErrorCode::SECURE_HW_COMMUNICATION_FAILED); + } + + if((response.size() < 2) || (getStatus(response) != APDU_RESP_STATUS_OK)) { + return (ErrorCode::UNKNOWN_ERROR); + } + return ErrorCode::OK; +} + +ErrorCode sendData(JavacardKeymaster4Device *pKeymaster, std::unique_ptr& transport, Instruction ins, std::vector& inData, +std::vector& response) { + ErrorCode ret = ErrorCode::UNKNOWN_ERROR; + std::vector apdu; + + if(!pKeymaster->getBootParamsInitialized()) { + if((ret = setBootParams(transport)) != ErrorCode::OK) { + return ret; + } + pKeymaster->setBootParams(true); + } + + ret = constructApduMessage(ins, inData, apdu); + if(ret != ErrorCode::OK) return ret; if(!transport->sendData(apdu.data(), apdu.size(), response)) { return (ErrorCode::SECURE_HW_COMMUNICATION_FAILED); @@ -225,7 +358,7 @@ Return JavacardKeymaster4Device::getHardwareInfo(getHardwareInfo_cb _hidl_ hidl_string jcKeymasterName; hidl_string jcKeymasterAuthor; - ErrorCode ret = sendData(pTransportFactory, Instruction::INS_GET_HW_INFO_CMD, input, resp); + ErrorCode ret = sendData(this, pTransportFactory, Instruction::INS_GET_HW_INFO_CMD, input, resp); if((ret == ErrorCode::OK) && (resp.size() > 2)) { //Skip last 2 bytes in cborData, it contains status. @@ -252,7 +385,7 @@ Return JavacardKeymaster4Device::getHmacSharingParameters(getHmacSharingPa HmacSharingParameters hmacSharingParameters; ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; - errorCode = sendData(pTransportFactory, Instruction::INS_GET_HMAC_SHARING_PARAM_CMD, input, cborData); + errorCode = sendData(this, pTransportFactory, Instruction::INS_GET_HMAC_SHARING_PARAM_CMD, input, cborData); if((errorCode == ErrorCode::OK) && (cborData.size() > 2)) { //Skip last 2 bytes in cborData, it contains status. @@ -286,7 +419,7 @@ Return JavacardKeymaster4Device::computeSharedHmac(const hidl_vec cborData = array.encode(); - errorCode = sendData(pTransportFactory, Instruction::INS_COMPUTE_SHARED_HMAC_CMD, cborData, cborOutData); + errorCode = sendData(this, pTransportFactory, Instruction::INS_COMPUTE_SHARED_HMAC_CMD, cborData, cborOutData); if((errorCode == ErrorCode::OK) && (cborData.size() > 2)) { //Skip last 2 bytes in cborData, it contains status. @@ -315,7 +448,7 @@ Return JavacardKeymaster4Device::verifyAuthorization(uint64_t operationHan cborConverter_.addHardwareAuthToken(array, authToken); std::vector cborData = array.encode(); - errorCode = sendData(pTransportFactory, Instruction::INS_VERIFY_AUTHORIZATION_CMD, cborData, cborOutData); + errorCode = sendData(this, pTransportFactory, Instruction::INS_VERIFY_AUTHORIZATION_CMD, cborData, cborOutData); if((errorCode == ErrorCode::OK) && (cborData.size() > 2)) { //Skip last 2 bytes in cborData, it contains status. @@ -339,7 +472,7 @@ Return JavacardKeymaster4Device::addRngEntropy(const hidl_vec(data)); std::vector cborData = array.encode(); - errorCode = sendData(pTransportFactory, Instruction::INS_ADD_RNG_ENTROPY_CMD, cborData, cborOutData); + errorCode = sendData(this, pTransportFactory, Instruction::INS_ADD_RNG_ENTROPY_CMD, cborData, cborOutData); if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { //Skip last 2 bytes in cborData, it contains status. @@ -357,10 +490,11 @@ Return JavacardKeymaster4Device::generateKey(const hidl_vec& ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; KeyCharacteristics keyCharacteristics; + /* Convert to cbor format */ cborConverter_.addKeyparameters(array, keyParams); std::vector cborData = array.encode(); - errorCode = sendData(pTransportFactory, Instruction::INS_GENERATE_KEY_CMD, cborData, cborOutData); + errorCode = sendData(this, pTransportFactory, Instruction::INS_GENERATE_KEY_CMD, cborData, cborOutData); if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { //Skip last 2 bytes in cborData, it contains status. @@ -376,8 +510,9 @@ Return JavacardKeymaster4Device::generateKey(const hidl_vec& } Return JavacardKeymaster4Device::importKey(const hidl_vec& keyParams, KeyFormat keyFormat, const hidl_vec& keyData, importKey_cb _hidl_cb) { - keymaster_error_t error; + keymaster_error_t error = KM_ERROR_UNKNOWN_ERROR; hidl_vec inKey; + KeymasterKeyBlob key_material; if (keyFormat == KeyFormat::PKCS8) { ImportKeyRequest request; @@ -390,15 +525,16 @@ Return JavacardKeymaster4Device::importKey(const hidl_vec& k KeyCharacteristics resultCharacteristics; hidl_vec resultKeyBlob; + error = response.error; if (response.error == KM_ERROR_OK) { - AuthorizationSet hidden; - error = BuildHiddenAuthorizations(request.key_description, &hidden, softwareRootOfTrust); - if (error == KM_ERROR_OK) { - KeymasterKeyBlob key_material; - DeserializeIntegrityAssuredBlob(KeymasterKeyBlob(response.key_blob), hidden, &key_material, &response.enforced, &response.unenforced); - - inKey.setToExternal(const_cast(key_material.key_material), key_material.key_material_size); - } + key_material = KeymasterKeyBlob(response.key_blob); + inKey.setToExternal(const_cast(key_material.key_material), key_material.key_material_size); + } + if(error != KM_ERROR_OK) { + KeyCharacteristics resultCharacteristics; + hidl_vec resultKeyBlob; + _hidl_cb(legacy_enum_conversion(error), resultKeyBlob, resultCharacteristics); + return Void(); } } else if (keyFormat == KeyFormat::RAW) { //convert keyData to keyMaterial @@ -410,31 +546,31 @@ Return JavacardKeymaster4Device::importKey(const hidl_vec& k return Void(); } - cppbor::Array array; - std::unique_ptr item; - hidl_vec keyBlob; - std::vector cborOutData; - ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; - KeyCharacteristics keyCharacteristics; - - cborConverter_.addKeyparameters(array, keyParams); - array.add(static_cast(keyFormat)); - array.add(std::vector(inKey)); - std::vector cborData = array.encode(); - - errorCode = sendData(pTransportFactory, Instruction::INS_IMPORT_KEY_CMD, cborData, cborOutData); - - if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { - //Skip last 2 bytes in cborData, it contains status. - std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), - true); - if (item != nullptr) { - cborConverter_.getBinaryArray(item, 1, keyBlob); - cborConverter_.getKeyCharacteristics(item, 2, keyCharacteristics); - } - } - _hidl_cb(errorCode, keyBlob, keyCharacteristics); - return Void(); + cppbor::Array array; + std::unique_ptr item; + hidl_vec keyBlob; + std::vector cborOutData; + ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + KeyCharacteristics keyCharacteristics; + + cborConverter_.addKeyparameters(array, keyParams); + array.add(static_cast(KeyFormat::RAW)); //PKCS8 is already converted to RAW + array.add(std::vector(inKey)); + std::vector cborData = array.encode(); + + errorCode = sendData(this, pTransportFactory, Instruction::INS_IMPORT_KEY_CMD, cborData, cborOutData); + + if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), + true); + if (item != nullptr) { + cborConverter_.getBinaryArray(item, 1, keyBlob); + cborConverter_.getKeyCharacteristics(item, 2, keyCharacteristics); + } + } + _hidl_cb(errorCode, keyBlob, keyCharacteristics); + return Void(); } Return JavacardKeymaster4Device::importWrappedKey(const hidl_vec& wrappedKeyData, const hidl_vec& wrappingKeyBlob, const hidl_vec& maskingKey, const hidl_vec& unwrappingParams, uint64_t passwordSid, uint64_t biometricSid, importWrappedKey_cb _hidl_cb) { @@ -444,8 +580,25 @@ Return JavacardKeymaster4Device::importWrappedKey(const hidl_vec& std::vector cborOutData; ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; KeyCharacteristics keyCharacteristics; - - array.add(std::vector(wrappedKeyData)); + std::vector iv; + std::vector transitKey; + std::vector secureKey; + std::vector tag; + hidl_vec authList; + KeyFormat keyFormat; + std::vector wrappedKeyDescription; + + if(ErrorCode::OK != (errorCode = parseWrappedKey(wrappedKeyData, iv, transitKey, secureKey, + tag, authList, keyFormat, wrappedKeyDescription))) { + _hidl_cb(errorCode, keyBlob, keyCharacteristics); + return Void(); + } + array.add(transitKey); + array.add(iv); + array.add(static_cast(keyFormat)); + cborConverter_.addKeyparameters(array, authList); + array.add(secureKey); + array.add(tag); array.add(std::vector(wrappingKeyBlob)); array.add(std::vector(maskingKey)); cborConverter_.addKeyparameters(array, unwrappingParams); @@ -453,7 +606,7 @@ Return JavacardKeymaster4Device::importWrappedKey(const hidl_vec& array.add(biometricSid); /* TODO if biometricSid optional if user not sent this don't encode this cbor format */ std::vector cborData = array.encode(); - errorCode = sendData(pTransportFactory, Instruction::INS_IMPORT_WRAPPED_KEY_CMD, cborData, cborOutData); + errorCode = sendData(this, pTransportFactory, Instruction::INS_IMPORT_WRAPPED_KEY_CMD, cborData, cborOutData); if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { //Skip last 2 bytes in cborData, it contains status. @@ -481,7 +634,7 @@ Return JavacardKeymaster4Device::getKeyCharacteristics(const hidl_vec(appData)); std::vector cborData = array.encode(); - errorCode = sendData(pTransportFactory, Instruction::INS_GET_KEY_CHARACTERISTICS_CMD, cborData, cborOutData); + errorCode = sendData(this, pTransportFactory, Instruction::INS_GET_KEY_CHARACTERISTICS_CMD, cborData, cborOutData); if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { //Skip last 2 bytes in cborData, it contains status. @@ -495,20 +648,36 @@ Return JavacardKeymaster4Device::getKeyCharacteristics(const hidl_vec JavacardKeymaster4Device::exportKey(KeyFormat keyFormat, const hidl_vec& keyBlob, const hidl_vec& clientId, const hidl_vec& appData, exportKey_cb _hidl_cb) { +Return JavacardKeymaster4Device::exportKey(KeyFormat exportFormat, const hidl_vec& keyBlob, const hidl_vec& /*clientId*/, const hidl_vec& /*appData*/, exportKey_cb _hidl_cb) { + + ExportKeyRequest request; + request.key_format = legacy_enum_conversion(exportFormat); + request.SetKeyMaterial(keyBlob.data(), keyBlob.size()); + //addClientAndAppData(clientId, appData, &request.additional_params); + + ExportKeyResponse response; + softKm_->ExportKey(request, &response); + + hidl_vec resultKeyBlob; + if (response.error == KM_ERROR_OK) { + resultKeyBlob.setToExternal(response.key_data, response.key_data_length); + } + _hidl_cb(legacy_enum_conversion(response.error), resultKeyBlob); + return Void(); +/* cppbor::Array array; std::unique_ptr item; hidl_vec keyMaterial; std::vector cborOutData; ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; - array.add(static_cast(keyFormat)); + array.add(static_cast(exportFormat)); array.add(std::vector(keyBlob)); array.add(std::vector(clientId)); array.add(std::vector(appData)); std::vector cborData = array.encode(); - errorCode = sendData(pTransportFactory, Instruction::INS_EXPORT_KEY_CMD, cborData, cborOutData); + errorCode = sendData(this, pTransportFactory, Instruction::INS_EXPORT_KEY_CMD, cborData, cborOutData); if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { //Skip last 2 bytes in cborData, it contains status. @@ -519,7 +688,7 @@ Return JavacardKeymaster4Device::exportKey(KeyFormat keyFormat, const hidl } } _hidl_cb(errorCode, keyMaterial); - return Void(); + return Void();*/ } Return JavacardKeymaster4Device::attestKey(const hidl_vec& keyToAttest, const hidl_vec& attestParams, attestKey_cb _hidl_cb) { @@ -534,7 +703,7 @@ Return JavacardKeymaster4Device::attestKey(const hidl_vec& keyToA cborConverter_.addKeyparameters(array, attestParams); std::vector cborData = array.encode(); - errorCode = sendData(pTransportFactory, Instruction::INS_ATTEST_KEY_CMD, cborData, cborOutData); + errorCode = sendData(this, pTransportFactory, Instruction::INS_ATTEST_KEY_CMD, cborData, cborOutData); if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { //Skip last 2 bytes in cborData, it contains status. @@ -559,7 +728,7 @@ Return JavacardKeymaster4Device::upgradeKey(const hidl_vec& keyBl cborConverter_.addKeyparameters(array, upgradeParams); std::vector cborData = array.encode(); - errorCode = sendData(pTransportFactory, Instruction::INS_UPGRADE_KEY_CMD, cborData, cborOutData); + errorCode = sendData(this, pTransportFactory, Instruction::INS_UPGRADE_KEY_CMD, cborData, cborOutData); if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { //Skip last 2 bytes in cborData, it contains status. @@ -582,7 +751,7 @@ Return JavacardKeymaster4Device::deleteKey(const hidl_vec& k array.add(std::vector(keyBlob)); std::vector cborData = array.encode(); - errorCode = sendData(pTransportFactory, Instruction::INS_DELETE_KEY_CMD, cborData, cborOutData); + errorCode = sendData(this, pTransportFactory, Instruction::INS_DELETE_KEY_CMD, cborData, cborOutData); if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { //Skip last 2 bytes in cborData, it contains status. @@ -598,7 +767,7 @@ Return JavacardKeymaster4Device::deleteAllKeys() { std::vector input; ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; - errorCode = sendData(pTransportFactory, Instruction::INS_DELETE_ALL_KEYS_CMD, input, cborOutData); + errorCode = sendData(this, pTransportFactory, Instruction::INS_DELETE_ALL_KEYS_CMD, input, cborOutData); if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { //Skip last 2 bytes in cborData, it contains status. @@ -614,7 +783,7 @@ Return JavacardKeymaster4Device::destroyAttestationIds() { std::vector input; ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; - errorCode = sendData(pTransportFactory, Instruction::INS_DESTROY_ATT_IDS_CMD, input, cborOutData); + errorCode = sendData(this, pTransportFactory, Instruction::INS_DESTROY_ATT_IDS_CMD, input, cborOutData); if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { //Skip last 2 bytes in cborData, it contains status. @@ -629,98 +798,192 @@ Return JavacardKeymaster4Device::begin(KeyPurpose purpose, const hidl_vec< hidl_vec outParams; uint64_t operationHandle = 0; - if (KeyPurpose::ENCRYPT == purpose || - KeyPurpose::VERIFY == purpose) { - /* Public key operations are handled here*/ - } else { - cppbor::Array array; - std::vector cborOutData; - std::unique_ptr item; - - /* Convert input data to cbor format */ - array.add(static_cast(purpose)); - array.add(std::vector(keyBlob)); - cborConverter_.addKeyparameters(array, inParams); - cborConverter_.addHardwareAuthToken(array, authToken); - std::vector cborData = array.encode(); - - errorCode = sendData(pTransportFactory, Instruction::INS_BEGIN_OPERATION_CMD, cborData, cborOutData); - - if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { - //Skip last 2 bytes in cborData, it contains status. - std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), - true); - if (item != nullptr) { - cborConverter_.getKeyParameters(item, 1, outParams); - cborConverter_.getUint64(item, 2, operationHandle); - } + if (KeyPurpose::ENCRYPT == purpose || KeyPurpose::VERIFY == purpose) { + BeginOperationRequest request; + request.purpose = legacy_enum_conversion(purpose); + request.SetKeyMaterial(keyBlob.data(), keyBlob.size()); + request.additional_params.Reinitialize(KmParamSet(inParams)); + + BeginOperationResponse response; + softKm_->BeginOperation(request, &response); + + hidl_vec resultParams; + if (response.error == KM_ERROR_OK) { + resultParams = kmParamSet2Hidl(response.output_params); + } + if (response.error != KM_ERROR_INCOMPATIBLE_ALGORITHM) { /*Incompatible algorithm could be handled by JavaCard*/ + _hidl_cb(legacy_enum_conversion(response.error), resultParams, response.op_handle); + return Void(); } } - _hidl_cb(errorCode, outParams, operationHandle); - return Void(); -} -Return JavacardKeymaster4Device::update(uint64_t operationHandle, const hidl_vec& inParams, const hidl_vec& input, const HardwareAuthToken& authToken, const VerificationToken& verificationToken, update_cb _hidl_cb) { cppbor::Array array; - std::unique_ptr item; std::vector cborOutData; - ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; - hidl_vec outParams; - uint32_t inputConsumed = 0; - hidl_vec output; + std::unique_ptr item; /* Convert input data to cbor format */ - array.add(operationHandle); + array.add(static_cast(purpose)); + array.add(std::vector(keyBlob)); cborConverter_.addKeyparameters(array, inParams); - array.add(std::vector(input)); cborConverter_.addHardwareAuthToken(array, authToken); - cborConverter_.addVerificationToken(array, verificationToken); std::vector cborData = array.encode(); - errorCode = sendData(pTransportFactory, Instruction::INS_UPDATE_OPERATION_CMD, cborData, cborOutData); + errorCode = sendData(this, pTransportFactory, Instruction::INS_BEGIN_OPERATION_CMD, cborData, cborOutData); if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { //Skip last 2 bytes in cborData, it contains status. std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), - true); + true); if (item != nullptr) { - cborConverter_.getUint64(item, 1, inputConsumed); - cborConverter_.getKeyParameters(item, 2, outParams); - cborConverter_.getBinaryArray(item, 3, output); + cborConverter_.getKeyParameters(item, 1, outParams); + cborConverter_.getUint64(item, 2, operationHandle); + /* Store the operationInfo */ + oprCtx_->setOperationInfo(operationHandle, purpose, inParams); } } - _hidl_cb(errorCode, inputConsumed, outParams, output); + _hidl_cb(errorCode, outParams, operationHandle); return Void(); } -Return JavacardKeymaster4Device::finish(uint64_t operationHandle, const hidl_vec& inParams, const hidl_vec& input, const hidl_vec& signature, const HardwareAuthToken& authToken, const VerificationToken& verificationToken, finish_cb _hidl_cb) { - cppbor::Array array; - std::unique_ptr item; - std::vector cborOutData; +Return JavacardKeymaster4Device::update(uint64_t operationHandle, const hidl_vec& inParams, const hidl_vec& input, const HardwareAuthToken& authToken, const VerificationToken& verificationToken, update_cb _hidl_cb) { ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + UpdateOperationRequest request; + request.op_handle = operationHandle; + request.input.Reinitialize(input.data(), input.size()); + request.additional_params.Reinitialize(KmParamSet(inParams)); + + UpdateOperationResponse response; + softKm_->UpdateOperation(request, &response); + + uint32_t inputConsumed = 0; hidl_vec outParams; hidl_vec output; + errorCode = legacy_enum_conversion(response.error); + if (response.error == KM_ERROR_OK) { + inputConsumed = response.input_consumed; + outParams = kmParamSet2Hidl(response.output_params); + output = kmBuffer2hidlVec(response.output); + } else if(response.error == KM_ERROR_INVALID_OPERATION_HANDLE) { + std::vector tempOut; + /* OperationContext calls this below sendDataCallback callback function. This callback + * may be called multiple times if the input data is larger than MAX_ALLOWED_INPUT_SIZE. + */ + auto sendDataCallback = [&](std::vector& data, bool) -> ErrorCode { + cppbor::Array array; + std::unique_ptr item; + std::vector cborOutData; + + // Convert input data to cbor format + array.add(operationHandle); + cborConverter_.addKeyparameters(array, inParams); + array.add(data); + cborConverter_.addHardwareAuthToken(array, authToken); + cborConverter_.addVerificationToken(array, verificationToken); + std::vector cborData = array.encode(); + + errorCode = sendData(this, pTransportFactory, Instruction::INS_UPDATE_OPERATION_CMD, cborData, cborOutData); + + if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), + true); + if (item != nullptr) { + /*Ignore inputConsumed from javacard SE since HAL consumes all the input */ + //cborConverter_.getUint64(item, 1, inputConsumed); + if(outParams.size() == 0) + cborConverter_.getKeyParameters(item, 2, outParams); + cborConverter_.getBinaryArray(item, 3, tempOut); + } + } + return errorCode; + }; + if(ErrorCode::OK == (errorCode = oprCtx_->update(operationHandle, std::vector(input), + sendDataCallback))) { + /* Consumed all the input */ + inputConsumed = input.size(); + output = tempOut; + } + } + if(ErrorCode::OK != errorCode) { + /* Delete the entry on this operationHandle */ + oprCtx_->clearOperationData(operationHandle); + } + _hidl_cb(errorCode, inputConsumed, outParams, output); + return Void(); +} - /* Convert input data to cbor format */ - array.add(operationHandle); - cborConverter_.addKeyparameters(array, inParams); - array.add(std::vector(input)); - array.add(std::vector(signature)); - cborConverter_.addHardwareAuthToken(array, authToken); - cborConverter_.addVerificationToken(array, verificationToken); - std::vector cborData = array.encode(); +Return JavacardKeymaster4Device::finish(uint64_t operationHandle, const hidl_vec& inParams, const hidl_vec& input, const hidl_vec& signature, const HardwareAuthToken& authToken, const VerificationToken& verificationToken, finish_cb _hidl_cb) { + ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + FinishOperationRequest request; + request.op_handle = operationHandle; + request.input.Reinitialize(input.data(), input.size()); + request.signature.Reinitialize(signature.data(), signature.size()); + request.additional_params.Reinitialize(KmParamSet(inParams)); - errorCode = sendData(pTransportFactory, Instruction::INS_FINISH_OPERATION_CMD, cborData, cborOutData); + FinishOperationResponse response; + softKm_->FinishOperation(request, &response); - if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { - //Skip last 2 bytes in cborData, it contains status. - std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), - true); - if (item != nullptr) { - cborConverter_.getKeyParameters(item, 1, outParams); - cborConverter_.getBinaryArray(item, 2, output); + hidl_vec outParams; + hidl_vec output; + errorCode = legacy_enum_conversion(response.error); + if (response.error == KM_ERROR_OK) { + outParams = kmParamSet2Hidl(response.output_params); + output = kmBuffer2hidlVec(response.output); + } else if (response.error == KM_ERROR_INVALID_OPERATION_HANDLE) { + std::vector tempOut; + /* OperationContext calls this below sendDataCallback callback function. This callback + * may be called multiple times if the input data is larger than MAX_ALLOWED_INPUT_SIZE. + * This callback function decides whether to call update/finish instruction based on the + * input received from the OperationContext through finish variable. + * if finish variable is false update instruction is called, if it is true finish instruction + * is called. + */ + auto sendDataCallback = [&](std::vector& data, bool finish) -> ErrorCode { + cppbor::Array array; + Instruction ins; + std::unique_ptr item; + std::vector cborOutData; + int keyParamPos, outputPos; + + // Convert input data to cbor format + array.add(operationHandle); + cborConverter_.addKeyparameters(array, inParams); + array.add(data); + if(finish) { + array.add(std::vector(signature)); + ins = Instruction::INS_FINISH_OPERATION_CMD; + keyParamPos = 1; + outputPos = 2; + } else { + ins = Instruction::INS_UPDATE_OPERATION_CMD; + keyParamPos = 2; + outputPos = 3; + } + cborConverter_.addHardwareAuthToken(array, authToken); + cborConverter_.addVerificationToken(array, verificationToken); + std::vector cborData = array.encode(); + + errorCode = sendData(this, pTransportFactory, ins, cborData, cborOutData); + + if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), + true); + if (item != nullptr) { + if(outParams.size() == 0) + cborConverter_.getKeyParameters(item, keyParamPos, outParams); + cborConverter_.getBinaryArray(item, outputPos, tempOut); + } + } + return errorCode; + }; + if(ErrorCode::OK == (errorCode = oprCtx_->finish(operationHandle, std::vector(input), + sendDataCallback))) { + output = tempOut; } } + /* Delete the entry on this operationHandle */ + oprCtx_->clearOperationData(operationHandle); _hidl_cb(errorCode, outParams, output); return Void(); } @@ -735,13 +998,15 @@ Return JavacardKeymaster4Device::abort(uint64_t operationHandle) { array.add(operationHandle); std::vector cborData = array.encode(); - errorCode = sendData(pTransportFactory, Instruction::INS_ABORT_OPERATION_CMD, cborData, cborOutData); + errorCode = sendData(this, pTransportFactory, Instruction::INS_ABORT_OPERATION_CMD, cborData, cborOutData); if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { //Skip last 2 bytes in cborData, it contains status. std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), true); } + /* Delete the entry on this operationHandle */ + oprCtx_->clearOperationData(operationHandle); return errorCode; } @@ -758,7 +1023,7 @@ Return<::android::hardware::keymaster::V4_1::ErrorCode> JavacardKeymaster4Device std::vector cborData = array.encode(); /* TODO DeviceLocked command handled inside HAL */ - ErrorCode ret = sendData(pTransportFactory, Instruction::INS_DEVICE_LOCKED_CMD, cborData, cborOutData); + ErrorCode ret = sendData(this, pTransportFactory, Instruction::INS_DEVICE_LOCKED_CMD, cborData, cborOutData); if((ret == ErrorCode::OK) && (cborOutData.size() > 2)) { //Skip last 2 bytes in cborData, it contains status. @@ -775,7 +1040,7 @@ Return<::android::hardware::keymaster::V4_1::ErrorCode> JavacardKeymaster4Device std::vector cborInput; ::android::hardware::keymaster::V4_1::ErrorCode errorCode = ::android::hardware::keymaster::V4_1::ErrorCode::UNKNOWN_ERROR; - ErrorCode ret = sendData(pTransportFactory, Instruction::INS_EARLY_BOOT_ENDED_CMD, cborInput, cborOutData); + ErrorCode ret = sendData(this, pTransportFactory, Instruction::INS_EARLY_BOOT_ENDED_CMD, cborInput, cborOutData); if((ret == ErrorCode::OK) && (cborOutData.size() > 2)) { //Skip last 2 bytes in cborData, it contains status. diff --git a/HAL/keymaster/4.1/JavacardOperationContext.cpp b/HAL/keymaster/4.1/JavacardOperationContext.cpp new file mode 100644 index 00000000..0e1de44c --- /dev/null +++ b/HAL/keymaster/4.1/JavacardOperationContext.cpp @@ -0,0 +1,286 @@ +/* + ** + ** Copyright 2020, The Android Open Source Project + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +#include + +#define MAX_ALLOWED_INPUT_SIZE 512 +#define AES_BLOCK_SIZE 16 +#define DES_BLOCK_SIZE 8 +#define RSA_INPUT_MSG_LEN 245 /*(256-11)*/ +#define EC_INPUT_MSG_LEN 32 +#define MAX_RSA_BUFFER_SIZE 256 +#define MAX_EC_BUFFER_SIZE 32 + +namespace keymaster { +namespace V4_1 { +namespace javacard { + +enum class Operation { + Update = 0, + Finish = 1 +}; + +inline ErrorCode hidlParamSet2OperatinInfo(const hidl_vec& params, OperationInfo& info) { + for(int i = 0; i < params.size(); i++) { + const KeyParameter ¶m = params[i]; + switch(param.tag) { + case Tag::ALGORITHM: + info.alg = static_cast(param.f.integer); + break; + case Tag::DIGEST: + info.digest = static_cast(param.f.integer); + break; + case Tag::PADDING: + info.pad = static_cast(param.f.integer); + break; + default: + continue; + } + } + return ErrorCode::OK; +} + +ErrorCode OperationContext::setOperationInfo(uint64_t operationHandle, KeyPurpose purpose, const hidl_vec& params) { + ErrorCode errorCode = ErrorCode::OK; + OperationInfo info; + if(ErrorCode::OK != (errorCode = hidlParamSet2OperatinInfo(params, info))) { + return errorCode; + } + info.purpose = purpose; + return setOperationInfo(operationHandle, info); +} + +ErrorCode OperationContext::setOperationInfo(uint64_t operationHandle, OperationInfo& operInfo) { + OperationData data; + data.info = operInfo; + operationTable[operationHandle] = data; + return ErrorCode::OK; +} + +ErrorCode OperationContext::getOperationInfo(uint64_t operHandle, OperationInfo& operInfo) { + auto itr = operationTable.find(operHandle); + if(itr != operationTable.end()) { + operInfo = itr->second.info; + return ErrorCode::OK; + } + return ErrorCode::INVALID_OPERATION_HANDLE; +} + +ErrorCode OperationContext::clearOperationData(uint64_t operHandle) { + size_t size = operationTable.erase(operHandle); + if(!size) + return ErrorCode::INVALID_OPERATION_HANDLE; + else + return ErrorCode::OK; +} + +ErrorCode OperationContext::validateInputData(uint64_t operHandle, Operation opr, const std::vector& actualInput, std::vector& input) { + ErrorCode errorCode = ErrorCode::OK; + OperationData oprData; + + if(ErrorCode::OK != (errorCode = getOperationData(operHandle, oprData))) { + return errorCode; + } + + if(KeyPurpose::SIGN == oprData.info.purpose) { + if(Algorithm::RSA == oprData.info.alg && Digest::NONE == oprData.info.digest) { + if((oprData.data.buf_len+actualInput.size()) > RSA_INPUT_MSG_LEN) + return ErrorCode::INVALID_INPUT_LENGTH; + } else if(Algorithm::EC == oprData.info.alg && Digest::NONE == oprData.info.digest) { + /* Silently truncate the input */ + if(oprData.data.buf_len >= EC_INPUT_MSG_LEN) { + return ErrorCode::OK; + } else if(actualInput.size()+oprData.data.buf_len > EC_INPUT_MSG_LEN) { + for(int i=oprData.data.buf_len,j=0; i < EC_INPUT_MSG_LEN; ++i,++j) { + input.push_back(actualInput[j]); + } + return ErrorCode::OK; + } + } + } + + if(KeyPurpose::DECRYPT == oprData.info.purpose && Algorithm::RSA == oprData.info.alg) { + if((oprData.data.buf_len+actualInput.size()) > MAX_RSA_BUFFER_SIZE) { + return ErrorCode::INVALID_INPUT_LENGTH; + } + } + + if(opr == Operation::Finish) { + + if(oprData.info.pad == PaddingMode::NONE && oprData.info.alg == Algorithm::AES) { + if(((oprData.data.buf_len+actualInput.size()) % AES_BLOCK_SIZE) != 0) + return ErrorCode::INVALID_INPUT_LENGTH; + } + if(oprData.info.pad == PaddingMode::NONE && oprData.info.alg == Algorithm::TRIPLE_DES) { + if(((oprData.data.buf_len+actualInput.size()) % DES_BLOCK_SIZE) != 0) + return ErrorCode::INVALID_INPUT_LENGTH; + } + } + input = actualInput; + return errorCode; +} + +ErrorCode OperationContext::update(uint64_t operHandle, const std::vector& actualInput, sendDataToSE_cb cb) { + ErrorCode errorCode = ErrorCode::OK; + std::vector input; + + /* Validate the input data */ + if(ErrorCode::OK != (errorCode = validateInputData(operHandle, Operation::Update, actualInput, input))) { + return errorCode; + } + + if (input.size() > MAX_ALLOWED_INPUT_SIZE) { + int noOfChunks = input.size()/MAX_ALLOWED_INPUT_SIZE; + int extraData = input.size()%MAX_ALLOWED_INPUT_SIZE; + for(int i =0 ; i < noOfChunks; i++) { + auto first = input.cbegin() + (i*MAX_ALLOWED_INPUT_SIZE); + auto end = first + MAX_ALLOWED_INPUT_SIZE; + std::vector newInput(first, end); + if(ErrorCode::OK != (errorCode = handleInternalUpdate(operHandle, newInput.data(), newInput.size(), + Operation::Update, cb))) { + return errorCode; + } + } + if(extraData > 0) { + std::vector finalInput(input.cend()-extraData, input.cend()); + if(ErrorCode::OK != (errorCode = handleInternalUpdate(operHandle, finalInput.data(), finalInput.size(), + Operation::Update, cb))) { + return errorCode; + } + } + } else { + if(ErrorCode::OK != (errorCode = handleInternalUpdate(operHandle, input.data(), input.size(), + Operation::Update, cb))) { + return errorCode; + } + } + return errorCode; +} + +ErrorCode OperationContext::finish(uint64_t operHandle, const std::vector& actualInput, sendDataToSE_cb cb) { + ErrorCode errorCode = ErrorCode::OK; + std::vector input; + + /* Validate the input data */ + if(ErrorCode::OK != (errorCode = validateInputData(operHandle, Operation::Update, actualInput, input))) { + return errorCode; + } + + if (input.size() > MAX_ALLOWED_INPUT_SIZE) { + int noOfChunks = input.size()/MAX_ALLOWED_INPUT_SIZE; + int extraData = input.size()%MAX_ALLOWED_INPUT_SIZE; + for(int i =0 ; i < noOfChunks; i++) { + auto first = input.cbegin() + (i*MAX_ALLOWED_INPUT_SIZE); + auto end = first + MAX_ALLOWED_INPUT_SIZE; + std::vector newInput(first, end); + if(ErrorCode::OK != (errorCode = handleInternalUpdate(operHandle, newInput.data(), newInput.size(), + Operation::Finish, cb))) { + return errorCode; + } + } + if(extraData > 0) { + std::vector finalInput(input.cend()-extraData, input.cend()); + if(ErrorCode::OK != (errorCode = handleInternalUpdate(operHandle, finalInput.data(), finalInput.size(), + Operation::Finish, cb))) { + return errorCode; + } + } + } else { + if(ErrorCode::OK != (errorCode = handleInternalUpdate(operHandle, input.data(), input.size(), + Operation::Finish, cb))) { + return errorCode; + } + } + + /* Send if any buffered data is remaining or to call finish */ + if(ErrorCode::OK != (errorCode = handleInternalUpdate(operHandle, nullptr, 0, + Operation::Finish, cb, true))) { + return errorCode; + } + return errorCode; +} + +ErrorCode OperationContext::internalUpdate(uint64_t operHandle, uint8_t* input, size_t input_len, Operation opr, std::vector& out) { + int dataToSELen=0; + /*Length of the data consumed from input */ + int inputConsumed=0; + bool dataSendToSE = true; + int blockSize = 0; + BufferedData data = operationTable[operHandle].data; + int bufIndex = data.buf_len; + + if(Algorithm::AES == operationTable[operHandle].info.alg) { + blockSize = AES_BLOCK_SIZE; + } else if(Algorithm::TRIPLE_DES == operationTable[operHandle].info.alg) { + blockSize = DES_BLOCK_SIZE; + } + + if(data.buf_len > 0) { + if(opr == Operation::Finish) { + //Copy the buffer to be send to SE. + for(int i = 0; i < data.buf_len; i++) + { + out.push_back(data.buf[i]); + } + dataToSELen = data.buf_len + input_len; + } else { + if (data.buf_len + input_len >= blockSize) { + dataToSELen = data.buf_len + input_len; + //Copy the buffer to be send to SE. + for(int i = 0; i < data.buf_len; i++) + { + out.push_back(data.buf[i]); + } + } else { + dataSendToSE = false; + } + } + } else { + dataToSELen = input_len; + } + + if(dataSendToSE) { + if(opr == Operation::Update) { + dataToSELen = (dataToSELen/blockSize) * blockSize; + } + inputConsumed = dataToSELen - data.buf_len; + + //Copy the buffer to be send to SE. + for(int i = 0; i < inputConsumed; i++) + { + out.push_back(input[i]); + } + + /* All the data is consumed so clear buffer */ + if(data.buf_len != 0) { + memset(data.buf, 0x00, sizeof(data.buf)); + bufIndex = data.buf_len = 0; + } + } + + //Store the remaining buffer for later use. + data.buf_len += (input_len - inputConsumed); + for(int i = 0; i < (input_len - inputConsumed); i++) + { + data.buf[bufIndex+i] = input[inputConsumed+i]; + } + return ErrorCode::OK; +} + +} // namespace javacard +} // namespace V4_1 +} // namespace keymaster diff --git a/HAL/keymaster/4.1/java_card_soft_keymaster_context.cpp b/HAL/keymaster/4.1/java_card_soft_keymaster_context.cpp new file mode 100644 index 00000000..76731d5d --- /dev/null +++ b/HAL/keymaster/4.1/java_card_soft_keymaster_context.cpp @@ -0,0 +1,334 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +using std::unique_ptr; + +namespace keymaster { + +JavaCardSoftKeymasterContext::JavaCardSoftKeymasterContext(keymaster_security_level_t security_level) + : PureSoftKeymasterContext(security_level) {} + +JavaCardSoftKeymasterContext::~JavaCardSoftKeymasterContext() {} + +keymaster_error_t JavaCardSoftKeymasterContext::CreateKeyBlob(const AuthorizationSet& key_description, + const keymaster_key_origin_t origin, + const KeymasterKeyBlob& key_material, + KeymasterKeyBlob* blob, + AuthorizationSet* hw_enforced, + AuthorizationSet* sw_enforced) const { + if (key_description.GetTagValue(TAG_ROLLBACK_RESISTANCE)) { + return KM_ERROR_ROLLBACK_RESISTANCE_UNAVAILABLE; + } + + keymaster_error_t error = SetKeyBlobAuthorizations(key_description, origin, os_version_, + os_patchlevel_, hw_enforced, sw_enforced); + if (error != KM_ERROR_OK) return error; + + AuthorizationSet hidden; + error = BuildHiddenAuthorizations(key_description, &hidden, softwareRootOfTrust); + if (error != KM_ERROR_OK) return error; + + size_t size = key_material.SerializedSize(); + + if (!blob->Reset(size)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + + uint8_t* p = blob->writable_data(); + p = key_material.Serialize(p, blob->end()); + + return KM_ERROR_OK; +} + +inline keymaster_tag_t legacy_enum_conversion(const Tag value) { + return keymaster_tag_t(value); +} + +inline Tag legacy_enum_conversion(const keymaster_tag_t value) { + return Tag(value); +} + +inline keymaster_tag_type_t typeFromTag(const keymaster_tag_t tag) { + return keymaster_tag_get_type(tag); +} + +keymaster_key_param_set_t hidlKeyParams2Km(const hidl_vec& keyParams) { + keymaster_key_param_set_t set; + + set.params = new keymaster_key_param_t[keyParams.size()]; + set.length = keyParams.size(); + + for (size_t i = 0; i < keyParams.size(); ++i) { + auto tag = legacy_enum_conversion(keyParams[i].tag); + switch (typeFromTag(tag)) { + case KM_ENUM: + case KM_ENUM_REP: + set.params[i] = keymaster_param_enum(tag, keyParams[i].f.integer); + break; + case KM_UINT: + case KM_UINT_REP: + set.params[i] = keymaster_param_int(tag, keyParams[i].f.integer); + break; + case KM_ULONG: + case KM_ULONG_REP: + set.params[i] = keymaster_param_long(tag, keyParams[i].f.longInteger); + break; + case KM_DATE: + set.params[i] = keymaster_param_date(tag, keyParams[i].f.dateTime); + break; + case KM_BOOL: + if (keyParams[i].f.boolValue) + set.params[i] = keymaster_param_bool(tag); + else + set.params[i].tag = KM_TAG_INVALID; + break; + case KM_BIGNUM: + case KM_BYTES: + set.params[i] = + keymaster_param_blob(tag, &keyParams[i].blob[0], keyParams[i].blob.size()); + break; + case KM_INVALID: + default: + set.params[i].tag = KM_TAG_INVALID; + /* just skip */ + break; + } + } + + return set; +} + +class KmParamSet : public keymaster_key_param_set_t { + public: + explicit KmParamSet(const hidl_vec& keyParams) + : keymaster_key_param_set_t(hidlKeyParams2Km(keyParams)) {} + KmParamSet(KmParamSet&& other) : keymaster_key_param_set_t{other.params, other.length} { + other.length = 0; + other.params = nullptr; + } + KmParamSet(const KmParamSet&) = delete; + ~KmParamSet() { delete[] params; } +}; + +EVP_PKEY* RSA_fromMaterial(const uint8_t* modulus, size_t mod_size) { + BIGNUM *n = BN_bin2bn(modulus, mod_size, NULL); + BIGNUM *e = BN_new();//bignum_decode(exp, 5); + char exp[] = "65537"; + BN_dec2bn(&e, exp); + + if (!n || !e) + return NULL; + + if (e && n) { + EVP_PKEY* pRsaKey = EVP_PKEY_new(); + RSA* rsa = RSA_new(); + rsa->e = e; + rsa->n = n; + EVP_PKEY_assign_RSA(pRsaKey, rsa); + return pRsaKey; + } else { + if (n) BN_free(n); + if (e) BN_free(e); + return NULL; + } +} + +EC_GROUP* ChooseGroup(keymaster_ec_curve_t ec_curve) { + switch (ec_curve) { + case KM_EC_CURVE_P_224: + return EC_GROUP_new_by_curve_name(NID_secp224r1); + break; + case KM_EC_CURVE_P_256: + return EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); + break; + case KM_EC_CURVE_P_384: + return EC_GROUP_new_by_curve_name(NID_secp384r1); + break; + case KM_EC_CURVE_P_521: + return EC_GROUP_new_by_curve_name(NID_secp521r1); + break; + default: + return nullptr; + break; + } +} + +EVP_PKEY* EC_fromMaterial(const uint8_t* pub_key, size_t key_size, keymaster_ec_curve_t ec_curve) { + + EC_GROUP *ec_group = ChooseGroup(ec_curve); + EC_POINT *p = EC_POINT_new(ec_group); + EC_KEY *ec_key = EC_KEY_new(); + EVP_PKEY *pEcKey = EVP_PKEY_new(); + + if((EC_KEY_set_group(ec_key, ec_group) != 1) || (EC_POINT_oct2point(ec_group, p, pub_key, key_size, NULL) != 1) + || (EC_KEY_set_public_key(ec_key, p) != 1) || (EVP_PKEY_set1_EC_KEY(pEcKey, ec_key) != 1)) { + return NULL; + } + + return pEcKey; +} + +keymaster_error_t JavaCardSoftKeymasterContext::LoadKey(const keymaster_algorithm_t algorithm, KeymasterKeyBlob&& key_material, + AuthorizationSet&& hw_enforced, + AuthorizationSet&& sw_enforced, + UniquePtr* key) const { + auto factory = (AsymmetricKeyFactory*)GetKeyFactory(algorithm); + UniquePtr asym_key; + keymaster_error_t error = KM_ERROR_OK; + const uint8_t* tmp = key_material.key_material; + const size_t temp_size = key_material.key_material_size; + EVP_PKEY* pkey = NULL; + + if(algorithm == KM_ALGORITHM_RSA) { + pkey = RSA_fromMaterial(tmp, temp_size); + } else if(algorithm == KM_ALGORITHM_EC) { + keymaster_ec_curve_t ec_curve = KM_EC_CURVE_P_256; + if (!hw_enforced.GetTagValue(TAG_EC_CURVE, &ec_curve) && + !sw_enforced.GetTagValue(TAG_EC_CURVE, &ec_curve)) { + return KM_ERROR_INVALID_ARGUMENT; + }//TODO also get ec_curve based on key size + pkey = EC_fromMaterial(tmp, temp_size, ec_curve); + } + if (!pkey) + return TranslateLastOpenSslError(); + UniquePtr pkey_deleter(pkey); + + error = factory->CreateEmptyKey(move(hw_enforced), move(sw_enforced), &asym_key); + if (error != KM_ERROR_OK) + return error; + + asym_key->key_material() = move(key_material); + if (!asym_key->EvpToInternal(pkey)) + error = TranslateLastOpenSslError(); + else + key->reset(asym_key.release()); + + return error; +} + +keymaster_error_t JavaCardSoftKeymasterContext::ParseKeyBlob(const KeymasterKeyBlob& blob, + const AuthorizationSet& /*additional_params*/, + UniquePtr* key) const { + + // The JavaCardSoftKeymasterContext handle a key blob generated by JavaCard keymaster for public key operations. + // + // 1. A JavaCard keymaster key blob is a CborEncoded data of Secret, Nonce, AuthTag, KeyCharectristics and Public key. + // Here in public key operation we need only KeyCharectristics and Public key. + // Once these values extracted Public key is created based on parameters and returned. + // + + AuthorizationSet hw_enforced; + AuthorizationSet sw_enforced; + KeymasterKeyBlob key_material; + keymaster_error_t error; + + auto constructKey = [&, this] () mutable -> keymaster_error_t { + keymaster_algorithm_t algorithm; + if (!hw_enforced.GetTagValue(TAG_ALGORITHM, &algorithm) && + !sw_enforced.GetTagValue(TAG_ALGORITHM, &algorithm)) { + return KM_ERROR_INVALID_ARGUMENT; + } + + if (algorithm != KM_ALGORITHM_RSA && algorithm != KM_ALGORITHM_EC) { + return KM_ERROR_INCOMPATIBLE_ALGORITHM; + } + error = LoadKey(algorithm, move(key_material), move(hw_enforced), + move(sw_enforced), key); + return error; + }; + + CborConverter cc; + std::unique_ptr item; + ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + std::vector cborKey(blob.key_material_size); +// std::vector cborKey(187); + + for(size_t i = 0; i < blob.key_material_size; i++) { + cborKey[i] = blob.key_material[i]; + } +/*uint8_t tempBlob[] = {0x85, 0x58, 0x20, 0xDA, 0x29, 0xC7, 0x1A, 0x8C, 0xE7, 0x6A, 0x0D, 0xFD, +0x2E, 0x53, 0x06, 0x81, 0x85, 0x37, 0x2D, 0x9E, 0x74, 0xE7, 0xF1, 0xD5, +0x3F, 0x0E, 0xAB, 0x1A, 0xF8, 0xE9, 0x46, 0xFD, 0xDC, 0x37, 0x54, 0x4C, +0xE9, 0xA7, 0xD0, 0x71, 0x96, 0xCC, 0x66, 0x18, 0xF0, 0x53, 0xD1, 0x30, +0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x82, 0xA1, 0x1A, 0x30, 0x00, 0x01, 0xF5, 0x1A, 0x01, 0x02, 0x03, +0x04, 0xA6, 0x1A, 0x10, 0x00, 0x00, 0x02, 0x03, 0x1A, 0x50, 0x00, 0x00, +0xC8, 0x1A, 0x00, 0x01, 0x00, 0x01, 0x1A, 0x30, 0x00, 0x00, 0x03, 0x19, +0x01, 0x00, 0x1A, 0x10, 0x00, 0x02, 0xBE, 0x00, 0x1A, 0x30, 0x00, 0x02, +0xC1, 0x00, 0x1A, 0x30, 0x00, 0x02, 0xC2, 0x1A, 0x00, 0x03, 0x15, 0x14, +0x58, 0x41, 0x04, 0x2B, 0xF1, 0x84, 0xD4, 0xFB, 0x63, 0x44, 0x20, 0xD0, +0xA3, 0x7D, 0x6A, 0xC1, 0xC5, 0x26, 0x12, 0xCD, 0x79, 0x77, 0x81, 0x22, +0x33, 0x30, 0x70, 0xF7, 0x25, 0x6D, 0x75, 0xE0, 0xD4, 0xD0, 0x50, 0xD6, +0x80, 0x65, 0x2A, 0x44, 0x0B, 0x8E, 0xFC, 0xA0, 0x8B, 0xC5, 0xF4, 0x8A, +0xCA, 0x4B, 0x89, 0x6E, 0x8B, 0xFC, 0x38, 0xB7, 0xC9, 0xB9, 0xB6, 0xE7, +0x57, 0xE6, 0x53, 0xE9, 0xBF, 0x94, 0x3A}; + for(size_t i = 0; i < 187; i++) { + cborKey[i] = tempBlob[i]; + } +*/ + std::tie(item, errorCode) = cc.decodeData(cborKey, false); + if (item != nullptr) { + std::vector temp; + cc.getBinaryArray(item, 4, temp); + + key_material = {temp.data(), temp.size()}; + temp.clear(); + KeyCharacteristics keyCharacteristics; + cc.getKeyCharacteristics(item, 3, keyCharacteristics); + + sw_enforced.Reinitialize(KmParamSet(keyCharacteristics.softwareEnforced)); + hw_enforced.Reinitialize(KmParamSet(keyCharacteristics.hardwareEnforced)); + } + return constructKey(); +} +} // namespace keymaster diff --git a/HAL/keymaster/Android.bp b/HAL/keymaster/Android.bp index 10bfe5d2..33136850 100644 --- a/HAL/keymaster/Android.bp +++ b/HAL/keymaster/Android.bp @@ -18,6 +18,8 @@ cc_library { srcs: [ "4.1/JavacardKeymaster4Device.cpp", "4.1/CborConverter.cpp", + "4.1/java_card_soft_keymaster_context.cpp", + "4.1/JavacardOperationContext.cpp", ], local_include_dirs: [ "include", diff --git a/HAL/keymaster/include/JavacardKeymaster4Device.h b/HAL/keymaster/include/JavacardKeymaster4Device.h index 058812e9..95299956 100644 --- a/HAL/keymaster/include/JavacardKeymaster4Device.h +++ b/HAL/keymaster/include/JavacardKeymaster4Device.h @@ -27,6 +27,7 @@ #include #include #include +#include namespace keymaster { namespace V4_1 { @@ -84,12 +85,18 @@ class JavacardKeymaster4Device : public IKeymasterDevice { Return deviceLocked(bool passwordOnly, const VerificationToken& verificationToken) override; Return earlyBootEnded() override; + //Helper methods. + bool getBootParamsInitialized() { return setUpBootParams; } + void setBootParams(bool flag) { setUpBootParams = flag; } + protected: CborConverter cborConverter_; std::unique_ptr pTransportFactory; private: std::unique_ptr<::keymaster::AndroidKeymaster> softKm_; + std::unique_ptr oprCtx_; + bool setUpBootParams; }; } // namespace javacard diff --git a/HAL/keymaster/include/JavacardOperationContext.h b/HAL/keymaster/include/JavacardOperationContext.h new file mode 100644 index 00000000..f5e78a9c --- /dev/null +++ b/HAL/keymaster/include/JavacardOperationContext.h @@ -0,0 +1,153 @@ +/* + ** + ** Copyright 2020, The Android Open Source Project + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +#ifndef KEYMASTER_V4_1_JAVACARD_OPERATIONCONTEXT_H_ +#define KEYMASTER_V4_1_JAVACARD_OPERATIONCONTEXT_H_ + +#include +#include + +#define MAX_BUF_SIZE 256 + +namespace keymaster { +namespace V4_1 { +namespace javacard { + +using ::android::hardware::hidl_vec; +using ::android::hardware::keymaster::V4_0::ErrorCode; +using ::android::hardware::keymaster::V4_0::Algorithm; +using ::android::hardware::keymaster::V4_0::KeyPurpose; +using ::android::hardware::keymaster::V4_0::Digest; +using ::android::hardware::keymaster::V4_0::PaddingMode; +using ::android::hardware::keymaster::V4_0::KeyParameter; +using ::android::hardware::keymaster::V4_0::Tag; + +using sendDataToSE_cb = std::function& data, bool finish)>; + +enum class Operation; + +struct BufferedData { + uint8_t buf[MAX_BUF_SIZE]; + int buf_len; +}; + +struct OperationInfo { + Algorithm alg; + KeyPurpose purpose; + Digest digest; + PaddingMode pad; +}; + +struct OperationData { + OperationInfo info; + BufferedData data; +}; + +class OperationContext { + +public: + OperationContext(){} + ~OperationContext() {} + ErrorCode setOperationInfo(uint64_t operationHandle, OperationInfo& oeprInfo); + ErrorCode setOperationInfo(uint64_t operationHandle, KeyPurpose purpose, const hidl_vec& params); + ErrorCode getOperationInfo(uint64_t operHandle, OperationInfo& operInfo); + ErrorCode clearOperationData(uint64_t operationHandle); + ErrorCode update(uint64_t operHandle, const std::vector& input, sendDataToSE_cb cb); + ErrorCode finish(uint64_t operHandle, const std::vector& input, sendDataToSE_cb cb); + +private: + std::map operationTable; + + inline ErrorCode getOperationData(uint64_t operHandle, OperationData& oprData) { + auto itr = operationTable.find(operHandle); + if(itr != operationTable.end()) { + oprData = itr->second; + return ErrorCode::OK; + } + return ErrorCode::INVALID_OPERATION_HANDLE; + } + + ErrorCode validateInputData(uint64_t operHandle, Operation opr, const std::vector& actualInput, + std::vector& input); + ErrorCode internalUpdate(uint64_t operHandle, uint8_t* input, size_t input_len, Operation opr, std::vector& + out); + ErrorCode handleInternalUpdate(uint64_t operHandle, uint8_t* data, size_t len, Operation opr, + sendDataToSE_cb cb, bool finish=false) { + ErrorCode errorCode = ErrorCode::OK; + std::vector out; + OperationData oprData; + + if(ErrorCode::OK != (errorCode = getOperationData(operHandle, oprData))) { + return errorCode; + } + + if(Algorithm::AES == oprData.info.alg || Algorithm::TRIPLE_DES == oprData.info.alg) { + if(ErrorCode::OK != (errorCode = internalUpdate(operHandle, data, len, + opr, out))) { + return errorCode; + } + + if(ErrorCode::OK != (errorCode = cb(out, finish))) { + return errorCode; + } + } else { + if(oprData.info.digest == Digest::NONE) { + if(finish) { + for(int i = 0; i < oprData.data.buf_len; ++i) { + out[i] = oprData.data.buf[i]; + } + if(ErrorCode::OK != (errorCode = cb(out, finish))) { + return errorCode; + } + } else { + /* For RSA/EC algorithms just do buffering, don't send data to SE in update. + * input message length should not be more than the MAX_BUF_SIZE. + */ + if(oprData.data.buf_len <= MAX_BUF_SIZE) { + size_t bufIndex = oprData.data.buf_len; + size_t pos = 0; + for(; (pos < len) && (pos < (MAX_BUF_SIZE-bufIndex)); pos++) + { + oprData.data.buf[bufIndex+pos] = data[pos]; + } + oprData.data.buf_len += pos; + } + } + } else { + for(size_t j=0; j < len; ++j) + { + out[j] = data[j]; + } + /* if len=0, then no need to call the callback, since there is no information to be send to javacard, + * but if finish flag is true irrespective of len callback should be called. + */ + if(len != 0 || finish) { + if(ErrorCode::OK != (errorCode = cb(out, finish))) { + return errorCode; + } + } + } + } + return errorCode; + } +}; + +} // namespace javacard +} // namespace V4_1 +} // namespace keymaster + +#endif // KEYMASTER_V4_1_JAVACARD_OPERATIONCONTEXT_H_ diff --git a/HAL/keymaster/include/java_card_soft_keymaster_context.h b/HAL/keymaster/include/java_card_soft_keymaster_context.h new file mode 100644 index 00000000..07be5c9e --- /dev/null +++ b/HAL/keymaster/include/java_card_soft_keymaster_context.h @@ -0,0 +1,68 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SYSTEM_KEYMASTER_JAVA_CARD_SOFT_KEYMASTER_CONTEXT_H_ +#define SYSTEM_KEYMASTER_JAVA_CARD_SOFT_KEYMASTER_CONTEXT_H_ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace keymaster { + +class SoftKeymasterKeyRegistrations; +class Keymaster0Engine; +class Keymaster1Engine; +class Key; + +/** + * SoftKeymasterContext provides the context for a non-secure implementation of AndroidKeymaster. + */ +class JavaCardSoftKeymasterContext : public keymaster::PureSoftKeymasterContext { + keymaster_error_t LoadKey(const keymaster_algorithm_t algorithm, KeymasterKeyBlob&& key_material, + AuthorizationSet&& hw_enforced, + AuthorizationSet&& sw_enforced, + UniquePtr* key) const; + public: + // Security level must only be used for testing. + explicit JavaCardSoftKeymasterContext( + keymaster_security_level_t security_level = KM_SECURITY_LEVEL_SOFTWARE); + ~JavaCardSoftKeymasterContext() override; + + keymaster_error_t ParseKeyBlob(const KeymasterKeyBlob& blob, + const AuthorizationSet& additional_params, + UniquePtr* key) const override; + /********************************************************************************************* + * Implement SoftwareKeyBlobMaker + */ + keymaster_error_t CreateKeyBlob(const AuthorizationSet& auths, keymaster_key_origin_t origin, + const KeymasterKeyBlob& key_material, KeymasterKeyBlob* blob, + AuthorizationSet* hw_enforced, + AuthorizationSet* sw_enforced) const override; + +}; + +} // namespace keymaster + +#endif // SYSTEM_KEYMASTER_PURE_SOFT_KEYMASTER_CONTEXT_H_