diff --git a/HAL/keymaster/4.1/CborConverter.cpp b/HAL/keymaster/4.1/CborConverter.cpp index 1d22b6e8..ce594c30 100644 --- a/HAL/keymaster/4.1/CborConverter.cpp +++ b/HAL/keymaster/4.1/CborConverter.cpp @@ -258,6 +258,19 @@ ::android::hardware::hidl_vec& value) { return ret; } +bool CborConverter::getBinaryArray(const std::unique_ptr& item, const uint32_t pos, +::android::hardware::hidl_string& value) { + std::vector vec; + std::string str; + if(!getBinaryArray(item, pos, vec)) { + return false; + } + for(auto ch : vec) { + str += ch; + } + value = str; + return true; +} bool CborConverter::getBinaryArray(const std::unique_ptr& item, const uint32_t pos, std::vector& value) { bool ret = false; diff --git a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp index 7e04681a..861dcfda 100644 --- a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp +++ b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp @@ -16,6 +16,7 @@ */ #include +#include #include #include #include @@ -28,9 +29,16 @@ #include #include -#include +#include #include #include +#include +#include +#include +#include + +#define JAVACARD_KEYMASTER_NAME "JavacardKeymaster4.1Device v0.1" +#define JAVACARD_KEYMASTER_AUTHOR "Android Open Source Project" #define APDU_CLS 0x80 #define APDU_P1 0x40 @@ -46,7 +54,7 @@ namespace V4_1 { namespace javacard { static std::unique_ptr pTransportFactory = nullptr; -constexpr size_t kOperationTableSize = 16; +constexpr size_t kOperationTableSize = 4; struct KM_AUTH_LIST_Delete { void operator()(KM_AUTH_LIST* p) { KM_AUTH_LIST_free(p); } @@ -87,7 +95,128 @@ static inline std::unique_ptr& getTransportFacto return pTransportFactory; } -ErrorCode encodeParametersVerified(const VerificationToken& verificationToken, std::vector asn1ParamsVerified) { +static inline bool readDataFromFile(const char *filename, std::vector& data) { + FILE *fp; + bool ret = true; + fp = fopen(filename, "rb"); + if(fp == NULL) { + LOG(ERROR) << "Failed to open file: " << filename; + return false; + } + fseek(fp, 0L, SEEK_END); + long int filesize = ftell(fp); + rewind(fp); + std::unique_ptr buf(new uint8_t[filesize]); + if( 0 == fread(buf.get(), filesize, 1, fp)) { + LOG(ERROR) << "No Content in the file: " << filename; + ret = false; + } + if(true == ret) { + data.insert(data.begin(), buf.get(), buf.get() + filesize); + } + fclose(fp); + return ret; +} + +static inline bool findTag(const hidl_vec& params, Tag tag) { + size_t size = params.size(); + for(size_t i = 0; i < size; ++i) { + if(tag == params[i].tag) + return true; + } + return false; +} + +static inline bool getTag(const hidl_vec& params, Tag tag, KeyParameter& param) { + size_t size = params.size(); + for(size_t i = 0; i < size; ++i) { + if(tag == params[i].tag) { + param = params[i]; + return true; + } + } + return false; +} + +static inline X509* parseDerCertificate(const char* filename) { + X509 *x509 = NULL; + std::vector certData; + + /* Read the Root certificate */ + if(!readDataFromFile(filename, certData)) { + LOG(ERROR) << " Failed to read the Root certificate"; + return NULL; + } + /* Create BIO instance from certificate data */ + BIO *bio = BIO_new_mem_buf(certData.data(), certData.size()); + if(bio == NULL) { + LOG(ERROR) << " Failed to create BIO from buffer."; + return NULL; + } + /* Create X509 instance from BIO */ + x509 = d2i_X509_bio(bio, NULL); + if(x509 == NULL) { + LOG(ERROR) << " Failed to get X509 instance from BIO."; + return NULL; + } + BIO_free(bio); + return x509; +} + +static inline void getDerSubjectName(X509* x509, std::vector& subject) { + uint8_t *subjectDer = NULL; + X509_NAME* asn1Subject = X509_get_subject_name(x509); + if(asn1Subject == NULL) { + LOG(ERROR) << " Failed to read the subject."; + return; + } + /* Convert X509_NAME to der encoded subject */ + int len = i2d_X509_NAME(asn1Subject, &subjectDer); + if (len < 0) { + LOG(ERROR) << " Failed to get readable name from X509_NAME."; + return; + } + subject.insert(subject.begin(), subjectDer, subjectDer+len); +} + +static inline void getAuthorityKeyIdentifier(X509* x509, std::vector& authKeyId) { + long xlen; + int tag, xclass; + + int loc = X509_get_ext_by_NID(x509, NID_authority_key_identifier, -1); + X509_EXTENSION *ext = X509_get_ext(x509, loc); + if(ext == NULL) { + LOG(ERROR) << " Failed to read authority key identifier."; + return; + } + + ASN1_OCTET_STRING *asn1AuthKeyId = X509_EXTENSION_get_data(ext); + const uint8_t *strAuthKeyId = ASN1_STRING_get0_data(asn1AuthKeyId); + int strAuthKeyIdLen = ASN1_STRING_length(asn1AuthKeyId); + int ret = ASN1_get_object(&strAuthKeyId, &xlen, &tag, &xclass, strAuthKeyIdLen); + if (ret == 0x80 || strAuthKeyId == NULL) { + LOG(ERROR) << "Failed to get the auth key identifier from ASN1 sequence."; + return; + } + authKeyId.insert(authKeyId.begin(), strAuthKeyId, strAuthKeyId + xlen); +} + +static inline void getNotAfter(X509* x509, std::vector& notAfterDate) { + const ASN1_TIME* notAfter = X509_get0_notAfter(x509); + if(notAfter == NULL) { + LOG(ERROR) << " Failed to read expiry time."; + return; + } + int strNotAfterLen = ASN1_STRING_length(notAfter); + const uint8_t *strNotAfter = ASN1_STRING_get0_data(notAfter); + if(strNotAfter == NULL) { + LOG(ERROR) << " Failed to read expiry time from ASN1 string."; + return; + } + notAfterDate.insert(notAfterDate.begin(), strNotAfter, strNotAfter + strNotAfterLen); +} + +ErrorCode encodeParametersVerified(const VerificationToken& verificationToken, std::vector& asn1ParamsVerified) { if (verificationToken.parametersVerified.size() > 0) { AuthorizationSet paramSet; KeymasterBlob derBlob; @@ -119,7 +248,7 @@ ErrorCode encodeParametersVerified(const VerificationToken& verificationToken, s return ErrorCode::OK; } -ErrorCode prepareCborArrayFromRawKey(const hidl_vec& keyParams, KeyFormat keyFormat, const hidl_vec& blob, cppbor::Array& +ErrorCode prepareCborArrayFromKeyData(const hidl_vec& keyParams, KeyFormat keyFormat, const hidl_vec& blob, cppbor::Array& array) { ErrorCode errorCode = ErrorCode::OK; AuthorizationSet paramSet; @@ -223,29 +352,6 @@ uint16_t getStatus(std::vector& inputData) { return (inputData.at(inputData.size()-2) << 8) | (inputData.at(inputData.size()-1)); } -bool readDataFromFile(const char *filename, std::vector& data) { - FILE *fp; - bool ret = true; - fp = fopen(filename, "rb"); - if(fp == NULL) { - LOG(ERROR) << "Failed to open file: " << filename; - return false; - } - fseek(fp, 0L, SEEK_END); - long int filesize = ftell(fp); - rewind(fp); - std::unique_ptr buf(new uint8_t[filesize]); - if( 0 == fread(buf.get(), filesize, 1, fp)) { - LOG(ERROR) << "No Content in the file: " << filename; - ret = false; - } - if(true == ret) { - data.insert(data.begin(), buf.get(), buf.get() + filesize); - } - fclose(fp); - return ret; -} - ErrorCode initiateProvision() { /* This is just a reference implemenation */ std::string brand("Google"); @@ -329,16 +435,38 @@ keyData) { Instruction ins = Instruction::INS_PROVISION_CMD; std::vector response; CborConverter cborConverter; + X509 *x509 = NULL; + std::vector subject; + std::vector authorityKeyIdentifier; + std::vector notAfter; + + /* Subject, AuthorityKeyIdentifier and Expirty time of the root certificate are required by javacard. */ + /* Get X509 certificate instance for the root certificate.*/ + if(NULL == (x509 = parseDerCertificate(ROOT_RSA_CERT))) { + return errorCode; + } - if(ErrorCode::OK != (errorCode = prepareCborArrayFromRawKey(keyParams, keyFormat, keyData, subArray))) { + if(ErrorCode::OK != (errorCode = prepareCborArrayFromKeyData(keyParams, keyFormat, keyData, subArray))) { return errorCode; } + /* Get subject in DER */ + getDerSubjectName(x509, subject); + /* Get AuthorityKeyIdentifier */ + getAuthorityKeyIdentifier(x509, authorityKeyIdentifier); + /* Get Expirty Time */ + getNotAfter(x509, notAfter); + /*Free X509 */ + X509_free(x509); + /* construct cbor */ cborConverter.addKeyparameters(array, keyParams); - array.add(static_cast(keyFormat)); + array.add(static_cast(KeyFormat::RAW)); std::vector encodedArray = subArray.encode(); cppbor::Bstr bstr(encodedArray.begin(), encodedArray.end()); array.add(bstr); + array.add(subject); + array.add(notAfter); + array.add(authorityKeyIdentifier); std::vector cborData = array.encode(); if(ErrorCode::OK != (errorCode = constructApduMessage(ins, cborData, apdu))) @@ -406,89 +534,141 @@ JavacardKeymaster4Device::~JavacardKeymaster4Device() {} // Methods from IKeymasterDevice follow. Return JavacardKeymaster4Device::getHardwareInfo(getHardwareInfo_cb _hidl_cb) { - //_hidl_cb(SecurityLevel::STRONGBOX, JAVACARD_KEYMASTER_NAME, JAVACARD_KEYMASTER_AUTHOR); - std::vector resp; - std::vector input; - std::unique_ptr item; - uint64_t securityLevel = static_cast(SecurityLevel::STRONGBOX); - hidl_string jcKeymasterName; - hidl_string jcKeymasterAuthor; + // When socket is not connected return hardware info parameters from HAL itself. + std::vector resp; + std::vector input; + std::unique_ptr item; + uint64_t securityLevel = static_cast(SecurityLevel::STRONGBOX); + hidl_string jcKeymasterName; + hidl_string jcKeymasterAuthor; ErrorCode ret = sendData(Instruction::INS_GET_HW_INFO_CMD, input, resp); - - if((ret == ErrorCode::OK) && (resp.size() > 2)) { - //Skip last 2 bytes in cborData, it contains status. - std::tie(item, ret) = cborConverter_.decodeData(std::vector(resp.begin(), resp.end()-2), - true); - if (item != nullptr) { - std::vector temp; - cborConverter_.getUint64(item, 0, securityLevel); //SecurityLevel - cborConverter_.getBinaryArray(item, 1, temp); - jcKeymasterName = std::string(temp.begin(), temp.end()); - temp.clear(); - cborConverter_.getBinaryArray(item, 2, temp); - jcKeymasterAuthor = std::string(temp.begin(), temp.end()); + if(ret == ErrorCode::SECURE_HW_COMMUNICATION_FAILED) { + //Socket not connected. + _hidl_cb(SecurityLevel::STRONGBOX, JAVACARD_KEYMASTER_NAME, JAVACARD_KEYMASTER_AUTHOR); + return Void(); + } else { + if((ret == ErrorCode::OK) && (resp.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, ret) = cborConverter_.decodeData(std::vector(resp.begin(), resp.end()-2), + true); + if (item != nullptr) { + std::vector temp; + if(!cborConverter_.getUint64(item, 0, securityLevel) || + !cborConverter_.getBinaryArray(item, 1, jcKeymasterName) || + !cborConverter_.getBinaryArray(item, 2, jcKeymasterAuthor)) { + _hidl_cb(static_cast(securityLevel), jcKeymasterName, jcKeymasterAuthor); + return Void(); + } + } } + _hidl_cb(static_cast(securityLevel), jcKeymasterName, jcKeymasterAuthor); + return Void(); } - _hidl_cb(static_cast(securityLevel), jcKeymasterName, jcKeymasterAuthor); - return Void(); } Return JavacardKeymaster4Device::getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) { + /* 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. + */ std::vector cborData; - std::vector input; + std::vector input; std::unique_ptr item; HmacSharingParameters hmacSharingParameters; ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; errorCode = sendData(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. - std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborData.begin(), cborData.end()-2), - true); - if (item != nullptr) { - cborConverter_.getHmacSharingParameters(item, 1, hmacSharingParameters); //HmacSharingParameters. + if(errorCode == ErrorCode::SECURE_HW_COMMUNICATION_FAILED) { + auto response = softKm_->GetHmacSharingParameters(); + ::android::hardware::keymaster::V4_0::HmacSharingParameters params; + params.seed.setToExternal(const_cast(response.params.seed.data), + response.params.seed.data_length); + static_assert(sizeof(response.params.nonce) == params.nonce.size(), "Nonce sizes don't match"); + memcpy(params.nonce.data(), response.params.nonce, params.nonce.size()); + _hidl_cb(legacy_enum_conversion(response.error), params); + return Void(); + } else { + if((errorCode == ErrorCode::OK) && (cborData.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborData.begin(), cborData.end()-2), + true); + if (item != nullptr) { + if(!cborConverter_.getHmacSharingParameters(item, 1, hmacSharingParameters)) { + errorCode = ErrorCode::UNKNOWN_ERROR; + } + } } + _hidl_cb(errorCode, hmacSharingParameters); + return Void(); } - _hidl_cb(errorCode, hmacSharingParameters); - return Void(); } Return JavacardKeymaster4Device::computeSharedHmac(const hidl_vec& params, computeSharedHmac_cb _hidl_cb) { + /* 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 + * computeSharedHmac. + */ cppbor::Array array; std::unique_ptr item; - std::vector cborOutData; + std::vector cborOutData; hidl_vec sharingCheck; ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; std::vector tempVec; - cppbor::Array innerArray; + cppbor::Array outerArray; for(size_t i = 0; i < params.size(); ++i) { + cppbor::Array innerArray; innerArray.add(static_cast>(params[i].seed)); - for(size_t j = 0; i < params[j].nonce.size(); j++) { + for(size_t j = 0; j < params[i].nonce.size(); j++) { tempVec.push_back(params[i].nonce[j]); } innerArray.add(tempVec); tempVec.clear(); + outerArray.add(std::move(innerArray)); } - array.add(std::move(innerArray)); + array.add(std::move(outerArray)); std::vector cborData = array.encode(); errorCode = sendData(Instruction::INS_COMPUTE_SHARED_HMAC_CMD, cborData, cborOutData); + if(errorCode == ErrorCode::SECURE_HW_COMMUNICATION_FAILED) { + ComputeSharedHmacRequest request; + request.params_array.params_array = new keymaster::HmacSharingParameters[params.size()]; + request.params_array.num_params = params.size(); + for (size_t i = 0; i < params.size(); ++i) { + request.params_array.params_array[i].seed = {params[i].seed.data(), params[i].seed.size()}; + static_assert(sizeof(request.params_array.params_array[i].nonce) == + decltype(params[i].nonce)::size(), + "Nonce sizes don't match"); + memcpy(request.params_array.params_array[i].nonce, params[i].nonce.data(), + params[i].nonce.size()); + } - if((errorCode == ErrorCode::OK) && (cborData.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) { - std::vector bstr; - cborConverter_.getBinaryArray(item, 1, bstr); - sharingCheck.setToExternal(bstr.data(), bstr.size()); + auto response = softKm_->ComputeSharedHmac(request); + hidl_vec sharing_check; + if (response.error == KM_ERROR_OK) sharing_check = kmBlob2hidlVec(response.sharing_check); + + _hidl_cb(legacy_enum_conversion(response.error), sharing_check); + return Void(); + + } else { + if((errorCode == ErrorCode::OK) && (cborData.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) { + std::vector bstr; + if(!cborConverter_.getBinaryArray(item, 1, bstr)) { + errorCode = ErrorCode::UNKNOWN_ERROR; + } else { + sharingCheck = bstr; + } + } } + _hidl_cb(errorCode, sharingCheck); + return Void(); } - _hidl_cb(errorCode, sharingCheck); - return Void(); + } Return JavacardKeymaster4Device::verifyAuthorization(uint64_t operationHandle, const hidl_vec& parametersToVerify, const HardwareAuthToken& authToken, verifyAuthorization_cb _hidl_cb) { @@ -511,7 +691,8 @@ Return JavacardKeymaster4Device::verifyAuthorization(uint64_t operationHan std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), true); if (item != nullptr) { - cborConverter_.getVerificationToken(item, 1, verificationToken); + if(!cborConverter_.getVerificationToken(item, 1, verificationToken)) + errorCode = ErrorCode::UNKNOWN_ERROR; } } _hidl_cb(errorCode, verificationToken); @@ -545,9 +726,19 @@ Return JavacardKeymaster4Device::generateKey(const hidl_vec& std::vector cborOutData; ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; KeyCharacteristics keyCharacteristics; + hidl_vec updatedParams(keyParams); + + if(!findTag(keyParams, Tag::CREATION_DATETIME) && + !findTag(keyParams, Tag::ACTIVE_DATETIME)) { + //Add CREATION_DATETIME in HAL, as secure element is not having clock. + size_t size = keyParams.size(); + updatedParams.resize(size+1); + updatedParams[size].tag = Tag::CREATION_DATETIME; + updatedParams[size].f.dateTime = java_time(time(nullptr)); + } /* Convert to cbor format */ - cborConverter_.addKeyparameters(array, keyParams); + cborConverter_.addKeyparameters(array, updatedParams); std::vector cborData = array.encode(); errorCode = sendData(Instruction::INS_GENERATE_KEY_CMD, cborData, cborOutData); @@ -557,8 +748,14 @@ Return JavacardKeymaster4Device::generateKey(const hidl_vec& 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); + if(!cborConverter_.getBinaryArray(item, 1, keyBlob) || + !cborConverter_.getKeyCharacteristics(item, 2, keyCharacteristics)) { + //Clear the buffer. + keyBlob.setToExternal(nullptr, 0); + keyCharacteristics.softwareEnforced.setToExternal(nullptr, 0); + keyCharacteristics.hardwareEnforced.setToExternal(nullptr, 0); + errorCode = ErrorCode::UNKNOWN_ERROR; + } } } _hidl_cb(errorCode, keyBlob, keyCharacteristics); @@ -580,7 +777,7 @@ Return JavacardKeymaster4Device::importKey(const hidl_vec& k } cborConverter_.addKeyparameters(array, keyParams); array.add(static_cast(KeyFormat::RAW)); //javacard accepts only RAW. - if(ErrorCode::OK != (errorCode = prepareCborArrayFromRawKey(keyParams, keyFormat, keyData, subArray))) { + if(ErrorCode::OK != (errorCode = prepareCborArrayFromKeyData(keyParams, keyFormat, keyData, subArray))) { _hidl_cb(errorCode, keyBlob, keyCharacteristics); return Void(); } @@ -597,8 +794,14 @@ Return JavacardKeymaster4Device::importKey(const hidl_vec& k 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); + if(!cborConverter_.getBinaryArray(item, 1, keyBlob) || + !cborConverter_.getKeyCharacteristics(item, 2, keyCharacteristics)) { + //Clear the buffer. + keyBlob.setToExternal(nullptr, 0); + keyCharacteristics.softwareEnforced.setToExternal(nullptr, 0); + keyCharacteristics.hardwareEnforced.setToExternal(nullptr, 0); + errorCode = ErrorCode::UNKNOWN_ERROR; + } } } _hidl_cb(errorCode, keyBlob, keyCharacteristics); @@ -646,12 +849,17 @@ Return JavacardKeymaster4Device::importWrappedKey(const hidl_vec& 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); + if(!cborConverter_.getBinaryArray(item, 1, keyBlob) || + !cborConverter_.getKeyCharacteristics(item, 2, keyCharacteristics)) { + //Clear the buffer. + keyBlob.setToExternal(nullptr, 0); + keyCharacteristics.softwareEnforced.setToExternal(nullptr, 0); + keyCharacteristics.hardwareEnforced.setToExternal(nullptr, 0); + errorCode = ErrorCode::UNKNOWN_ERROR; + } } } _hidl_cb(errorCode, keyBlob, keyCharacteristics); - return Void(); } @@ -674,14 +882,31 @@ Return JavacardKeymaster4Device::getKeyCharacteristics(const hidl_vec(cborOutData.begin(), cborOutData.end()-2), true); if (item != nullptr) { - cborConverter_.getKeyCharacteristics(item, 1, keyCharacteristics); + if(!cborConverter_.getKeyCharacteristics(item, 1, keyCharacteristics)) { + keyCharacteristics.softwareEnforced.setToExternal(nullptr, 0); + keyCharacteristics.hardwareEnforced.setToExternal(nullptr, 0); + errorCode = ErrorCode::UNKNOWN_ERROR; + } } } _hidl_cb(errorCode, keyCharacteristics); return Void(); } -Return JavacardKeymaster4Device::exportKey(KeyFormat exportFormat, 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) { + ErrorCode errorCode = ErrorCode::UNKNOWN_ERROR; + hidl_vec resultKeyBlob; + + //Check if keyblob is corrupted + getKeyCharacteristics(keyBlob, clientId, appData, + [&](ErrorCode error, KeyCharacteristics /*keyCharacteristics*/) { + errorCode = error; + }); + + if(errorCode != ErrorCode::OK) { + _hidl_cb(errorCode, resultKeyBlob); + return Void(); + } ExportKeyRequest request; request.key_format = legacy_enum_conversion(exportFormat); @@ -690,7 +915,10 @@ Return JavacardKeymaster4Device::exportKey(KeyFormat exportFormat, const h ExportKeyResponse response; softKm_->ExportKey(request, &response); - hidl_vec resultKeyBlob; + if(response.error == KM_ERROR_INCOMPATIBLE_ALGORITHM) { + //Symmetric Keys cannot be exported. + response.error = KM_ERROR_UNSUPPORTED_KEY_FORMAT; + } if (response.error == KM_ERROR_OK) { resultKeyBlob.setToExternal(response.key_data, response.key_data_length); } @@ -719,16 +947,19 @@ Return JavacardKeymaster4Device::attestKey(const hidl_vec& keyToA std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), true); if (item != nullptr) { - cborConverter_.getMultiBinaryArray(item, 1, temp); - } - if(readDataFromFile(ROOT_RSA_CERT, rootCert)) { - temp.push_back(std::move(rootCert)); - certChain.resize(temp.size()); - for(int i = 0; i < temp.size(); i++) { - certChain[i] = temp[i]; + if(!cborConverter_.getMultiBinaryArray(item, 1, temp)) { + errorCode = ErrorCode::UNKNOWN_ERROR; + } else { + if(readDataFromFile(ROOT_RSA_CERT, rootCert)) { + temp.push_back(std::move(rootCert)); + certChain.resize(temp.size()); + for(int i = 0; i < temp.size(); i++) { + certChain[i] = temp[i]; + } + } else { + LOG(ERROR) << "No root certificate found"; + } } - } else { - LOG(ERROR) << "No root certificate found"; } } _hidl_cb(errorCode, certChain); @@ -753,7 +984,8 @@ Return JavacardKeymaster4Device::upgradeKey(const hidl_vec& keyBl std::tie(item, errorCode) = cborConverter_.decodeData(std::vector(cborOutData.begin(), cborOutData.end()-2), true); if (item != nullptr) { - cborConverter_.getBinaryArray(item, 1, upgradedKeyBlob); + if(!cborConverter_.getBinaryArray(item, 1, upgradedKeyBlob)) + errorCode = ErrorCode::UNKNOWN_ERROR; } } _hidl_cb(errorCode, upgradedKeyBlob); @@ -768,7 +1000,6 @@ Return JavacardKeymaster4Device::deleteKey(const hidl_vec& k array.add(std::vector(keyBlob)); std::vector cborData = array.encode(); - errorCode = sendData(Instruction::INS_DELETE_KEY_CMD, cborData, cborOutData); if((errorCode == ErrorCode::OK) && (cborOutData.size() > 2)) { @@ -845,6 +1076,7 @@ Return JavacardKeymaster4Device::begin(KeyPurpose purpose, const hidl_vec< std::unique_ptr item; std::unique_ptr blobItem = nullptr; KeyCharacteristics keyCharacteristics; + KeyParameter param; /* Convert input data to cbor format */ array.add(static_cast(purpose)); @@ -859,22 +1091,27 @@ Return JavacardKeymaster4Device::begin(KeyPurpose purpose, const hidl_vec< /* TODO if keyBlob is corrupted it crashes in cbor */ std::tie(blobItem, errorCode) = cborConverter_.decodeData(std::vector(keyBlob), false); - if(blobItem == nullptr) { - _hidl_cb(errorCode, outParams, operationHandle); - return Void(); - } - errorCode = sendData(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); - /* Store the operationInfo */ - cborConverter_.getKeyCharacteristics(blobItem, 3, keyCharacteristics); - oprCtx_->setOperationInfo(operationHandle, purpose, keyCharacteristics.hardwareEnforced); + if(blobItem != nullptr) { + errorCode = ErrorCode::UNKNOWN_ERROR; + if(cborConverter_.getKeyCharacteristics(blobItem, 3, keyCharacteristics) && + getTag(keyCharacteristics.hardwareEnforced, Tag::ALGORITHM, param)) { + errorCode = sendData(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) { + if(!cborConverter_.getKeyParameters(item, 1, outParams) || + !cborConverter_.getUint64(item, 2, operationHandle)) { + errorCode = ErrorCode::UNKNOWN_ERROR; + outParams.setToExternal(nullptr, 0); + operationHandle = 0; + } else { + /* Store the operationInfo */ + oprCtx_->setOperationInfo(operationHandle, purpose, param.f.algorithm, inParams); + } + } + } } } _hidl_cb(errorCode, outParams, operationHandle); @@ -909,6 +1146,15 @@ Return JavacardKeymaster4Device::update(uint64_t operationHandle, const hi std::unique_ptr item; std::vector cborOutData; std::vector asn1ParamsVerified; + // For symmetic ciphers only block aligned data is send to javacard Applet to reduce the number of calls to + //javacard. If the input message is less than block size then it is buffered inside the HAL. so in case if + // after buffering there is no data to send to javacard don't call javacard applet. + //For AES GCM operations, even though the input length is 0(which is not block aligned), if there is + //ASSOCIATED_DATA present in KeyParameters. Then we need to make a call to javacard Applet. + if(data.size() == 0 && !findTag(inParams, Tag::ASSOCIATED_DATA)) { + //Return OK, since this is not error case. + return ErrorCode::OK; + } if(ErrorCode::OK != (errorCode = encodeParametersVerified(verificationToken, asn1ParamsVerified))) { return errorCode; @@ -931,9 +1177,16 @@ Return JavacardKeymaster4Device::update(uint64_t operationHandle, const hi 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); + //This callback function may gets called multiple times so parse and get the outParams only once. + //Otherwise there can be chance of duplicate entries in outParams. Use tempOut to collect all the + //cipher text and finally copy it to the output. getBinaryArray function appends the new cipher text + //at the end of the tempOut(std::vector). + if((outParams.size() == 0 && !cborConverter_.getKeyParameters(item, 2, outParams)) || + !cborConverter_.getBinaryArray(item, 3, tempOut)) { + outParams.setToExternal(nullptr, 0); + tempOut.clear(); + errorCode = ErrorCode::UNKNOWN_ERROR; + } } } return errorCode; @@ -971,6 +1224,7 @@ Return JavacardKeymaster4Device::finish(uint64_t operationHandle, const hi output = kmBuffer2hidlVec(response.output); } else if (response.error == KM_ERROR_INVALID_OPERATION_HANDLE) { std::vector tempOut; + bool aadTag = false; /* 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 @@ -990,16 +1244,34 @@ Return JavacardKeymaster4Device::finish(uint64_t operationHandle, const hi return errorCode; } + //In case if there is ASSOCIATED_DATA present in the keyparams, then make sure it is either passed with + //update call or finish call. Don't send ASSOCIATED_DATA in both update and finish calls. aadTag is used to + //check if ASSOCIATED_DATA is already sent in update call. If addTag is true then skip ASSOCIATED_DATA from + //keyparams in finish call. // Convert input data to cbor format array.add(operationHandle); - cborConverter_.addKeyparameters(array, inParams); - array.add(data); if(finish) { + std::vector finishParams; + if(aadTag) { + for(int i = 0; i < inParams.size(); i++) { + if(inParams[i].tag != Tag::ASSOCIATED_DATA) + finishParams.push_back(inParams[i]); + } + } else { + finishParams = inParams; + } + cborConverter_.addKeyparameters(array, finishParams); + array.add(data); array.add(std::vector(signature)); ins = Instruction::INS_FINISH_OPERATION_CMD; keyParamPos = 1; outputPos = 2; } else { + if(findTag(inParams, Tag::ASSOCIATED_DATA)) { + aadTag = true; + } + cborConverter_.addKeyparameters(array, inParams); + array.add(data); ins = Instruction::INS_UPDATE_OPERATION_CMD; keyParamPos = 2; outputPos = 3; @@ -1015,9 +1287,17 @@ Return JavacardKeymaster4Device::finish(uint64_t operationHandle, const hi 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); + //There is a change that this finish callback may gets called multiple times if the input data size + //is larger the MAX_ALLOWED_INPUT_SIZE (Refer OperationContext) so parse and get the outParams only + //once. Otherwise there can be chance of duplicate entries in outParams. Use tempOut to collect all + //the cipher text and finally copy it to the output. getBinaryArray function appends the new cipher + //text at the end of the tempOut(std::vector). + if((outParams.size() == 0 && !cborConverter_.getKeyParameters(item, keyParamPos, outParams)) || + !cborConverter_.getBinaryArray(item, outputPos, tempOut)) { + outParams.setToExternal(nullptr, 0); + tempOut.clear(); + errorCode = ErrorCode::UNKNOWN_ERROR; + } } } return errorCode; diff --git a/HAL/keymaster/4.1/JavacardOperationContext.cpp b/HAL/keymaster/4.1/JavacardOperationContext.cpp index 7e242162..d9d05d35 100644 --- a/HAL/keymaster/4.1/JavacardOperationContext.cpp +++ b/HAL/keymaster/4.1/JavacardOperationContext.cpp @@ -20,7 +20,7 @@ #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 RSA_INPUT_MSG_LEN 256 #define EC_INPUT_MSG_LEN 32 #define MAX_RSA_BUFFER_SIZE 256 #define MAX_EC_BUFFER_SIZE 32 @@ -47,6 +47,9 @@ inline ErrorCode hidlParamSet2OperatinInfo(const hidl_vec& params, case Tag::PADDING: info.pad = static_cast(param.f.integer); break; + case Tag::BLOCK_MODE: + info.mode = static_cast(param.f.integer); + break; default: continue; } @@ -54,33 +57,19 @@ inline ErrorCode hidlParamSet2OperatinInfo(const hidl_vec& params, return ErrorCode::OK; } -ErrorCode OperationContext::setOperationInfo(uint64_t operationHandle, KeyPurpose purpose, const hidl_vec& params) { +ErrorCode OperationContext::setOperationInfo(uint64_t operationHandle, KeyPurpose purpose, Algorithm alg, const hidl_vec& params) { ErrorCode errorCode = ErrorCode::OK; - OperationInfo info; - if(ErrorCode::OK != (errorCode = hidlParamSet2OperatinInfo(params, info))) { + OperationData data; + if(ErrorCode::OK != (errorCode = hidlParamSet2OperatinInfo(params, data.info))) { return errorCode; } - info.purpose = purpose; - return setOperationInfo(operationHandle, info); -} - -ErrorCode OperationContext::setOperationInfo(uint64_t operationHandle, OperationInfo& operInfo) { - OperationData data; - data.info = operInfo; + data.info.purpose = purpose; + data.info.alg = alg; memset((void*)&(data.data), 0x00, sizeof(data.data)); 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) @@ -91,11 +80,8 @@ ErrorCode OperationContext::clearOperationData(uint64_t operHandle) { 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; - } + OperationData& oprData = operationTable[operHandle]; if(KeyPurpose::SIGN == oprData.info.purpose) { if(Algorithm::RSA == oprData.info.alg && Digest::NONE == oprData.info.digest) { @@ -121,14 +107,19 @@ ErrorCode OperationContext::validateInputData(uint64_t operHandle, Operation opr } 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; + //If it is observed in finish operation that buffered data + input data exceeds the MAX_ALLOWED_INPUT_SIZE then + //combine both the data in a single buffer. This helps in making sure that no data is left out in the buffer after + //finish opertion. + if((oprData.data.buf_len+actualInput.size()) > MAX_ALLOWED_INPUT_SIZE) { + for(size_t i = 0; i < oprData.data.buf_len; ++i) { + input.push_back(oprData.data.buf[i]); + } + input.insert(input.end(), actualInput.begin(), actualInput.end()); + //As buffered data is already consumed earse the buffer. + if(oprData.data.buf_len != 0) { + memset(oprData.data.buf, 0x00, sizeof(oprData.data.buf)); + oprData.data.buf_len = 0; + } } } input = actualInput; @@ -177,7 +168,7 @@ ErrorCode OperationContext::finish(uint64_t operHandle, const std::vector input; /* Validate the input data */ - if(ErrorCode::OK != (errorCode = validateInputData(operHandle, Operation::Update, actualInput, input))) { + if(ErrorCode::OK != (errorCode = validateInputData(operHandle, Operation::Finish, actualInput, input))) { return errorCode; } @@ -196,30 +187,23 @@ ErrorCode OperationContext::finish(uint64_t operHandle, const std::vector 0) { std::vector finalInput(input.cend()-extraData, input.cend()); if(ErrorCode::OK != (errorCode = handleInternalUpdate(operHandle, finalInput.data(), finalInput.size(), - Operation::Update, cb))) { + Operation::Finish, cb, true))) { return errorCode; } } } else { if(ErrorCode::OK != (errorCode = handleInternalUpdate(operHandle, input.data(), input.size(), - Operation::Update, cb))) { + Operation::Finish, cb, true))) { 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; +/* This function is called for only symmetric operations */ +ErrorCode OperationContext::getBlockAlignedData(uint64_t operHandle, uint8_t* input, size_t input_len, Operation opr, std::vector& out) { + int dataToSELen = 0; + int inputConsumed = 0;/*Length of the data consumed from input */ int blockSize = 0; BufferedData& data = operationTable[operHandle].data; int bufIndex = data.buf_len; @@ -230,34 +214,36 @@ ErrorCode OperationContext::internalUpdate(uint64_t operHandle, uint8_t* input, 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; - } + 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 { - dataToSELen = input_len; + /*Update */ + //Calculate the block sized length on combined input of both buffered data and input data. + uint32_t blockAlignedLen = ((data.buf_len + input_len)/blockSize) * blockSize; + //For symmetric ciphers, decryption operation and PKCS7 padding mode save last 16 bytes of block and send this + //block in finish operation. This is done to make sure that there will be always a 16 bytes data to finish + //operation so that javacard Applet may remove PKCS7 padding if any. + if(((operationTable[operHandle].info.alg == Algorithm::AES) || + (operationTable[operHandle].info.alg == Algorithm::TRIPLE_DES)) && + (operationTable[operHandle].info.pad == PaddingMode::PKCS7) && + (operationTable[operHandle].info.purpose == KeyPurpose::DECRYPT)) { + if(blockAlignedLen >= blockSize) blockAlignedLen -= blockSize; + } + //Copy data to be send to SE from buffer, only if atleast a minimum block aligned size is available. + if(blockAlignedLen >= blockSize) { + for(size_t pos = 0; pos < data.buf_len; pos++) { + out.push_back(data.buf[pos]); + } + } + dataToSELen = blockAlignedLen; } - if(dataSendToSE) { - if(opr == Operation::Update) { - dataToSELen = (dataToSELen/blockSize) * blockSize; - } + if(dataToSELen > 0) { inputConsumed = dataToSELen - data.buf_len; //Copy the buffer to be send to SE. @@ -282,6 +268,83 @@ ErrorCode OperationContext::internalUpdate(uint64_t operHandle, uint8_t* input, return ErrorCode::OK; } +ErrorCode OperationContext::handleInternalUpdate(uint64_t operHandle, uint8_t* data, size_t len, Operation opr, + sendDataToSE_cb cb, bool finish) { + ErrorCode errorCode = ErrorCode::OK; + std::vector out; + + if(Algorithm::AES == operationTable[operHandle].info.alg || + Algorithm::TRIPLE_DES == operationTable[operHandle].info.alg) { + /*Symmetric */ + if(ErrorCode::OK != (errorCode = getBlockAlignedData(operHandle, data, len, + opr, out))) { + return errorCode; + } + //Call the callback under these condition + //1. if it is a finish operation. + //2. if there is some data to be send to Javacard.(either update or finish operation). + //3. if the operation is GCM Mode. Even though there is no data to be send there could be AAD data to be sent to + //javacard. + if(finish || out.size() > 0 || BlockMode::GCM == operationTable[operHandle].info.mode) { + if(ErrorCode::OK != (errorCode = cb(out, finish))) { + return errorCode; + } + } + } else { + /* Asymmetric */ + if(operationTable[operHandle].info.purpose == KeyPurpose::DECRYPT || + operationTable[operHandle].info.digest == Digest::NONE) { + //In case of Decrypt operation or Sign operation with no digest case, buffer the data in + //update call and send it to SE in finish call. + if(finish) { + //If finish flag is true all the data has to be sent to javacard. + size_t i = 0; + for(; i < operationTable[operHandle].data.buf_len; ++i) { + out.push_back(operationTable[operHandle].data.buf[i]); + } + for(i = 0; i < len; ++i) { + out.push_back(data[i]); + } + //As buffered data is already consumed earse the buffer. + if(operationTable[operHandle].data.buf_len != 0) { + memset(operationTable[operHandle].data.buf, 0x00, sizeof(operationTable[operHandle].data.buf)); + operationTable[operHandle].data.buf_len = 0; + } + if(ErrorCode::OK != (errorCode = cb(out, finish))) { + return errorCode; + } + } else { + //For strongbox keymaster, in NoDigest case the length of the input message for RSA should be more than + //256 and for EC it should not be more than 32. This validation is already happening in + //validateInputData function. Just for safety sake we are checking the length to MAX_BUF_SIZE. + if(operationTable[operHandle].data.buf_len <= MAX_BUF_SIZE) { + size_t bufIndex = operationTable[operHandle].data.buf_len; + size_t pos = 0; + for(; (pos < len) && (pos < (MAX_BUF_SIZE-bufIndex)); pos++) + { + operationTable[operHandle].data.buf[bufIndex+pos] = data[pos]; + } + operationTable[operHandle].data.buf_len += pos; + } + } + } else { /* With Digest */ + for(size_t j=0; j < len; ++j) + { + out.push_back(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 length the 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 diff --git a/HAL/keymaster/4.1/java_card_soft_keymaster_context.cpp b/HAL/keymaster/4.1/JavacardSoftKeymasterContext.cpp similarity index 99% rename from HAL/keymaster/4.1/java_card_soft_keymaster_context.cpp rename to HAL/keymaster/4.1/JavacardSoftKeymasterContext.cpp index 1186b398..8f9905af 100644 --- a/HAL/keymaster/4.1/java_card_soft_keymaster_context.cpp +++ b/HAL/keymaster/4.1/JavacardSoftKeymasterContext.cpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include diff --git a/HAL/keymaster/4.1/SocketTransport.cpp b/HAL/keymaster/4.1/SocketTransport.cpp index 0dba18f9..51c28675 100644 --- a/HAL/keymaster/4.1/SocketTransport.cpp +++ b/HAL/keymaster/4.1/SocketTransport.cpp @@ -19,9 +19,11 @@ #include #include #include "Transport.h" +#include #define PORT 8080 #define IPADDR "10.9.40.24" +//#define IPADDR "192.168.0.5" #define MAX_RECV_BUFFER_SIZE 2048 namespace se_transport { @@ -69,7 +71,15 @@ bool SocketTransport::sendData(const uint8_t* inData, const size_t inLen, std::v } if (0 > send(mSocket, inData, inLen , 0 )) { - LOG(ERROR) << "Failed to send data over socket."; + static int connectionResetCnt = 0; /* To avoid loop */ + if (ECONNRESET == errno && connectionResetCnt == 0) { + //Connection reset. Try open socket and then sendData. + socketStatus = false; + connectionResetCnt++; + return sendData(inData, inLen, output); + } + LOG(ERROR) << "Failed to send data over socket err: " << errno; + connectionResetCnt = 0; return false; } ssize_t valRead = read( mSocket , buffer, MAX_RECV_BUFFER_SIZE); @@ -89,7 +99,6 @@ bool SocketTransport::closeConnection() { } bool SocketTransport::isConnected() { - //TODO return socketStatus; } diff --git a/HAL/keymaster/4.1/android.hardware.keymaster@4.1-javacard.service.rc b/HAL/keymaster/4.1/android.hardware.keymaster@4.1-javacard.service.rc new file mode 100644 index 00000000..556ffd1d --- /dev/null +++ b/HAL/keymaster/4.1/android.hardware.keymaster@4.1-javacard.service.rc @@ -0,0 +1,6 @@ +service android.hardware.keymaster@4.1-javacard.service /vendor/bin/hw/android.hardware.keymaster@4.1-javacard.service + interface android.hardware.keymaster@4.0::IKeymasterDevice default + interface android.hardware.keymaster@4.1::IKeymasterDevice default + class early_hal + user system + group system drmrpc diff --git a/HAL/keymaster/4.1/android.hardware.keymaster@4.1-service.javacard.xml b/HAL/keymaster/4.1/android.hardware.keymaster@4.1-javacard.service.xml similarity index 53% rename from HAL/keymaster/4.1/android.hardware.keymaster@4.1-service.javacard.xml rename to HAL/keymaster/4.1/android.hardware.keymaster@4.1-javacard.service.xml index 4fb320a6..5e365def 100644 --- a/HAL/keymaster/4.1/android.hardware.keymaster@4.1-service.javacard.xml +++ b/HAL/keymaster/4.1/android.hardware.keymaster@4.1-javacard.service.xml @@ -2,10 +2,6 @@ android.hardware.keymaster hwbinder - 4.1 - - IKeymasterDevice - default - + @4.1::IKeymasterDevice/javacard diff --git a/HAL/keymaster/4.1/android.hardware.keymaster@4.1-service.javacard.rc b/HAL/keymaster/4.1/android.hardware.keymaster@4.1-service.javacard.rc deleted file mode 100644 index 1094c090..00000000 --- a/HAL/keymaster/4.1/android.hardware.keymaster@4.1-service.javacard.rc +++ /dev/null @@ -1,4 +0,0 @@ -service vendor.keymaster-4-1 /vendor/bin/hw/android.hardware.keymaster@4.1-service.javacard - class early_hal - user nobody - group drmrpc diff --git a/HAL/keymaster/4.1/service.cpp b/HAL/keymaster/4.1/service.cpp index 60123b5c..75ed2510 100644 --- a/HAL/keymaster/4.1/service.cpp +++ b/HAL/keymaster/4.1/service.cpp @@ -22,10 +22,9 @@ int main() { ::android::hardware::configureRpcThreadpool(1, true); + auto keymaster = new ::keymaster::V4_1::javacard::JavacardKeymaster4Device(); - auto keymaster = new ::android::hardware::keymaster::V4_1::JavacardKeymaster4Device(); - - auto status = keymaster->registerAsService(); + auto status = keymaster->registerAsService("javacard"); if (status != android::OK) { LOG(FATAL) << "Could not register service for Keymaster 4.1 (" << status << ")"; return -1; diff --git a/HAL/keymaster/Android.bp b/HAL/keymaster/Android.bp index bd253b43..ef67cb6e 100644 --- a/HAL/keymaster/Android.bp +++ b/HAL/keymaster/Android.bp @@ -13,12 +13,49 @@ // limitations under the License. // + +cc_binary { + name: "android.hardware.keymaster@4.1-javacard.service", + relative_install_path: "hw", + vendor: true, + init_rc: ["4.1/android.hardware.keymaster@4.1-javacard.service.rc"], + vintf_fragments: ["4.1/android.hardware.keymaster@4.1-javacard.service.xml"], + srcs: [ + "4.1/service.cpp", + "4.1/JavacardKeymaster4Device.cpp", + "4.1/CborConverter.cpp", + "4.1/JavacardSoftKeymasterContext.cpp", + "4.1/JavacardOperationContext.cpp", + "4.1/CommonUtils.cpp", + ], + local_include_dirs: [ + "include", + ], + shared_libs: [ + "liblog", + "libcutils", + "libdl", + "libbase", + "libutils", + "libhardware", + "libhidlbase", + "libsoftkeymasterdevice", + "libkeymaster_messages", + "libkeymaster_portable", + "libcppbor_external", + "android.hardware.keymaster@4.1", + "android.hardware.keymaster@4.0", + "libjc_transport", + "libcrypto", + ], +} + cc_library { name: "libJavacardKeymaster41", srcs: [ "4.1/JavacardKeymaster4Device.cpp", "4.1/CborConverter.cpp", - "4.1/java_card_soft_keymaster_context.cpp", + "4.1/JavacardSoftKeymasterContext.cpp", "4.1/JavacardOperationContext.cpp", "4.1/CommonUtils.cpp", ], @@ -33,14 +70,14 @@ cc_library { "libutils", "libhardware", "libhidlbase", - "libsoftkeymasterdevice", + "libsoftkeymasterdevice", "libkeymaster_messages", - "libkeymaster_portable", + "libkeymaster_portable", "libcppbor_external", "android.hardware.keymaster@4.1", "android.hardware.keymaster@4.0", "libjc_transport", - "libcrypto", + "libcrypto", ], } @@ -48,6 +85,9 @@ cc_library { name: "libjc_transport", host_supported: true, vendor_available: true, + vndk: { + enabled: true, + }, srcs: [ "4.1/SocketTransport.cpp", diff --git a/HAL/keymaster/include/CborConverter.h b/HAL/keymaster/include/CborConverter.h index 9ea2ef94..ecbe2783 100644 --- a/HAL/keymaster/include/CborConverter.h +++ b/HAL/keymaster/include/CborConverter.h @@ -90,6 +90,11 @@ class CborConverter */ bool getHmacSharingParameters(const std::unique_ptr& item, const uint32_t pos, HmacSharingParameters& params); + /** + * Get the Binary string at the given position from the item pointer. + */ + bool getBinaryArray(const std::unique_ptr& item, const uint32_t pos, ::android::hardware::hidl_string& value); + /** * Get the Binary string at the given position from the item pointer. */ diff --git a/HAL/keymaster/include/CommonUtils.h b/HAL/keymaster/include/CommonUtils.h index a3feee14..e418fc0c 100644 --- a/HAL/keymaster/include/CommonUtils.h +++ b/HAL/keymaster/include/CommonUtils.h @@ -70,6 +70,12 @@ inline void blob2Vec(const uint8_t *from, size_t size, std::vector& to) } } +inline hidl_vec kmBlob2hidlVec(const keymaster_blob_t& blob) { + hidl_vec result; + result.setToExternal(const_cast(blob.data), blob.data_length); + return result; +} + keymaster_key_param_set_t hidlKeyParams2Km(const hidl_vec& keyParams); hidl_vec kmParamSet2Hidl(const keymaster_key_param_set_t& set); diff --git a/HAL/keymaster/include/JavacardOperationContext.h b/HAL/keymaster/include/JavacardOperationContext.h index 7a6fb706..53d08dd9 100644 --- a/HAL/keymaster/include/JavacardOperationContext.h +++ b/HAL/keymaster/include/JavacardOperationContext.h @@ -34,117 +34,117 @@ 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::BlockMode; using ::android::hardware::keymaster::V4_0::Tag; +/** + * Callback function to send data back to the caller. + */ using sendDataToSE_cb = std::function& data, bool finish)>; enum class Operation; +/** + * This struct is used to store the buffered data. + */ struct BufferedData { uint8_t buf[MAX_BUF_SIZE]; size_t buf_len; }; +/** + * This struct is used to store the operation info. + */ struct OperationInfo { Algorithm alg; KeyPurpose purpose; Digest digest; PaddingMode pad; + BlockMode mode; }; +/** + * OperationContext uses this struct to store the buffered data and the correspoding operation info. + */ struct OperationData { OperationInfo info; BufferedData data; }; +/** + * This class manages the data that is send for any crypto operation. + * + * For Symmetric operations, update function sends only block aligned data and stores the remaining data in the buffer + * so at any point the buffer may contain data ranging from 0 to a maximum of block size, where as finish function sends + * all the data (input data + buffered data) to the caller and clears the buffer. To support PKCS#7 padding removal, + * the last block size from the input is always buffered in update operation and this last block is sent in finish + * operation. + * + * For Asymmetric operations, if the operation is with Digest then the input data is not buffered, where as if the + * operation is with no Digest then update function buffers the input data and finish function extracts the data from + * buffer and sends to the caller. Update and finish functions does validation on the input data based on the algorithm. + * + * In General, the maximum allowed input data that is sent is limited to MAX_ALLOWED_INPUT_SIZE. If the input data + * exceeds this limit each update or finish function divides the input data into chunks of MAX_ALLOWED_INPUT_SIZE and + * sends each chunk back to the caller through update callback. + */ 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); + /** + * In Begin operation caller has to call this function to store the operation data corresponding to the operation + * handle. + */ + ErrorCode setOperationInfo(uint64_t operationHandle, KeyPurpose purpose, Algorithm alg, const hidl_vec& params); + /** + * This function clears the operation data from the map. Caller has to call this function once the operation is done + * or if there is any error while processing the operation. + */ ErrorCode clearOperationData(uint64_t operationHandle); + /** + * This function validaes the input data based on the algorithm and does process on the data to either store it or + * send back to the caller. The data is sent using sendDataTOSE_cb callback. + */ ErrorCode update(uint64_t operHandle, const std::vector& input, sendDataToSE_cb cb); + /** + * This function validaes the input data based on the algorithm and send all the input data along with buffered data + * to the caller. The data is sent using sendDataTOSE_cb callback. + */ ErrorCode finish(uint64_t operHandle, const std::vector& input, sendDataToSE_cb cb); private: + /** + * This is used to store the operation related info and the buffered data. Key is the operation handle and the value + * is OperationData. + */ 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; - } + /* Helper functions */ + /** + * This fucntion validates the input data based on the algorithm and the operation info parameters. This function + * also does a processing on the input data if either the algorithm is EC or if it is a Finish operation. For EC + * operations it truncates the input data if it exceeds 32 bytes for No Digest case. In case of finish operations + * this function combines both the buffered data and input data if both exceeds MAX_ALLOWED_INPUT_SIZE. + */ 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; - - if(Algorithm::AES == operationTable[operHandle].info.alg || - Algorithm::TRIPLE_DES == operationTable[operHandle].info.alg) { - if(ErrorCode::OK != (errorCode = internalUpdate(operHandle, data, len, - opr, out))) { - return errorCode; - } - if(finish || out.size() > 0) { - - if(ErrorCode::OK != (errorCode = cb(out, finish))) { - return errorCode; - } - } - } else { - /* Asymmetric */ - if(operationTable[operHandle].info.purpose == KeyPurpose::DECRYPT || - operationTable[operHandle].info.digest == Digest::NONE) { - /* In case of Decrypt, sign with no digest cases buffer the data in - * update call and send data to SE in finish call. - */ - if(finish) { - for(size_t i = 0; i < operationTable[operHandle].data.buf_len; ++i) { - out.push_back(operationTable[operHandle].data.buf[i]); - } - if(ErrorCode::OK != (errorCode = cb(out, finish))) { - return errorCode; - } - } else { - //Input message length should not be more than the MAX_BUF_SIZE. - if(operationTable[operHandle].data.buf_len <= MAX_BUF_SIZE) { - size_t bufIndex = operationTable[operHandle].data.buf_len; - size_t pos = 0; - for(; (pos < len) && (pos < (MAX_BUF_SIZE-bufIndex)); pos++) - { - operationTable[operHandle].data.buf[bufIndex+pos] = data[pos]; - } - operationTable[operHandle].data.buf_len += pos; - } - } - } else { - for(size_t j=0; j < len; ++j) - { - out.push_back(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 length the callback should be called. - */ - if(len != 0 || finish) { - if(ErrorCode::OK != (errorCode = cb(out, finish))) { - return errorCode; - } - } - } - } - return errorCode; - } + std::vector& input); + /** + * This function is used for Symmetric operations. It extracts the block sized data from the input and buffers the + * reamining data for update calls only. For finish calls it extracts all the buffered data combines it with + * input data. + */ + ErrorCode getBlockAlignedData(uint64_t operHandle, uint8_t* input, size_t input_len, Operation opr, std::vector& + out); + /** + * This function sends the data back to the caller using callback functions. It does some processing on input data + * for Asymmetic operations. + */ + ErrorCode handleInternalUpdate(uint64_t operHandle, uint8_t* data, size_t len, Operation opr, + sendDataToSE_cb cb, bool finish=false); + }; } // namespace javacard diff --git a/HAL/keymaster/include/java_card_soft_keymaster_context.h b/HAL/keymaster/include/JavacardSoftKeymasterContext.h similarity index 100% rename from HAL/keymaster/include/java_card_soft_keymaster_context.h rename to HAL/keymaster/include/JavacardSoftKeymasterContext.h diff --git a/HAL/keymaster/include/Transport.h b/HAL/keymaster/include/Transport.h index 4c230b0a..25294102 100644 --- a/HAL/keymaster/include/Transport.h +++ b/HAL/keymaster/include/Transport.h @@ -79,7 +79,7 @@ class OmapiTransport : public ITransport { class SocketTransport : public ITransport { public: - SocketTransport() : socketStatus(false) { + SocketTransport() : mSocket(-1), socketStatus(false) { } /** * Creates a socket instance and connects to the provided server IP and port.