From fa957d00dcdb398503ba8a43afb7738c8d5af9d6 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Tue, 8 Dec 2020 11:01:05 +0000 Subject: [PATCH 01/21] Added provision_tool source --- HAL/keymaster/4.1/provision_tool.cpp | 449 +++++++++++++++++++++++++++ HAL/keymaster/Android.bp | 26 ++ 2 files changed, 475 insertions(+) create mode 100644 HAL/keymaster/4.1/provision_tool.cpp diff --git a/HAL/keymaster/4.1/provision_tool.cpp b/HAL/keymaster/4.1/provision_tool.cpp new file mode 100644 index 00000000..2c9fb180 --- /dev/null +++ b/HAL/keymaster/4.1/provision_tool.cpp @@ -0,0 +1,449 @@ +/* + ** + ** 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFFER_MAX_LENGTH 256 +#define SB_KEYMASTER_SERVICE "javacard" +#define INS_BEGIN_KM_CMD 0x00 +#define APDU_CLS 0x80 +#define APDU_P1 0x40 +#define APDU_P2 0x00 +#define APDU_RESP_STATUS_OK 0x9000 + +enum class Instruction { + // Provisioning commands + INS_PROVISION_ATTESTATION_KEY_CMD = INS_BEGIN_KM_CMD+1, + INS_PROVISION_CERT_CHAIN_CMD = INS_BEGIN_KM_CMD+2, + INS_PROVISION_CERT_PARAMS_CMD = INS_BEGIN_KM_CMD+3, + INS_PROVISION_ATTEST_IDS_CMD = INS_BEGIN_KM_CMD+4, + INS_PROVISION_SHARED_SECRET_CMD = INS_BEGIN_KM_CMD+5, + INS_SET_BOOT_PARAMS_CMD = INS_BEGIN_KM_CMD+6, + INS_LOCK_PROVISIONING_CMD = INS_BEGIN_KM_CMD+7, + INS_GET_PROVISION_STATUS_CMD = INS_BEGIN_KM_CMD+8, +}; + +enum ProvisionStatus { + NOT_PROVISIONED = 0x00, + PROVISION_STATUS_ATTESTATION_KEY = 0x01, + PROVISION_STATUS_ATTESTATION_CERT_CHAIN = 0x02, + PROVISION_STATUS_ATTESTATION_CERT_PARAMS = 0x04, + PROVISION_STATUS_ATTEST_IDS = 0x08, + PROVISION_STATUS_SHARED_SECRET = 0x10, + PROVISION_STATUS_BOOT_PARAM = 0x20, + PROVISION_STATUS_PROVISIONING_LOCKED = 0x40, +}; + +using ::android::hardware::keymaster::V4_0::ErrorCode; +using ::android::hardware::keymaster::V4_0::HardwareAuthenticatorType; +using ::android::hardware::keymaster::V4_0::HardwareAuthToken; +using ::android::hardware::keymaster::V4_0::HmacSharingParameters; +using ::android::hardware::keymaster::V4_0::KeyCharacteristics; +using ::android::hardware::keymaster::V4_0::KeyFormat; +using ::android::hardware::keymaster::V4_0::KeyParameter; +using ::android::hardware::keymaster::V4_0::KeyPurpose; +using ::android::hardware::keymaster::V4_0::OperationHandle; +using ::android::hardware::keymaster::V4_0::SecurityLevel; +using ::android::hardware::keymaster::V4_0::VerificationToken; +using ::android::hardware::keymaster::V4_0::Tag; +using ::android::hardware::keymaster::V4_1::IKeymasterDevice; +using ::android::sp; +using se_transport::TransportFactory; + +static sp sbKeymaster; +static TransportFactory *pTransportFactory; + +constexpr char hex_value[256] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // '0'..'9' + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'A'..'F' + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'a'..'f' + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +std::string hex2str(const uint8_t* a, size_t len) { + std::string b; + size_t num = len / 2; + b.resize(num); + for (size_t i = 0; i < num; i++) { + b[i] = (hex_value[a[i * 2] & 0xFF] << 4) + (hex_value[a[i * 2 + 1] & 0xFF]); + } + return b; +} + +//static function declarations. +static ErrorCode constructApduMessage(Instruction& ins, std::vector& inputData, std::vector& apduOut, bool +extendedOutput); +static ErrorCode sendProvisionData(Instruction ins, std::vector& inData, std::vector& response, bool +extendedOutput); +static Tag mapAttestKeyToAttestTag(const char* key); + + + +static inline uint16_t getStatus(std::vector& inputData) { + //Last two bytes are the status SW0SW1 + return (inputData.at(inputData.size()-2) << 8) | (inputData.at(inputData.size()-1)); +} + +static inline TransportFactory* getTransportFactoryInstance() { + if(pTransportFactory == nullptr) { + pTransportFactory = new se_transport::TransportFactory( + android::base::GetBoolProperty("ro.kernel.qemu", false)); + pTransportFactory->openConnection(); + } + return pTransportFactory; +} + +static Tag mapAttestKeyToAttestTag(const char* key) { + //keymaster_tag_t tag = KM_TAG_INVALID; + Tag tag = Tag::INVALID; + std::string keyStr(key); + + if (0 == keyStr.compare("brand")) { + tag = Tag::ATTESTATION_ID_BRAND; + } else if(0 == keyStr.compare("device")) { + tag = Tag::ATTESTATION_ID_DEVICE; + } else if(0 == keyStr.compare("product")) { + tag = Tag::ATTESTATION_ID_PRODUCT; + } else if(0 == keyStr.compare("serial")) { + tag = Tag::ATTESTATION_ID_SERIAL; + } else if(0 == keyStr.compare("imei")) { + tag = Tag::ATTESTATION_ID_IMEI; + } else if(0 == keyStr.compare("meid")) { + tag = Tag::ATTESTATION_ID_MEID; + } else if(0 == keyStr.compare("manufacturer")) { + tag = Tag::ATTESTATION_ID_MANUFACTURER; + } else if(0 == keyStr.compare("model")) { + tag = Tag::ATTESTATION_ID_MODEL; + } + return tag; +} + +static ErrorCode constructApduMessage(Instruction& ins, std::vector& inputData, std::vector& apduOut, bool +extendedOutput) { + apduOut.push_back(static_cast(APDU_CLS)); //CLS + apduOut.push_back(static_cast(ins)); //INS + apduOut.push_back(static_cast(APDU_P1)); //P1 + apduOut.push_back(static_cast(APDU_P2)); //P2 + + if(UCHAR_MAX < inputData.size() && USHRT_MAX >= inputData.size()) { + //Extended length 3 bytes, starts with 0x00 + apduOut.push_back(static_cast(0x00)); + apduOut.push_back(static_cast(inputData.size() >> 8)); + apduOut.push_back(static_cast(inputData.size() & 0xFF)); + //Data + apduOut.insert(apduOut.end(), inputData.begin(), inputData.end()); + //Expected length of output + apduOut.push_back(static_cast(0x00)); + apduOut.push_back(static_cast(0x00)); + apduOut.push_back(static_cast(0x00));//Accepting complete length of output at a time + } else if(0 <= inputData.size() && UCHAR_MAX >= inputData.size()) { + //Short length + apduOut.push_back(static_cast(inputData.size())); + //Data + if(inputData.size() > 0) + apduOut.insert(apduOut.end(), inputData.begin(), inputData.end()); + //Expected length of output + apduOut.push_back(static_cast(0x00));//Accepting complete length of output at a time + if(extendedOutput) + apduOut.push_back(static_cast(0x00)); + + } else { + return (ErrorCode::INSUFFICIENT_BUFFER_SPACE); + } + + return (ErrorCode::OK);//success +} + +static ErrorCode sendProvisionData(Instruction ins, std::vector& inData, std::vector& response, bool +extendedOutput=false) { + ErrorCode ret = ErrorCode::OK; + std::vector apdu; + CborConverter cborConverter; + std::unique_ptr item; + ret = constructApduMessage(ins, inData, apdu, extendedOutput); + if(ret != ErrorCode::OK) return ret; + + if(!pTransportFactory->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); + } + + if((response.size() > 2)) { + //Skip last 2 bytes in cborData, it contains status. + std::tie(item, ret) = cborConverter.decodeData(std::vector(response.begin(), response.end()-2), + true); + } else { + ret = ErrorCode::UNKNOWN_ERROR; + } + + return ret; +} + +void usage() { + printf("Usage:\n"); + printf("provision --attest_ids --shared_secret <32 bytes secret> --set_boot_params --lock_provision" + "--provision_status\n"); + printf("\n\n"); + printf("Options:\n"); + printf("-h, --help show this help message and exit.\n"); + printf("-a, --attest_ids FILE \n"); + printf("\t Syntax for attest_ids inside the file:\n"); + printf("\t brand=Google\n"); + printf("\t device=Pixel 3A\n"); + printf("\t product=Pixel\n"); + printf("\t serial=UGYJFDjFeRuBEH\n"); + printf("\t imei=987080543071019\n"); + printf("\t meid=27863510227963\n"); + printf("\t manufacturer=Foxconn\n"); + printf("\t model=HD1121\n"); + printf("-s, --shared_secret <32 bytes secret> \n"); + //TODO include set_boot_params + printf("\t The value of shared secret should be a 32 bytes in HEX\n"); + printf("-p, --provision_status Prints the provision status.\n"); + printf("-l, --lock_provision Locks the provision commands.\n"); +} + +bool provisionAttestationIds(const char* filename) { + CborConverter cborConverter; + cppbor::Array array; + Instruction ins = Instruction::INS_PROVISION_ATTEST_IDS_CMD; + ErrorCode errorCode = ErrorCode::OK; + std::vector response; + FILE *fp; + char tempChar; + int tempIndex = 0; + uint8_t buf[BUFFER_MAX_LENGTH]; + bool ret = true; + fp = fopen(filename, "rb"); + + if(fp == NULL) { + std::cout << "Failed to open file: " << filename; + return false; + } + std::vector params; + KeyParameter parameter; + Tag tag; + while((tempChar = fgetc(fp))) { + if (tempChar == '\n' || tempChar == EOF) { + buf[tempIndex] = '\0'; + tempIndex = 0; + if(0 != strlen((const char*)buf)) { + std::vector blob(buf, buf + strlen((const char*)buf)); + parameter.blob = std::move(blob); + params.push_back(parameter); + } + parameter = KeyParameter(); + // Decide to break or continue + if(tempChar == EOF) + break; + else + continue; + + } else if (tempChar == '=') { + buf[tempIndex] = '\0'; + tempIndex = 0; + if(Tag::INVALID == (tag = mapAttestKeyToAttestTag((const char*)buf))) { + ret = false; + printf("\n Invalid TAG \n"); + break; + } + parameter.tag = tag; + printf("Key: %s", buf); + continue; + } + buf[tempIndex++] = tempChar; + } + fclose(fp); + if(!ret) + return ret; + + hidl_vec attestParams(params); + + //Encode input data into CBOR. + cborConverter.addKeyparameters(array, attestParams); + std::vector cborData = array.encode(); + + if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { + ret = false; + printf("\n Failed to provision attestation ids error: %d\n", uint32_t(errorCode)); + } + return ret; +} + +bool lockProvision() { + bool ret = true; + cppbor::Array array; + Instruction ins = Instruction::INS_LOCK_PROVISIONING_CMD; + ErrorCode errorCode = ErrorCode::OK; + std::vector cborData; + std::vector response; + printf("\n lock provision\n"); + + + if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { + ret = false; + printf("\n Failed to lock provisioning error: %d\n", uint32_t(errorCode)); + } + return ret; +} + +bool getProvisionStatus() { + bool ret = true; + CborConverter cborConverter; + cppbor::Array array; + Instruction ins = Instruction::INS_GET_PROVISION_STATUS_CMD; + ErrorCode errorCode = ErrorCode::OK; + std::vector cborData; + std::vector response; + std::unique_ptr item; + printf("\nget provision sttus\n"); + + + if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { + ret = false; + printf("\n Failed to get provision status error: %d\n", uint32_t(errorCode)); + } + std::tie(item, errorCode) = cborConverter.decodeData(std::vector(response.begin(), response.end()-2), + true); + if(item != NULL) { + uint64_t status; + + if(!cborConverter.getUint64(item, 1, status)) { + ret = false; + printf("\n Failed to get the status value \n"); + } else { + printf("\n Current provision status: %ld", status); + } + } + return ret; +} + +bool provisionSharedSecret(const uint8_t* secret) { + bool ret = true; + cppbor::Array array; + Instruction ins = Instruction::INS_PROVISION_SHARED_SECRET_CMD; + ErrorCode errorCode = ErrorCode::OK; + std::vector response; + std::string str = hex2str(secret, strlen((const char*)secret)); + //Length of the secret should be 32 bytes. + if(32 != str.length()) { + return false; + } + std::vector input(str.data(), str.data() + str.length()); + + //Encode input data into CBOR. + array.add(input); + std::vector cborData = array.encode(); + + if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { + ret = false; + printf("\n Failed to provision shared secret error: %d\n", uint32_t(errorCode)); + } + return ret; +} + +int main(int argc, char* argv[]) +{ + int c; + struct option longOpts[] = { + {"attest_ids", required_argument, NULL, 'a'}, + {"shared_secret", required_argument, NULL, 's'}, + {"set_boot_params", required_argument, NULL, 'b'}, + {"provision_status", no_argument, NULL, 'p'}, + {"lock_provision", no_argument, NULL, 'l'}, + {"help", no_argument, NULL, 'h'}, + {0,0,0,0} + }; + sbKeymaster = IKeymasterDevice::getService(SB_KEYMASTER_SERVICE); + + if(NULL == sbKeymaster) { + printf("\n Failed to get StrongBox Keymaster service\n"); + exit(0); + } + pTransportFactory = getTransportFactoryInstance(); + if(NULL == pTransportFactory) { + printf("\n Failed to create transport factory\n"); + exit(0); + } + + if (argc <= 1) { + printf("\n Invalid command \n"); + usage(); + } + + /* getopt_long stores the option index here. */ + while ((c = getopt_long(argc, argv, ":plha:s:", longOpts, NULL)) != -1) { + switch(c) { + case 'a': + printf("\n attest_ids filename:%s\n", optarg); + provisionAttestationIds(optarg); + break; + case 's': + provisionSharedSecret((const uint8_t*)optarg); + break; + case 'p': + getProvisionStatus(); + break; + case 'l': + lockProvision(); + break; + case 'h': + usage(); + break; + case 0: + printf("\n set 0\n"); + break; + case ':': + printf("\n missing argument\n"); + usage(); + break; + case '?': + default: + printf("\n Invalid option\n"); + usage(); + break; + } + } + if(optind < argc) { + usage(); + } + return 0; +} diff --git a/HAL/keymaster/Android.bp b/HAL/keymaster/Android.bp index 8b34023d..0065f70c 100644 --- a/HAL/keymaster/Android.bp +++ b/HAL/keymaster/Android.bp @@ -14,6 +14,32 @@ // +cc_binary { + name: "provision_tool", + relative_install_path: "hw", + vendor: true, + srcs: [ + "4.1/provision_tool.cpp", + "4.1/CommonUtils.cpp", + "4.1/CborConverter.cpp", + ], + shared_libs: [ + "libdl", + "libcutils", + "libutils", + "libbase", + "libhardware", + "libhidlbase", + "libkeymaster_messages", + "libkeymaster_portable", + "android.hardware.keymaster@4.1", + "android.hardware.keymaster@4.0", + "libcppbor", + "libjc_transport", + "libcrypto", + ], +} + cc_binary { name: "android.hardware.keymaster@4.1-javacard.service", relative_install_path: "hw", From e6672fdb1fcb412cb6da4d9639bc06dd5c709ca2 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Wed, 9 Dec 2020 23:00:52 +0000 Subject: [PATCH 02/21] 1. Used libjsoncpp for parsing json file 2. taking input from json file 3. Added all the provisiong flow. --- HAL/keymaster/4.1/provision_tool.cpp | 692 ++++++++++++++++++++++----- HAL/keymaster/Android.bp | 1 + HAL/keymaster/sample_json.txt | 25 + 3 files changed, 593 insertions(+), 125 deletions(-) create mode 100644 HAL/keymaster/sample_json.txt diff --git a/HAL/keymaster/4.1/provision_tool.cpp b/HAL/keymaster/4.1/provision_tool.cpp index 2c9fb180..ce698375 100644 --- a/HAL/keymaster/4.1/provision_tool.cpp +++ b/HAL/keymaster/4.1/provision_tool.cpp @@ -16,17 +16,25 @@ */ #include +#include #include #include #include +#include +#include +#include +#include #include #include #include +#include #include #include #include #include #include +#include +#include #define BUFFER_MAX_LENGTH 256 #define SB_KEYMASTER_SERVICE "javacard" @@ -35,6 +43,8 @@ #define APDU_P1 0x40 #define APDU_P2 0x00 #define APDU_RESP_STATUS_OK 0x9000 +#define MAX_ATTEST_IDS_SIZE 8 +#define SHARED_SECRET_SIZE 32 enum class Instruction { // Provisioning commands @@ -60,6 +70,7 @@ enum ProvisionStatus { }; using ::android::hardware::keymaster::V4_0::ErrorCode; +using ::android::hardware::keymaster::V4_0::EcCurve; using ::android::hardware::keymaster::V4_0::HardwareAuthenticatorType; using ::android::hardware::keymaster::V4_0::HardwareAuthToken; using ::android::hardware::keymaster::V4_0::HmacSharingParameters; @@ -77,6 +88,7 @@ using se_transport::TransportFactory; static sp sbKeymaster; static TransportFactory *pTransportFactory; +Json::Value root; constexpr char hex_value[256] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // @@ -95,9 +107,9 @@ constexpr char hex_value[256] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -std::string hex2str(const uint8_t* a, size_t len) { +std::string hex2str(std::string a) { std::string b; - size_t num = len / 2; + size_t num = a.size() / 2; b.resize(num); for (size_t i = 0; i < num; i++) { b[i] = (hex_value[a[i * 2] & 0xFF] << 4) + (hex_value[a[i * 2 + 1] & 0xFF]); @@ -110,9 +122,103 @@ static ErrorCode constructApduMessage(Instruction& ins, std::vector& in extendedOutput); static ErrorCode sendProvisionData(Instruction ins, std::vector& inData, std::vector& response, bool extendedOutput); -static Tag mapAttestKeyToAttestTag(const char* key); +static Tag mapAttestKeyToAttestTag(std::string key); +bool parseJsonFile(const char* filename); +static bool readDataFromFile(const char *filename, std::vector& data) { + FILE *fp; + bool ret = true; + fp = fopen(filename, "rb"); + if(fp == NULL) { + printf("\nFailed to open file: \n"); + 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)) { + printf("\n No content in the file \n"); + ret = false; + } + if(true == ret) { + data.insert(data.end(), buf.get(), buf.get() + filesize); + } + fclose(fp); + return ret; +} + +static inline X509* parseDerCertificate(std::vector& certData) { + X509 *x509 = 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); +} static inline uint16_t getStatus(std::vector& inputData) { //Last two bytes are the status SW0SW1 @@ -128,10 +234,8 @@ static inline TransportFactory* getTransportFactoryInstance() { return pTransportFactory; } -static Tag mapAttestKeyToAttestTag(const char* key) { - //keymaster_tag_t tag = KM_TAG_INVALID; +static Tag mapAttestKeyToAttestTag(std::string keyStr) { Tag tag = Tag::INVALID; - std::string keyStr(key); if (0 == keyStr.compare("brand")) { tag = Tag::ATTESTATION_ID_BRAND; @@ -218,115 +322,205 @@ extendedOutput=false) { } void usage() { - printf("Usage:\n"); - printf("provision --attest_ids --shared_secret <32 bytes secret> --set_boot_params --lock_provision" - "--provision_status\n"); - printf("\n\n"); - printf("Options:\n"); + printf("Usage: provision_tool [options]\n"); + printf("Valid options are:\n"); printf("-h, --help show this help message and exit.\n"); - printf("-a, --attest_ids FILE \n"); - printf("\t Syntax for attest_ids inside the file:\n"); - printf("\t brand=Google\n"); - printf("\t device=Pixel 3A\n"); - printf("\t product=Pixel\n"); - printf("\t serial=UGYJFDjFeRuBEH\n"); - printf("\t imei=987080543071019\n"); - printf("\t meid=27863510227963\n"); - printf("\t manufacturer=Foxconn\n"); - printf("\t model=HD1121\n"); - printf("-s, --shared_secret <32 bytes secret> \n"); - //TODO include set_boot_params - printf("\t The value of shared secret should be a 32 bytes in HEX\n"); - printf("-p, --provision_status Prints the provision status.\n"); - printf("-l, --lock_provision Locks the provision commands.\n"); + printf("-a, --all jsonFile \t Executes all the provision commands \n"); + printf("-k, --attest_key jsonFile \t Provision attestation key \n"); + printf("-c, --cert_chain jsonFile \t Provision attestation certificate chain \n"); + printf("-p, --cert_params jsonFile \t Provision attestation certificate parameters \n"); + printf("-i, --attest_ids jsonFile \t Provision attestation IDs \n"); + printf("-r, --shared_secret jsonFile \t Provion shared secret \n"); + printf("-b, --set_boot_params jsonFile \t Provion boot parameters \n"); + printf("-s, --provision_status \t Prints the provision status.\n"); + printf("-l, --lock_provision \t Locks the provision commands.\n"); } -bool provisionAttestationIds(const char* filename) { - CborConverter cborConverter; - cppbor::Array array; - Instruction ins = Instruction::INS_PROVISION_ATTEST_IDS_CMD; - ErrorCode errorCode = ErrorCode::OK; - std::vector response; - FILE *fp; - char tempChar; - int tempIndex = 0; - uint8_t buf[BUFFER_MAX_LENGTH]; - bool ret = true; - fp = fopen(filename, "rb"); - - if(fp == NULL) { - std::cout << "Failed to open file: " << filename; - return false; - } - std::vector params; - KeyParameter parameter; - Tag tag; - while((tempChar = fgetc(fp))) { - if (tempChar == '\n' || tempChar == EOF) { - buf[tempIndex] = '\0'; - tempIndex = 0; - if(0 != strlen((const char*)buf)) { - std::vector blob(buf, buf + strlen((const char*)buf)); - parameter.blob = std::move(blob); - params.push_back(parameter); - } - parameter = KeyParameter(); - // Decide to break or continue - if(tempChar == EOF) +bool getBootParameterIntValue(Json::Value& bootParamsObj, const char* key, uint32_t *value) { + bool ret = false; + Json::Value val = bootParamsObj[key]; + if(val.empty()) + return ret; + + if(!val.isInt()) + return ret; + + *value = (uint32_t)val.asInt(); + + return true; +} + +bool getBootParameterBlobValue(Json::Value& bootParamsObj, const char* key, std::vector& blob) { + bool ret = false; + Json::Value val = bootParamsObj[key]; + if(val.empty()) + return ret; + + if(!val.isString()) + return ret; + + std::string blobStr = hex2str(val.asString()); + + for(char ch : blobStr) { + blob.push_back((uint8_t)ch); + } + + return true; +} + +bool setBootParameters(const char* filename) { + Json::Value bootParamsObj; + bool ret = false; + + if(!parseJsonFile(filename)) + return ret; + + bootParamsObj = root.get("set_boot_params", bootParamsObj); + if (!bootParamsObj.isNull()) { + cppbor::Array array; + ErrorCode errorCode = ErrorCode::OK; + std::vector apdu; + std::vector response; + Instruction ins = Instruction::INS_SET_BOOT_PARAMS_CMD; + uint32_t value; + std::vector blob; + + if(!getBootParameterIntValue(bootParamsObj, "os_version", &value)) { + printf("\n Invalid value for os_version or os_version tag missing\n"); + return ret; + } + array.add(value); + if(!getBootParameterIntValue(bootParamsObj, "os_patch_level", &value)) { + printf("\n Invalid value for os_patch_level or os_patch_level tag missing\n"); + return ret; + } + array.add(value); + if(!getBootParameterIntValue(bootParamsObj, "vendor_patch_level", &value)) { + printf("\n Invalid value for vendor_patch_level or vendor_patch_level tag missing\n"); + return ret; + } + array.add(value); + if(!getBootParameterIntValue(bootParamsObj, "boot_patch_level", &value)) { + printf("\n Invalid value for boot_patch_level or boot_patch_level tag missing\n"); + return ret; + } + array.add(value); + if(!getBootParameterBlobValue(bootParamsObj, "verified_boot_key", blob)) { + printf("\n Invalid value for verified_boot_key or verified_boot_key tag missing\n"); + return ret; + } + array.add(blob); + blob.clear(); + if(!getBootParameterBlobValue(bootParamsObj, "verified_boot_key_hash", blob)) { + printf("\n Invalid value for verified_boot_key_hash or verified_boot_key_hash tag missing\n"); + return ret; + } + array.add(blob); + blob.clear(); + if(!getBootParameterIntValue(bootParamsObj, "boot_state", &value)) { + printf("\n Invalid value for boot_state or boot_state tag missing\n"); + return ret; + } + array.add(value); + if(!getBootParameterIntValue(bootParamsObj, "device_locked", &value)) { + printf("\n Invalid value for device_locked or device_locked tag missing\n"); + return ret; + } + array.add(value); + + std::vector cborData = array.encode(); + + if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { + printf("\n Failed to set boot parameters errorCode:%d\n", errorCode); + return ret; + } + + } else { + return ret; + } + printf("\n SE successfully accepted boot paramters \n"); + return true; +} + +bool provisionAttestationIds(const char *filename) { + Json::Value attestIds; + bool ret = false; + + if(!parseJsonFile(filename)) + return ret; + + attestIds = root.get("attest_ids", attestIds); + if (!attestIds.isNull()) { + if (attestIds.size() != MAX_ATTEST_IDS_SIZE) { + return ret; + } + Json::Value value; + std::vector temp; + int i = 0; + std::vector params(attestIds.size()); + Json::Value::Members keys = attestIds.getMemberNames(); + Tag tag; + for(std::string key : keys) { + if(Tag::INVALID == (tag = mapAttestKeyToAttestTag(key))) { break; - else - continue; - - } else if (tempChar == '=') { - buf[tempIndex] = '\0'; - tempIndex = 0; - if(Tag::INVALID == (tag = mapAttestKeyToAttestTag((const char*)buf))) { - ret = false; - printf("\n Invalid TAG \n"); + } + value = attestIds[key]; + if(value.empty()) { break; } - parameter.tag = tag; - printf("Key: %s", buf); - continue; + params[i].tag = tag; + for(char ch : value.asString()) { + temp.push_back((uint8_t)ch); + } + params[i].blob.resize(temp.size()); + params[i].blob = temp; + temp.clear(); + i++; } - buf[tempIndex++] = tempChar; - } - fclose(fp); - if(!ret) - return ret; - hidl_vec attestParams(params); + if(i != MAX_ATTEST_IDS_SIZE) + return ret; - //Encode input data into CBOR. - cborConverter.addKeyparameters(array, attestParams); - std::vector cborData = array.encode(); + CborConverter cborConverter; + cppbor::Array array; + Instruction ins = Instruction::INS_PROVISION_ATTEST_IDS_CMD; + ErrorCode errorCode = ErrorCode::OK; + std::vector response; + hidl_vec attestParams(params); - if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { - ret = false; - printf("\n Failed to provision attestation ids error: %d\n", uint32_t(errorCode)); + //Encode input data into CBOR. + cborConverter.addKeyparameters(array, attestParams); + std::vector cborData = array.encode(); + + if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { + printf("\n Failed to provision attestation ids error: %d\n", uint32_t(errorCode)); + return ret; + } + } else { + return ret; } - return ret; + printf("\n provisioned attestation ids successfully \n"); + return true; } bool lockProvision() { - bool ret = true; + bool ret = false; cppbor::Array array; Instruction ins = Instruction::INS_LOCK_PROVISIONING_CMD; ErrorCode errorCode = ErrorCode::OK; std::vector cborData; std::vector response; - printf("\n lock provision\n"); - if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { - ret = false; printf("\n Failed to lock provisioning error: %d\n", uint32_t(errorCode)); + return ret; } - return ret; + printf("\n Successfully locked provisioning process. Now SE doesn't accept any further provision commands. \n"); + return true; } bool getProvisionStatus() { - bool ret = true; + bool ret = false; CborConverter cborConverter; cppbor::Array array; Instruction ins = Instruction::INS_GET_PROVISION_STATUS_CMD; @@ -334,12 +528,10 @@ bool getProvisionStatus() { std::vector cborData; std::vector response; std::unique_ptr item; - printf("\nget provision sttus\n"); - if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { - ret = false; printf("\n Failed to get provision status error: %d\n", uint32_t(errorCode)); + return ret; } std::tie(item, errorCode) = cborConverter.decodeData(std::vector(response.begin(), response.end()-2), true); @@ -347,53 +539,287 @@ bool getProvisionStatus() { uint64_t status; if(!cborConverter.getUint64(item, 1, status)) { - ret = false; printf("\n Failed to get the status value \n"); + return ret; } else { - printf("\n Current provision status: %ld", status); + printf("\nCurrent provision status: %ld\n", status); } + } else { + return ret; } - return ret; + return true; } -bool provisionSharedSecret(const uint8_t* secret) { - bool ret = true; - cppbor::Array array; - Instruction ins = Instruction::INS_PROVISION_SHARED_SECRET_CMD; - ErrorCode errorCode = ErrorCode::OK; - std::vector response; - std::string str = hex2str(secret, strlen((const char*)secret)); - //Length of the secret should be 32 bytes. - if(32 != str.length()) { +bool provisionSharedSecret(const char* filename) { + Json::Value sharedSecret; + bool ret = false; + + if(!parseJsonFile(filename)) + return ret; + + sharedSecret = root.get("shared_secret", sharedSecret); + if (!sharedSecret.isNull()) { + cppbor::Array array; + Instruction ins = Instruction::INS_PROVISION_SHARED_SECRET_CMD; + ErrorCode errorCode = ErrorCode::OK; + std::vector response; + std::string str = sharedSecret.asString(); + std::string secret = hex2str(str); + + //Length of the secret should be 32 bytes. + if(SHARED_SECRET_SIZE != secret.size()) { + return ret; + } + std::vector input(secret.data(), secret.data() + secret.length()); + + //Encode input data into CBOR. + array.add(input); + std::vector cborData = array.encode(); + + if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { + printf("\n Failed to provision shared secret error: %d\n", uint32_t(errorCode)); + return ret; + } + } else { + return ret; + } + printf("\n Provisioned shared secret successfully \n"); + return true; +} + +static bool provisionAttestationKey(const char* filename) { + Json::Value keyFile; + bool ret = false; + + if(!parseJsonFile(filename)) + return ret; + + keyFile = root.get("attest_key", keyFile); + if (!keyFile.isNull()) { + ErrorCode errorCode = ErrorCode::OK; + CborConverter cborConverter; + cppbor::Array array; + cppbor::Array subArray; + std::vector data; + std::vector privKey; + std::vector pubKey; + Instruction ins = Instruction::INS_PROVISION_ATTESTATION_KEY_CMD; + EcCurve curve; + std::vector response; + + std::string keyFileName = keyFile.asString(); + if(!readDataFromFile(keyFileName.data(), data)) { + printf("\n Failed to read the Root ec key\n"); + return ret; + } + keymaster::AuthorizationSet authSetKeyParams(keymaster::AuthorizationSetBuilder() + .Authorization(keymaster::TAG_ALGORITHM, KM_ALGORITHM_EC) + .Authorization(keymaster::TAG_DIGEST, KM_DIGEST_SHA_2_256) + .Authorization(keymaster::TAG_EC_CURVE, KM_EC_CURVE_P_256) + .Authorization(keymaster::TAG_PURPOSE, static_cast(0x7F))); /* The value 0x7F is not present in types.hal */ + // Read the ECKey from the file. + hidl_vec keyParams = keymaster::V4_1::javacard::kmParamSet2Hidl(authSetKeyParams); + + if(ErrorCode::OK != (errorCode = keymaster::V4_1::javacard::ecRawKeyFromPKCS8(data, privKey, pubKey, curve))) { + printf("\n Failed to convert PKCS8 to RAW key\n"); + return ret; + } + subArray.add(privKey); + subArray.add(pubKey); + std::vector encodedArray = subArray.encode(); + cppbor::Bstr bstr(encodedArray.begin(), encodedArray.end()); + + //Encode data. + cborConverter.addKeyparameters(array, keyParams); + array.add(static_cast(KeyFormat::RAW)); + array.add(bstr); + + std::vector cborData = array.encode(); + + if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { + printf("\n Failed to provision attestation key\n"); + return ret; + } + } else { + return ret; + } + printf("\n Provisioned attestation key successfully\n"); + return true; +} + +bool provisionAttestationCertificateChain(const char* filename) { + Json::Value certChainFile; + bool ret = false; + + if(!parseJsonFile(filename)) + return ret; + + certChainFile = root.get("attest_cert_chain", certChainFile); + if (!certChainFile.isNull()) { + ErrorCode errorCode = ErrorCode::OK; + cppbor::Array array; + Instruction ins = Instruction::INS_PROVISION_CERT_CHAIN_CMD; + std::vector response; + + std::vector certData; + std::string strCertChain = certChainFile.asString(); + /* Read the Root certificate */ + if(!readDataFromFile(strCertChain.data(), certData)) { + printf("\n Failed to read the Root certificate\n"); + return ret; + } + cppbor::Bstr certChain(certData.begin(), certData.end()); + std::vector cborData = certChain.encode(); + + if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { + printf("\n Failed to provision cert chain errorCode:%d\n", static_cast(errorCode)); + return ret; + } + } else { + return ret; + } + printf("\n Provisioned attestation certificate chain successfully\n"); + return true; +} + +bool provisionAttestationCertificateParams(const char* filename) { + Json::Value certChainFile; + bool ret = false; + + if(!parseJsonFile(filename)) + return ret; + + certChainFile = root.get("attest_cert_chain", certChainFile); + if (!certChainFile.isNull()) { + ErrorCode errorCode = ErrorCode::OK; + cppbor::Array array; + Instruction ins = Instruction::INS_PROVISION_CERT_PARAMS_CMD; + std::vector response; + X509 *x509 = NULL; + std::vector subject; + std::vector authorityKeyIdentifier; + std::vector notAfter; + std::vector certData; + std::vector> certChain; + + + std::string strCertChain = certChainFile.asString(); + /* Read the Root certificate */ + if(!readDataFromFile(strCertChain.data(), certData)) { + printf("\n Failed to read the Root certificate\n"); + return ret; + } + + // Get first certificate from chain of certificates. + if(ErrorCode::OK != (errorCode =keymaster::V4_1::javacard::getCertificateChain(certData, certChain))) { + printf("\n Failed to parse the certificate chain \n"); + return ret; + } + + if(certChain.size() == 0) { + printf("\n Length of the certificate chain is 0\n"); + return ret; + } + + + /* 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(certChain[0]))) { + printf("\n Failed to parse the DER certificate \n"); + return ret; + } + + /* Get subject in DER */ + getDerSubjectName(x509, subject); + /* Get AuthorityKeyIdentifier */ + getAuthorityKeyIdentifier(x509, authorityKeyIdentifier); + /* Get Expirty Time */ + getNotAfter(x509, notAfter); + /*Free X509 */ + X509_free(x509); + + array.add(subject); + array.add(notAfter); + array.add(authorityKeyIdentifier); + std::vector cborData = array.encode(); + + if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { + printf("\n Failed to provision cert params errorCode:%d\n", static_cast(errorCode)); + return ret; + } + } else { + return ret; + } + printf("\n Provisioned attestation certificate parameters successfully\n"); + return true; +} + +bool provision(const char* filename) { + + if(!provisionAttestationKey(filename)) { + printf("\n Failed to provision attestation Key\n"); + return false; + } + if(!provisionAttestationCertificateChain(filename)) { + printf("\n Failed to provision certificate chain\n"); + return false; + } + if(!provisionAttestationCertificateParams(filename)) { + printf("\n Failed to provision certificate paramters\n"); return false; } - std::vector input(str.data(), str.data() + str.length()); + if(!provisionSharedSecret(filename)) { + printf("\n Failed to provision shared secret\n"); + return false; + } + if(!provisionAttestationIds(filename)) { + printf("\n Failed to provision attestation ids\n"); + return false; + } + if(!setBootParameters(filename)) { + printf("\n Failed to set boot parameters\n"); + return false; + } + return true; +} - //Encode input data into CBOR. - array.add(input); - std::vector cborData = array.encode(); +bool parseJsonFile(const char* filename) { + std::stringstream buffer; + Json::Reader jsonReader; - if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { - ret = false; - printf("\n Failed to provision shared secret error: %d\n", uint32_t(errorCode)); + if(!root.empty()) { + printf("\n Already parsed \n"); + return true; + } + std::ifstream stream(filename); + buffer << stream.rdbuf(); + if(jsonReader.parse(buffer.str(), root)) { + printf("\n Parsed json file successfully\n"); + return true; + } else { + printf("\n Failed to parse json file\n"); + return false; } - return ret; } int main(int argc, char* argv[]) { int c; struct option longOpts[] = { - {"attest_ids", required_argument, NULL, 'a'}, - {"shared_secret", required_argument, NULL, 's'}, + {"all", required_argument, NULL, 'a'}, + {"attest_key", required_argument, NULL, 'k'}, + {"cert_chain", required_argument, NULL, 'c'}, + {"cert_params", required_argument, NULL,'p'}, + {"attest_ids", required_argument, NULL, 'i'}, + {"shared_secret", required_argument, NULL, 'r'}, {"set_boot_params", required_argument, NULL, 'b'}, - {"provision_status", no_argument, NULL, 'p'}, + {"provision_status", no_argument, NULL, 's'}, {"lock_provision", no_argument, NULL, 'l'}, {"help", no_argument, NULL, 'h'}, {0,0,0,0} }; - sbKeymaster = IKeymasterDevice::getService(SB_KEYMASTER_SERVICE); + sbKeymaster = IKeymasterDevice::getService(SB_KEYMASTER_SERVICE); if(NULL == sbKeymaster) { printf("\n Failed to get StrongBox Keymaster service\n"); exit(0); @@ -410,16 +836,35 @@ int main(int argc, char* argv[]) } /* getopt_long stores the option index here. */ - while ((c = getopt_long(argc, argv, ":plha:s:", longOpts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, ":slha:k:c:p:i:r:b:", longOpts, NULL)) != -1) { switch(c) { - case 'a': - printf("\n attest_ids filename:%s\n", optarg); + case 'a': + //all + provision(optarg); + break; + case 'k': + //attest key + provisionAttestationKey(optarg); + break; + case 'c': + //attest certchain + provisionAttestationCertificateChain(optarg); + break; + case 'p': + //attest cert params + provisionAttestationCertificateParams(optarg); + break; + case 'i': provisionAttestationIds(optarg); break; - case 's': - provisionSharedSecret((const uint8_t*)optarg); + case 'r': + provisionSharedSecret(optarg); break; - case 'p': + case 'b': + //set boot params + setBootParameters(optarg); + break; + case 's': getProvisionStatus(); break; case 'l': @@ -428,9 +873,6 @@ int main(int argc, char* argv[]) case 'h': usage(); break; - case 0: - printf("\n set 0\n"); - break; case ':': printf("\n missing argument\n"); usage(); diff --git a/HAL/keymaster/Android.bp b/HAL/keymaster/Android.bp index 0065f70c..c8ccb497 100644 --- a/HAL/keymaster/Android.bp +++ b/HAL/keymaster/Android.bp @@ -37,6 +37,7 @@ cc_binary { "libcppbor", "libjc_transport", "libcrypto", + "libjsoncpp", ], } diff --git a/HAL/keymaster/sample_json.txt b/HAL/keymaster/sample_json.txt new file mode 100644 index 00000000..b65164aa --- /dev/null +++ b/HAL/keymaster/sample_json.txt @@ -0,0 +1,25 @@ +{ + "attest_ids": { + "brand": "Google", + "device": "Pixel 3A", + "product": "Pixel", + "serial": "UGYJFDjFeRuBEH", + "imei": "987080543071019", + "meid": "27863510227963", + "manufacturer": "Foxconn", + "model": "HD1121" + }, + "shared_secret": "0000000000000000000000000000000000000000000000000000000000000000", + "set_boot_params": { + "os_version": 100, + "os_patch_level": 100, + "vendor_patch_level": 0, + "boot_patch_level": 0, + "verified_boot_key": "0000000000000000000000000000000000000000000000000000000000000000", + "verified_boot_key_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "boot_state": 0, + "device_locked": 0 + }, + "attest_key": "/data/data/ec_key.der", + "attest_cert_chain": "/data/data/ec_cert_chain.der" +} From a25e9c0e2e94a6607e7b7b6d24c228f7f9ab169f Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Thu, 14 Jan 2021 19:51:33 +0530 Subject: [PATCH 03/21] updated provisioning tool --- .../4.1/JavacardKeymaster4Device.cpp | 1 - HAL/keymaster/Android.bp | 62 ++++++++++--------- provisioning_tool/Android.bp | 41 ++++++++++++ provisioning_tool/README.md | 1 + .../provision_tool.cpp | 3 +- provisioning_tool/sample_json.txt | 25 ++++++++ 6 files changed, 102 insertions(+), 31 deletions(-) create mode 100644 provisioning_tool/Android.bp create mode 100644 provisioning_tool/README.md rename {HAL/keymaster/4.1 => provisioning_tool}/provision_tool.cpp (99%) create mode 100644 provisioning_tool/sample_json.txt diff --git a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp index 23583024..08c634ca 100644 --- a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp +++ b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp @@ -266,7 +266,6 @@ ErrorCode sendData(Instruction ins, std::vector& inData, std::vector Date: Mon, 25 Jan 2021 13:59:38 +0530 Subject: [PATCH 04/21] make provision as separate library --- .../4.1/JavacardKeymaster4Device.cpp | 65 +- HAL/keymaster/4.1/Provision.cpp | 264 ++------ HAL/keymaster/Android.bp | 7 +- HAL/keymaster/include/Provision.h | 41 +- provisioning_tool/Android.bp | 2 +- provisioning_tool/provision_tool.cpp | 634 +++++------------- provisioning_tool/sample_json.txt | 7 +- 7 files changed, 339 insertions(+), 681 deletions(-) diff --git a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp index 27f32150..3086e287 100644 --- a/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp +++ b/HAL/keymaster/4.1/JavacardKeymaster4Device.cpp @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -91,7 +90,19 @@ enum class Instruction { INS_ABORT_OPERATION_CMD = INS_END_KM_PROVISION_CMD+19, INS_DEVICE_LOCKED_CMD = INS_END_KM_PROVISION_CMD+20, INS_EARLY_BOOT_ENDED_CMD = INS_END_KM_PROVISION_CMD+21, - INS_GET_CERT_CHAIN_CMD = INS_END_KM_PROVISION_CMD+22 + INS_GET_CERT_CHAIN_CMD = INS_END_KM_PROVISION_CMD+22, + INS_GET_PROVISION_STATUS_CMD = INS_BEGIN_KM_CMD+8, +}; + +enum ProvisionStatus { + NOT_PROVISIONED = 0x00, + PROVISION_STATUS_ATTESTATION_KEY = 0x01, + PROVISION_STATUS_ATTESTATION_CERT_CHAIN = 0x02, + PROVISION_STATUS_ATTESTATION_CERT_PARAMS = 0x04, + PROVISION_STATUS_ATTEST_IDS = 0x08, + PROVISION_STATUS_PRESHARED_SECRET = 0x10, + PROVISION_STATUS_BOOT_PARAM = 0x20, + PROVISION_STATUS_PROVISIONING_LOCKED = 0x40, }; //Extended error codes @@ -368,15 +379,57 @@ uint16_t getStatus(std::vector& inputData) { return (inputData.at(inputData.size()-2) << 8) | (inputData.at(inputData.size()-1)); } +static bool isSEProvisioned() { + ErrorCode errorCode = ErrorCode::OK; + Instruction ins = Instruction::INS_GET_PROVISION_STATUS_CMD; + std::vector cborData; + std::vector response; + std::unique_ptr item; + CborConverter cborConverter; + std::vector apdu; + bool ret = false; + + errorCode = constructApduMessage(ins, cborData, apdu); + if(errorCode != ErrorCode::OK) return ret; + + if(!getTransportFactoryInstance()->sendData(apdu.data(), apdu.size(), response)) { + LOG(ERROR) << " Failed to send GET_PROVISION_STATUS_CMD "; + return ret; + } + + if((response.size() <= 2) || (getStatus(response) != APDU_RESP_STATUS_OK)) { + return ret; + } + //Check if SE is provisioned. + std::tie(item, errorCode) = cborConverter.decodeData(std::vector(response.begin(), response.end()-2), + true); + if(item != NULL) { + uint64_t status; + + if(!cborConverter.getUint64(item, 1, status)) { + LOG(ERROR) << "Failed to parse the status from cbor data"; + return ret; + } + + if ( (0 != (status & ProvisionStatus::PROVISION_STATUS_ATTESTATION_KEY)) && + (0 != (status & ProvisionStatus::PROVISION_STATUS_ATTESTATION_CERT_CHAIN)) && + (0 != (status & ProvisionStatus::PROVISION_STATUS_ATTESTATION_CERT_PARAMS)) && + (0 != (status & ProvisionStatus::PROVISION_STATUS_PRESHARED_SECRET)) && + (0 != (status & ProvisionStatus::PROVISION_STATUS_BOOT_PARAM))) { + ret = true; + } + } + return ret; +} + + ErrorCode sendData(Instruction ins, std::vector& inData, std::vector& response, bool extendedOutput=false) { ErrorCode ret = ErrorCode::UNKNOWN_ERROR; std::vector apdu; - // TODO In real scenario the provision happens in the factory. In that case this - // below code is not required. This is just used for simulation. - if (ErrorCode::OK != (ret = provision(getTransportFactoryInstance()))) { - LOG(ERROR) << "Failed to provision the device"; + if (!isSEProvisioned()) { + LOG(ERROR) << "Javacard applet is not provisioned."; return ret; } ret = constructApduMessage(ins, inData, apdu, extendedOutput); diff --git a/HAL/keymaster/4.1/Provision.cpp b/HAL/keymaster/4.1/Provision.cpp index 24f65667..a896db88 100644 --- a/HAL/keymaster/4.1/Provision.cpp +++ b/HAL/keymaster/4.1/Provision.cpp @@ -28,10 +28,8 @@ #include #include #include + #include -#define ROOT_EC_KEY "/data/data/ec_key.der" -#define INTERMEDIATE_EC_CERT "/data/data/ec_cert.der" -#define ROOT_EC_CERT "/data/data/ec_root_cert.der" #define INS_BEGIN_KM_CMD 0x00 #define APDU_CLS 0x80 #define APDU_P1 0x40 @@ -42,7 +40,6 @@ namespace keymaster { namespace V4_1 { namespace javacard { -constexpr uint8_t kFakeKeyAgreementKey[32] = {}; enum class Instruction { // Provisioning commands INS_PROVISION_ATTESTATION_KEY_CMD = INS_BEGIN_KM_CMD+1, @@ -67,32 +64,15 @@ enum ProvisionStatus { }; // Static function declarations. -static bool readDataFromFile(const char *filename, std::vector& data); static ErrorCode constructApduMessage(Instruction& ins, std::vector& inputData, std::vector& apduOut, bool extendedOutput=false); static ErrorCode sendProvisionData(std::unique_ptr& transport, Instruction ins, std::vector& inData, std::vector& response, bool extendedOutput = false); -static ErrorCode provisionAttestationKey(std::unique_ptr& transport); -static ErrorCode provisionAttestationCertificateChain(std::unique_ptr& transport); -static ErrorCode provisionAttestationCertificateParams(std::unique_ptr& transport); -static ErrorCode provisionAttestationIDs(std::unique_ptr& transport); -static ErrorCode provisionSharedSecret(std::unique_ptr& transport); -static ErrorCode getProvisionStatus(std::unique_ptr& transport, std::vector& -response); -static ErrorCode lockProvision(std::unique_ptr& transport); -static ErrorCode setBootParameters(std::unique_ptr& transport); static uint16_t getStatus(std::vector& inputData); -static bool isSEProvisioned(uint64_t status); -static inline X509* parseDerCertificate(const char* filename) { +static inline X509* parseDerCertificate(std::vector& certData) { 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) { @@ -145,30 +125,6 @@ static uint16_t getStatus(std::vector& inputData) { return (inputData.at(inputData.size()-2) << 8) | (inputData.at(inputData.size()-1)); } -static 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); - data.insert(data.end(), buf.get(), buf.get() + filesize); - } - fclose(fp); - return ret; -} - static ErrorCode constructApduMessage(Instruction& ins, std::vector& inputData, std::vector& apduOut, bool extendedOutput) { apduOut.push_back(static_cast(APDU_CLS)); //CLS @@ -235,77 +191,73 @@ extendedOutput) { return ret; } -static ErrorCode provisionAttestationKey(std::unique_ptr& transport) { +// Class Provision Start + +ErrorCode Provision::initProvision() { + if(pTransportFactory == nullptr) { + pTransportFactory = std::unique_ptr(new se_transport::TransportFactory( + android::base::GetBoolProperty("ro.kernel.qemu", false))); + pTransportFactory->openConnection(); + } + return ErrorCode::OK; +} + +ErrorCode Provision::provisionAttestationKey(std::vector& batchKey) { ErrorCode errorCode = ErrorCode::OK; - CborConverter cborConverter; - cppbor::Array array; - cppbor::Array subArray; - std::vector data; std::vector privKey; std::vector pubKey; - Instruction ins = Instruction::INS_PROVISION_ATTESTATION_KEY_CMD; EcCurve curve; + CborConverter cborConverter; + cppbor::Array array; + cppbor::Array subArray; std::vector response; + Instruction ins = Instruction::INS_PROVISION_ATTESTATION_KEY_CMD; AuthorizationSet authSetKeyParams(AuthorizationSetBuilder() .Authorization(TAG_ALGORITHM, KM_ALGORITHM_EC) .Authorization(TAG_DIGEST, KM_DIGEST_SHA_2_256) .Authorization(TAG_EC_CURVE, KM_EC_CURVE_P_256) .Authorization(TAG_PURPOSE, static_cast(0x7F))); /* The value 0x7F is not present in types.hal */ - // Read the ECKey from the file. hidl_vec keyParams = kmParamSet2Hidl(authSetKeyParams); - - if(!readDataFromFile(ROOT_EC_KEY, data)) { - LOG(ERROR) << " Failed to read the Root rsa key"; - return ErrorCode::UNKNOWN_ERROR; - } - if(ErrorCode::OK != (errorCode = ecRawKeyFromPKCS8(data, privKey, pubKey, curve))) { + if(ErrorCode::OK != (errorCode = ecRawKeyFromPKCS8(batchKey, privKey, pubKey, curve))) { return errorCode; } subArray.add(privKey); subArray.add(pubKey); std::vector encodedArray = subArray.encode(); cppbor::Bstr bstr(encodedArray.begin(), encodedArray.end()); - //Encode data. cborConverter.addKeyparameters(array, keyParams); array.add(static_cast(KeyFormat::RAW)); array.add(bstr); std::vector cborData = array.encode(); - - if(ErrorCode::OK != (errorCode = sendProvisionData(transport, ins, cborData, response))) { + if(ErrorCode::OK != (errorCode = sendProvisionData(pTransportFactory, ins, cborData, response))) { return errorCode; } return errorCode; } -static ErrorCode provisionAttestationCertificateChain(std::unique_ptr& transport) { +ErrorCode Provision::provisionAtestationCertificateChain(std::vector>& certChain) { ErrorCode errorCode = ErrorCode::OK; cppbor::Array array; Instruction ins = Instruction::INS_PROVISION_CERT_CHAIN_CMD; std::vector response; std::vector certData; - /* Read the Root certificate */ - if(!readDataFromFile(INTERMEDIATE_EC_CERT, certData)) { - LOG(ERROR) << " Failed to read the Root certificate"; - return (ErrorCode::UNKNOWN_ERROR); + for (auto data : certChain) { + certData.insert(certData.end(), data.begin(), data.end()); } - if(!readDataFromFile(ROOT_EC_CERT, certData)) { - LOG(ERROR) << " Failed to read the Root certificate"; - return (ErrorCode::UNKNOWN_ERROR); - } - cppbor::Bstr certChain(certData.begin(), certData.end()); - std::vector cborData = certChain.encode(); + cppbor::Bstr bstrCertChain(certData.begin(), certData.end()); + std::vector cborData = bstrCertChain.encode(); - if(ErrorCode::OK != (errorCode = sendProvisionData(transport, ins, cborData, response))) { + if(ErrorCode::OK != (errorCode = sendProvisionData(pTransportFactory, ins, cborData, response))) { return errorCode; } return errorCode; } -static ErrorCode provisionAttestationCertificateParams(std::unique_ptr& transport) { +ErrorCode Provision::provisionAttestationCertificateParams(std::vector& batchCertificate) { ErrorCode errorCode = ErrorCode::OK; cppbor::Array array; Instruction ins = Instruction::INS_PROVISION_CERT_PARAMS_CMD; @@ -316,7 +268,7 @@ static ErrorCode provisionAttestationCertificateParams(std::unique_ptr cborData = array.encode(); - if(ErrorCode::OK != (errorCode = sendProvisionData(transport, ins, cborData, response))) { + if(ErrorCode::OK != (errorCode = sendProvisionData(pTransportFactory, ins, cborData, response))) { return errorCode; } return errorCode; } - -static ErrorCode provisionAttestationIDs(std::unique_ptr& transport) { +ErrorCode Provision::provisionAttestationID(AttestIDParams& attestParams) { ErrorCode errorCode = ErrorCode::OK; CborConverter cborConverter; cppbor::Array array; Instruction ins = Instruction::INS_PROVISION_ATTEST_IDS_CMD; std::vector response; - std::string brand("Google"); - std::string device("Pixel 3A"); - std::string product("Pixel"); - std::string serial("UGYJFDjFeRuBEH"); - std::string imei("987080543071019"); - std::string meid("27863510227963"); - std::string manufacturer("Foxconn"); - std::string model("HD1121"); - AuthorizationSet authSetAttestParams(AuthorizationSetBuilder() - .Authorization(TAG_ATTESTATION_ID_BRAND, brand.data(), brand.size()) - .Authorization(TAG_ATTESTATION_ID_DEVICE, device.data(), device.size()) - .Authorization(TAG_ATTESTATION_ID_PRODUCT, product.data(), product.size()) - .Authorization(TAG_ATTESTATION_ID_SERIAL, serial.data(), serial.size()) - .Authorization(TAG_ATTESTATION_ID_IMEI, imei.data(), imei.size()) - .Authorization(TAG_ATTESTATION_ID_MEID, meid.data(), meid.size()) - .Authorization(TAG_ATTESTATION_ID_MANUFACTURER, manufacturer.data(), manufacturer.size()) - .Authorization(TAG_ATTESTATION_ID_MODEL, model.data(), model.size())); + .Authorization(TAG_ATTESTATION_ID_BRAND, attestParams.brand.data(), attestParams.brand.size()) + .Authorization(TAG_ATTESTATION_ID_DEVICE, attestParams.device.data(), attestParams.device.size()) + .Authorization(TAG_ATTESTATION_ID_PRODUCT, attestParams.product.data(), attestParams.product.size()) + .Authorization(TAG_ATTESTATION_ID_SERIAL, attestParams.serial.data(), attestParams.serial.size()) + .Authorization(TAG_ATTESTATION_ID_IMEI, attestParams.imei.data(), attestParams.imei.size()) + .Authorization(TAG_ATTESTATION_ID_MEID, attestParams.meid.data(), attestParams.meid.size()) + .Authorization(TAG_ATTESTATION_ID_MANUFACTURER, attestParams.manufacturer.data(), attestParams.manufacturer.size()) + .Authorization(TAG_ATTESTATION_ID_MODEL, attestParams.model.data(), attestParams.model.size())); - hidl_vec attestParams = kmParamSet2Hidl(authSetAttestParams); + hidl_vec attestKeyParams = kmParamSet2Hidl(authSetAttestParams); array = cppbor::Array(); - cborConverter.addKeyparameters(array, attestParams); + cborConverter.addKeyparameters(array, attestKeyParams); std::vector cborData = array.encode(); - if(ErrorCode::OK != (errorCode = sendProvisionData(transport, ins, cborData, response))) { + if(ErrorCode::OK != (errorCode = sendProvisionData(pTransportFactory, ins, cborData, response))) { return errorCode; } return errorCode; } -static ErrorCode provisionSharedSecret(std::unique_ptr& transport) { +ErrorCode Provision::provisionPreSharedSecret(std::vector& preSharedSecret) { ErrorCode errorCode = ErrorCode::OK; cppbor::Array array; Instruction ins = Instruction::INS_PROVISION_PRESHARED_SECRET_CMD; std::vector response; - std::vector masterKey(kFakeKeyAgreementKey, kFakeKeyAgreementKey + - sizeof(kFakeKeyAgreementKey)/sizeof(kFakeKeyAgreementKey[0])); array = cppbor::Array(); - array.add(masterKey); + array.add(preSharedSecret); std::vector cborData = array.encode(); - if(ErrorCode::OK != (errorCode = sendProvisionData(transport, ins, cborData, response))) { - return errorCode; - } - return errorCode; -} - -static ErrorCode getProvisionStatus(std::unique_ptr& transport, std::vector& -response) { - ErrorCode errorCode = ErrorCode::OK; - Instruction ins = Instruction::INS_GET_PROVISION_STATUS_CMD; - std::vector cborData; - - if(ErrorCode::OK != (errorCode = sendProvisionData(transport, ins, cborData, response))) { + if(ErrorCode::OK != (errorCode = sendProvisionData(pTransportFactory, ins, cborData, response))) { return errorCode; } return errorCode; - } -static ErrorCode lockProvision(std::unique_ptr& transport) { +ErrorCode Provision::provisionBootParameters(BootParams& bootParams) { ErrorCode errorCode = ErrorCode::OK; - Instruction ins = Instruction::INS_LOCK_PROVISIONING_CMD; - std::vector cborData; - std::vector response; - - if(ErrorCode::OK != (errorCode = sendProvisionData(transport, ins, cborData, response))) { - return errorCode; - } - return errorCode; -} - -static ErrorCode setBootParameters(std::unique_ptr& transport) { - ErrorCode errorCode = ErrorCode::OK; - std::vector verifiedBootKey(32, 0); - std::vector verifiedBootKeyHash(32, 0); - uint32_t vendorPatchLevel = 0; - uint32_t bootPatchLevel = 0; cppbor::Array array; std::vector apdu; std::vector response; Instruction ins = Instruction::INS_SET_BOOT_PARAMS_CMD; - keymaster_verified_boot_t kmVerifiedBoot = KM_VERIFIED_BOOT_UNVERIFIED; array.add(GetOsVersion()). add(GetOsPatchlevel()). - add(vendorPatchLevel). - add(bootPatchLevel). + add(bootParams.vendorPatchLevel). + add(bootParams.bootPatchLevel). /* Verified Boot Key */ - add(verifiedBootKey). + add(bootParams.verifiedBootKey). /* Verified Boot Hash */ - add(verifiedBootKeyHash). + add(bootParams.verifiedBootKeyHash). /* boot state */ - add(static_cast(kmVerifiedBoot)). + add(bootParams.verifiedBootState). /* device locked */ - add(0); + add(bootParams.deviceLocked); std::vector cborData = array.encode(); - if(ErrorCode::OK != (errorCode = sendProvisionData(transport, ins, cborData, response))) { + if(ErrorCode::OK != (errorCode = sendProvisionData(pTransportFactory, ins, cborData, response))) { return errorCode; } return errorCode; } -static bool isSEProvisioned(uint64_t status) { - bool ret = false; - if ( (0 != (status & ProvisionStatus::PROVISION_STATUS_ATTESTATION_KEY)) && - (0 != (status & ProvisionStatus::PROVISION_STATUS_ATTESTATION_CERT_CHAIN)) && - (0 != (status & ProvisionStatus::PROVISION_STATUS_ATTESTATION_CERT_PARAMS)) && - (0 != (status & ProvisionStatus::PROVISION_STATUS_PRESHARED_SECRET)) && - (0 != (status & ProvisionStatus::PROVISION_STATUS_BOOT_PARAM))) { - ret = true; - } - return ret; -} - -ErrorCode provision(std::unique_ptr& transport) { +ErrorCode Provision::getProvisionStatus(uint64_t& status) { + ErrorCode errorCode = ErrorCode::OK; + Instruction ins = Instruction::INS_GET_PROVISION_STATUS_CMD; + std::vector cborData; std::vector response; std::unique_ptr item; CborConverter cborConverter; - ErrorCode errorCode = ErrorCode::OK; - //Get Provision status. - if(ErrorCode::OK != (errorCode = getProvisionStatus(transport, response))) { + if(ErrorCode::OK != (errorCode = sendProvisionData(pTransportFactory, ins, cborData, response))) { + LOG(ERROR) << "Failed to get provision status err: " << static_cast(errorCode); return errorCode; } - //Check if SE is provisioned. std::tie(item, errorCode) = cborConverter.decodeData(std::vector(response.begin(), response.end()-2), true); if(item != NULL) { - uint64_t status; - if(!cborConverter.getUint64(item, 1, status)) + if(!cborConverter.getUint64(item, 1, status)) { + LOG(ERROR) << "Failed to parse the status from cbor data"; return ErrorCode::UNKNOWN_ERROR; - - if(isSEProvisioned(status)) { - return ErrorCode::OK; //SE is Provisioned. } - - } else { - return ErrorCode::UNKNOWN_ERROR; } + return errorCode; +} - //SE not provisioned so Provision the SE. +ErrorCode Provision::lockProvision() { + ErrorCode errorCode = ErrorCode::OK; + Instruction ins = Instruction::INS_LOCK_PROVISIONING_CMD; + std::vector cborData; + std::vector response; - //Provision Attestation Key. - if(ErrorCode::OK != (errorCode = provisionAttestationKey(transport))) { - return errorCode; - } - //Provision Attestation certificate chain. - if(ErrorCode::OK != (errorCode = provisionAttestationCertificateChain(transport))) { - return errorCode; - } - //Provision certificate parameters. - if(ErrorCode::OK != (errorCode = provisionAttestationCertificateParams(transport))) { - return errorCode; - } - //Provision Attestation IDs. - if(ErrorCode::OK != (errorCode = provisionAttestationIDs(transport))) { - return errorCode; - } - //Provision Shared secret. - if(ErrorCode::OK != (errorCode = provisionSharedSecret(transport))) { - return errorCode; - } - //Set Boot parameters. - if(ErrorCode::OK != (errorCode = setBootParameters(transport))) { - return errorCode; - } - //Lock the provisioning. - if(ErrorCode::OK != (errorCode = lockProvision(transport))) { + if(ErrorCode::OK != (errorCode = sendProvisionData(pTransportFactory, ins, cborData, response))) { return errorCode; } - //return OK return errorCode; } +// Provision End } // namespace javacard } // namespace V4_1 diff --git a/HAL/keymaster/Android.bp b/HAL/keymaster/Android.bp index fdeaf9ce..9db148da 100644 --- a/HAL/keymaster/Android.bp +++ b/HAL/keymaster/Android.bp @@ -25,7 +25,8 @@ cc_binary { "4.1/JavacardKeymaster4Device.cpp", "4.1/JavacardSoftKeymasterContext.cpp", "4.1/JavacardOperationContext.cpp", - "4.1/Provision.cpp", + "4.1/CommonUtils.cpp", + "4.1/CborConverter.cpp", ], local_include_dirs: [ "include", @@ -46,7 +47,6 @@ cc_binary { "android.hardware.keymaster@4.0", "libjc_transport", "libcrypto", - "libjc_common", ], product_variables: { debuggable: { @@ -111,11 +111,12 @@ cc_library { } cc_library { - name: "libjc_common", + name: "libjc_provision", vendor_available: true, srcs: [ "4.1/CommonUtils.cpp", "4.1/CborConverter.cpp", + "4.1/Provision.cpp", ], local_include_dirs: [ "include", diff --git a/HAL/keymaster/include/Provision.h b/HAL/keymaster/include/Provision.h index a58c17c6..e6b670f2 100644 --- a/HAL/keymaster/include/Provision.h +++ b/HAL/keymaster/include/Provision.h @@ -25,10 +25,43 @@ namespace keymaster { namespace V4_1 { namespace javacard { -/** - * Provisions the SE. - */ -ErrorCode provision(std::unique_ptr& transport); +typedef struct BootParams_ { + uint32_t osVersion; + uint32_t osPatchLevel; + uint32_t vendorPatchLevel; + uint32_t bootPatchLevel; + std::vector verifiedBootKey; + std::vector verifiedBootKeyHash; + uint32_t verifiedBootState; + uint32_t deviceLocked; +} BootParams; + +typedef struct AttestIDParams_ { + std::string brand; + std::string device; + std::string product; + std::string serial; + std::string imei; + std::string meid; + std::string manufacturer; + std::string model; +} AttestIDParams; + +class Provision { +public: + ErrorCode initProvision(); + ErrorCode provisionAttestationKey(std::vector& batchKey); + ErrorCode provisionAtestationCertificateChain(std::vector>& CertChain); + ErrorCode provisionAttestationCertificateParams(std::vector& batchCertificate); + ErrorCode provisionAttestationID(AttestIDParams& attestParams); + ErrorCode provisionPreSharedSecret(std::vector& preSharedSecret); + ErrorCode provisionBootParameters(BootParams& bootParams ); + ErrorCode lockProvision(); + ErrorCode getProvisionStatus(uint64_t&); + +private: + std::unique_ptr pTransportFactory; +}; } // namespace javacard } // namespace V4_1 diff --git a/provisioning_tool/Android.bp b/provisioning_tool/Android.bp index 2f66b105..b9b39808 100644 --- a/provisioning_tool/Android.bp +++ b/provisioning_tool/Android.bp @@ -36,6 +36,6 @@ cc_binary { "libjc_transport", "libcrypto", "libjsoncpp", - "libjc_common", + "libjc_provision", ], } diff --git a/provisioning_tool/provision_tool.cpp b/provisioning_tool/provision_tool.cpp index 1cead86a..820384b1 100644 --- a/provisioning_tool/provision_tool.cpp +++ b/provisioning_tool/provision_tool.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #define BUFFER_MAX_LENGTH 256 #define SB_KEYMASTER_SERVICE "javacard" @@ -64,30 +65,14 @@ enum ProvisionStatus { PROVISION_STATUS_ATTESTATION_CERT_CHAIN = 0x02, PROVISION_STATUS_ATTESTATION_CERT_PARAMS = 0x04, PROVISION_STATUS_ATTEST_IDS = 0x08, - PROVISION_STATUS_SHARED_SECRET = 0x10, + PROVISION_STATUS_PRESHARED_SECRET = 0x10, PROVISION_STATUS_BOOT_PARAM = 0x20, PROVISION_STATUS_PROVISIONING_LOCKED = 0x40, }; using ::android::hardware::keymaster::V4_0::ErrorCode; -using ::android::hardware::keymaster::V4_0::EcCurve; -using ::android::hardware::keymaster::V4_0::HardwareAuthenticatorType; -using ::android::hardware::keymaster::V4_0::HardwareAuthToken; -using ::android::hardware::keymaster::V4_0::HmacSharingParameters; -using ::android::hardware::keymaster::V4_0::KeyCharacteristics; -using ::android::hardware::keymaster::V4_0::KeyFormat; -using ::android::hardware::keymaster::V4_0::KeyParameter; -using ::android::hardware::keymaster::V4_0::KeyPurpose; -using ::android::hardware::keymaster::V4_0::OperationHandle; -using ::android::hardware::keymaster::V4_0::SecurityLevel; -using ::android::hardware::keymaster::V4_0::VerificationToken; -using ::android::hardware::keymaster::V4_0::Tag; -using ::android::hardware::keymaster::V4_1::IKeymasterDevice; -using ::android::sp; -using se_transport::TransportFactory; - -static sp sbKeymaster; -static TransportFactory *pTransportFactory; + +static keymaster::V4_1::javacard::Provision mProvision; Json::Value root; constexpr char hex_value[256] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // @@ -117,12 +102,6 @@ std::string hex2str(std::string a) { return b; } -//static function declarations. -static ErrorCode constructApduMessage(Instruction& ins, std::vector& inputData, std::vector& apduOut, bool -extendedOutput); -static ErrorCode sendProvisionData(Instruction ins, std::vector& inData, std::vector& response, bool -extendedOutput); -static Tag mapAttestKeyToAttestTag(std::string key); bool parseJsonFile(const char* filename); static bool readDataFromFile(const char *filename, std::vector& data) { @@ -148,179 +127,6 @@ static bool readDataFromFile(const char *filename, std::vector& data) { return ret; } -static inline X509* parseDerCertificate(std::vector& certData) { - X509 *x509 = 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); -} - -static inline uint16_t getStatus(std::vector& inputData) { - //Last two bytes are the status SW0SW1 - return (inputData.at(inputData.size()-2) << 8) | (inputData.at(inputData.size()-1)); -} - -static inline TransportFactory* getTransportFactoryInstance() { - if(pTransportFactory == nullptr) { - pTransportFactory = new se_transport::TransportFactory( - android::base::GetBoolProperty("ro.kernel.qemu", false)); - pTransportFactory->openConnection(); - } - return pTransportFactory; -} - -static Tag mapAttestKeyToAttestTag(std::string keyStr) { - Tag tag = Tag::INVALID; - - if (0 == keyStr.compare("brand")) { - tag = Tag::ATTESTATION_ID_BRAND; - } else if(0 == keyStr.compare("device")) { - tag = Tag::ATTESTATION_ID_DEVICE; - } else if(0 == keyStr.compare("product")) { - tag = Tag::ATTESTATION_ID_PRODUCT; - } else if(0 == keyStr.compare("serial")) { - tag = Tag::ATTESTATION_ID_SERIAL; - } else if(0 == keyStr.compare("imei")) { - tag = Tag::ATTESTATION_ID_IMEI; - } else if(0 == keyStr.compare("meid")) { - tag = Tag::ATTESTATION_ID_MEID; - } else if(0 == keyStr.compare("manufacturer")) { - tag = Tag::ATTESTATION_ID_MANUFACTURER; - } else if(0 == keyStr.compare("model")) { - tag = Tag::ATTESTATION_ID_MODEL; - } - return tag; -} - -static ErrorCode constructApduMessage(Instruction& ins, std::vector& inputData, std::vector& apduOut, bool -extendedOutput) { - apduOut.push_back(static_cast(APDU_CLS)); //CLS - apduOut.push_back(static_cast(ins)); //INS - apduOut.push_back(static_cast(APDU_P1)); //P1 - apduOut.push_back(static_cast(APDU_P2)); //P2 - - if(UCHAR_MAX < inputData.size() && USHRT_MAX >= inputData.size()) { - //Extended length 3 bytes, starts with 0x00 - apduOut.push_back(static_cast(0x00)); - apduOut.push_back(static_cast(inputData.size() >> 8)); - apduOut.push_back(static_cast(inputData.size() & 0xFF)); - //Data - apduOut.insert(apduOut.end(), inputData.begin(), inputData.end()); - //Expected length of output - apduOut.push_back(static_cast(0x00)); - apduOut.push_back(static_cast(0x00)); - apduOut.push_back(static_cast(0x00));//Accepting complete length of output at a time - } else if(0 <= inputData.size() && UCHAR_MAX >= inputData.size()) { - //Short length - apduOut.push_back(static_cast(inputData.size())); - //Data - if(inputData.size() > 0) - apduOut.insert(apduOut.end(), inputData.begin(), inputData.end()); - //Expected length of output - apduOut.push_back(static_cast(0x00));//Accepting complete length of output at a time - if(extendedOutput) - apduOut.push_back(static_cast(0x00)); - - } else { - return (ErrorCode::INSUFFICIENT_BUFFER_SPACE); - } - - return (ErrorCode::OK);//success -} - -static ErrorCode sendProvisionData(Instruction ins, std::vector& inData, std::vector& response, bool -extendedOutput=false) { - ErrorCode ret = ErrorCode::OK; - std::vector apdu; - CborConverter cborConverter; - std::unique_ptr item; - ret = constructApduMessage(ins, inData, apdu, extendedOutput); - if(ret != ErrorCode::OK) return ret; - - if(!pTransportFactory->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); - } - - if((response.size() > 2)) { - //Skip last 2 bytes in cborData, it contains status. - std::tie(item, ret) = cborConverter.decodeData(std::vector(response.begin(), response.end()-2), - true); - } else { - ret = ErrorCode::UNKNOWN_ERROR; - } - - return ret; -} - void usage() { printf("Usage: provision_tool [options]\n"); printf("Valid options are:\n"); @@ -371,73 +177,55 @@ bool getBootParameterBlobValue(Json::Value& bootParamsObj, const char* key, std: bool setBootParameters(const char* filename) { Json::Value bootParamsObj; bool ret = false; + keymaster::V4_1::javacard::BootParams bootParams; if(!parseJsonFile(filename)) return ret; bootParamsObj = root.get("set_boot_params", bootParamsObj); if (!bootParamsObj.isNull()) { - cppbor::Array array; - ErrorCode errorCode = ErrorCode::OK; - std::vector apdu; - std::vector response; - Instruction ins = Instruction::INS_SET_BOOT_PARAMS_CMD; - uint32_t value; - std::vector blob; - - if(!getBootParameterIntValue(bootParamsObj, "os_version", &value)) { + + if(!getBootParameterIntValue(bootParamsObj, "os_version", &bootParams.osVersion)) { printf("\n Invalid value for os_version or os_version tag missing\n"); return ret; } - array.add(value); - if(!getBootParameterIntValue(bootParamsObj, "os_patch_level", &value)) { + if(!getBootParameterIntValue(bootParamsObj, "os_patch_level", &bootParams.osPatchLevel)) { printf("\n Invalid value for os_patch_level or os_patch_level tag missing\n"); return ret; } - array.add(value); - if(!getBootParameterIntValue(bootParamsObj, "vendor_patch_level", &value)) { + if(!getBootParameterIntValue(bootParamsObj, "vendor_patch_level", &bootParams.vendorPatchLevel)) { printf("\n Invalid value for vendor_patch_level or vendor_patch_level tag missing\n"); return ret; } - array.add(value); - if(!getBootParameterIntValue(bootParamsObj, "boot_patch_level", &value)) { + if(!getBootParameterIntValue(bootParamsObj, "boot_patch_level", &bootParams.bootPatchLevel)) { printf("\n Invalid value for boot_patch_level or boot_patch_level tag missing\n"); return ret; } - array.add(value); - if(!getBootParameterBlobValue(bootParamsObj, "verified_boot_key", blob)) { + if(!getBootParameterBlobValue(bootParamsObj, "verified_boot_key", bootParams.verifiedBootKey)) { printf("\n Invalid value for verified_boot_key or verified_boot_key tag missing\n"); return ret; } - array.add(blob); - blob.clear(); - if(!getBootParameterBlobValue(bootParamsObj, "verified_boot_key_hash", blob)) { + if(!getBootParameterBlobValue(bootParamsObj, "verified_boot_key_hash", bootParams.verifiedBootKeyHash)) { printf("\n Invalid value for verified_boot_key_hash or verified_boot_key_hash tag missing\n"); return ret; } - array.add(blob); - blob.clear(); - if(!getBootParameterIntValue(bootParamsObj, "boot_state", &value)) { + if(!getBootParameterIntValue(bootParamsObj, "boot_state", &bootParams.verifiedBootState)) { printf("\n Invalid value for boot_state or boot_state tag missing\n"); return ret; } - array.add(value); - if(!getBootParameterIntValue(bootParamsObj, "device_locked", &value)) { + if(!getBootParameterIntValue(bootParamsObj, "device_locked", &bootParams.deviceLocked)) { printf("\n Invalid value for device_locked or device_locked tag missing\n"); return ret; } - array.add(value); - - std::vector cborData = array.encode(); - - if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { - printf("\n Failed to set boot parameters errorCode:%d\n", errorCode); - return ret; - } } else { return ret; } + + if (ErrorCode::OK != mProvision.provisionBootParameters(bootParams)) { + return ret; + } + printf("\n SE successfully accepted boot paramters \n"); return true; } @@ -445,55 +233,47 @@ bool setBootParameters(const char* filename) { bool provisionAttestationIds(const char *filename) { Json::Value attestIds; bool ret = false; + keymaster::V4_1::javacard::AttestIDParams params; if(!parseJsonFile(filename)) return ret; attestIds = root.get("attest_ids", attestIds); if (!attestIds.isNull()) { - if (attestIds.size() != MAX_ATTEST_IDS_SIZE) { - return ret; - } Json::Value value; - std::vector temp; - int i = 0; - std::vector params(attestIds.size()); Json::Value::Members keys = attestIds.getMemberNames(); - Tag tag; for(std::string key : keys) { - if(Tag::INVALID == (tag = mapAttestKeyToAttestTag(key))) { - break; - } value = attestIds[key]; if(value.empty()) { - break; + continue; } - params[i].tag = tag; - for(char ch : value.asString()) { - temp.push_back((uint8_t)ch); + if (!value.isString()) { + return ret; } - params[i].blob.resize(temp.size()); - params[i].blob = temp; - temp.clear(); - i++; - } - - if(i != MAX_ATTEST_IDS_SIZE) - return ret; - - CborConverter cborConverter; - cppbor::Array array; - Instruction ins = Instruction::INS_PROVISION_ATTEST_IDS_CMD; - ErrorCode errorCode = ErrorCode::OK; - std::vector response; - hidl_vec attestParams(params); - //Encode input data into CBOR. - cborConverter.addKeyparameters(array, attestParams); - std::vector cborData = array.encode(); + if (0 == key.compare("brand")) { + params.brand = value.asString(); + } else if(0 == key.compare("device")) { + params.device = value.asString(); + } else if(0 == key.compare("product")) { + params.product = value.asString(); + } else if(0 == key.compare("serial")) { + params.serial = value.asString(); + } else if(0 == key.compare("imei")) { + params.imei = value.asString(); + } else if(0 == key.compare("meid")) { + params.meid = value.asString(); + } else if(0 == key.compare("manufacturer")) { + params.manufacturer = value.asString(); + } else if(0 == key.compare("model")) { + params.model = value.asString(); + } else { + printf("\n unknown attestation id key:%s \n", key.c_str()); + return ret; + } + } - if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { - printf("\n Failed to provision attestation ids error: %d\n", uint32_t(errorCode)); + if (ErrorCode::OK != mProvision.provisionAttestationID(params)) { return ret; } } else { @@ -504,14 +284,10 @@ bool provisionAttestationIds(const char *filename) { } bool lockProvision() { - bool ret = false; - cppbor::Array array; - Instruction ins = Instruction::INS_LOCK_PROVISIONING_CMD; - ErrorCode errorCode = ErrorCode::OK; - std::vector cborData; - std::vector response; + ErrorCode errorCode; + bool ret = false; - if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { + if(ErrorCode::OK != (errorCode = mProvision.lockProvision())) { printf("\n Failed to lock provisioning error: %d\n", uint32_t(errorCode)); return ret; } @@ -521,31 +297,32 @@ bool lockProvision() { bool getProvisionStatus() { bool ret = false; - CborConverter cborConverter; - cppbor::Array array; - Instruction ins = Instruction::INS_GET_PROVISION_STATUS_CMD; - ErrorCode errorCode = ErrorCode::OK; - std::vector cborData; - std::vector response; - std::unique_ptr item; - - if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { - printf("\n Failed to get provision status error: %d\n", uint32_t(errorCode)); + uint64_t status; + if (ErrorCode::OK != mProvision.getProvisionStatus(status)) { return ret; } - std::tie(item, errorCode) = cborConverter.decodeData(std::vector(response.begin(), response.end()-2), - true); - if(item != NULL) { - uint64_t status; - - if(!cborConverter.getUint64(item, 1, status)) { - printf("\n Failed to get the status value \n"); - return ret; - } else { - printf("\nCurrent provision status: %ld\n", status); + if ( (0 != (status & ProvisionStatus::PROVISION_STATUS_ATTESTATION_KEY)) && + (0 != (status & ProvisionStatus::PROVISION_STATUS_ATTESTATION_CERT_CHAIN)) && + (0 != (status & ProvisionStatus::PROVISION_STATUS_ATTESTATION_CERT_PARAMS)) && + (0 != (status & ProvisionStatus::PROVISION_STATUS_PRESHARED_SECRET)) && + (0 != (status & ProvisionStatus::PROVISION_STATUS_BOOT_PARAM))) { + printf("\n SE is provisioned \n"); + } else { + if (0 == (status & ProvisionStatus::PROVISION_STATUS_ATTESTATION_KEY)) { + printf("\n Attestation key is not provisioned \n"); + } + if (0 == (status & ProvisionStatus::PROVISION_STATUS_ATTESTATION_CERT_CHAIN)) { + printf("\n Attestation certificate chain is not provisioned \n"); + } + if (0 == (status & ProvisionStatus::PROVISION_STATUS_ATTESTATION_CERT_PARAMS)) { + printf("\n Attestation certificate params are not provisioned \n"); + } + if (0 == (status & ProvisionStatus::PROVISION_STATUS_PRESHARED_SECRET)) { + printf("\n Shared secret is not provisioned \n"); + } + if (0 == (status & ProvisionStatus::PROVISION_STATUS_BOOT_PARAM)) { + printf("\n Boot params are not provisioned \n"); } - } else { - return ret; } return true; } @@ -559,25 +336,13 @@ bool provisionSharedSecret(const char* filename) { sharedSecret = root.get("shared_secret", sharedSecret); if (!sharedSecret.isNull()) { - cppbor::Array array; - Instruction ins = Instruction::INS_PROVISION_SHARED_SECRET_CMD; - ErrorCode errorCode = ErrorCode::OK; - std::vector response; - std::string str = sharedSecret.asString(); - std::string secret = hex2str(str); - - //Length of the secret should be 32 bytes. - if(SHARED_SECRET_SIZE != secret.size()) { + + if (!sharedSecret.isString()) { return ret; } - std::vector input(secret.data(), secret.data() + secret.length()); - - //Encode input data into CBOR. - array.add(input); - std::vector cborData = array.encode(); - - if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { - printf("\n Failed to provision shared secret error: %d\n", uint32_t(errorCode)); + std::string secret = hex2str(sharedSecret.asString()); + std::vector data(secret.begin(), secret.end()); + if(ErrorCode::OK != mProvision.provisionPreSharedSecret(data)) { return ret; } } else { @@ -596,48 +361,14 @@ static bool provisionAttestationKey(const char* filename) { keyFile = root.get("attest_key", keyFile); if (!keyFile.isNull()) { - ErrorCode errorCode = ErrorCode::OK; - CborConverter cborConverter; - cppbor::Array array; - cppbor::Array subArray; std::vector data; - std::vector privKey; - std::vector pubKey; - Instruction ins = Instruction::INS_PROVISION_ATTESTATION_KEY_CMD; - EcCurve curve; - std::vector response; std::string keyFileName = keyFile.asString(); if(!readDataFromFile(keyFileName.data(), data)) { printf("\n Failed to read the Root ec key\n"); return ret; } - keymaster::AuthorizationSet authSetKeyParams(keymaster::AuthorizationSetBuilder() - .Authorization(keymaster::TAG_ALGORITHM, KM_ALGORITHM_EC) - .Authorization(keymaster::TAG_DIGEST, KM_DIGEST_SHA_2_256) - .Authorization(keymaster::TAG_EC_CURVE, KM_EC_CURVE_P_256) - .Authorization(keymaster::TAG_PURPOSE, static_cast(0x7F))); /* The value 0x7F is not present in types.hal */ - // Read the ECKey from the file. - hidl_vec keyParams = keymaster::V4_1::javacard::kmParamSet2Hidl(authSetKeyParams); - - if(ErrorCode::OK != (errorCode = keymaster::V4_1::javacard::ecRawKeyFromPKCS8(data, privKey, pubKey, curve))) { - printf("\n Failed to convert PKCS8 to RAW key\n"); - return ret; - } - subArray.add(privKey); - subArray.add(pubKey); - std::vector encodedArray = subArray.encode(); - cppbor::Bstr bstr(encodedArray.begin(), encodedArray.end()); - - //Encode data. - cborConverter.addKeyparameters(array, keyParams); - array.add(static_cast(KeyFormat::RAW)); - array.add(bstr); - - std::vector cborData = array.encode(); - - if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { - printf("\n Failed to provision attestation key\n"); + if(ErrorCode::OK != mProvision.provisionAttestationKey(data)) { return ret; } } else { @@ -656,23 +387,26 @@ bool provisionAttestationCertificateChain(const char* filename) { certChainFile = root.get("attest_cert_chain", certChainFile); if (!certChainFile.isNull()) { - ErrorCode errorCode = ErrorCode::OK; - cppbor::Array array; - Instruction ins = Instruction::INS_PROVISION_CERT_CHAIN_CMD; - std::vector response; - - std::vector certData; - std::string strCertChain = certChainFile.asString(); - /* Read the Root certificate */ - if(!readDataFromFile(strCertChain.data(), certData)) { - printf("\n Failed to read the Root certificate\n"); + std::vector> certData; + + if(certChainFile.isArray()) { + for (int i = 0; i < certChainFile.size(); i++) { + std::vector tmp; + if(certChainFile[i].isString()) { + /* Read the certificates. */ + if(!readDataFromFile(certChainFile[i].asString().data(), tmp)) { + printf("\n Failed to read the Root certificate\n"); + return ret; + } + certData.push_back(std::move(tmp)); + } else { + return ret; + } + } + } else { return ret; } - cppbor::Bstr certChain(certData.begin(), certData.end()); - std::vector cborData = certChain.encode(); - - if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { - printf("\n Failed to provision cert chain errorCode:%d\n", static_cast(errorCode)); + if (ErrorCode::OK != mProvision.provisionAtestationCertificateChain(certData)) { return ret; } } else { @@ -691,60 +425,21 @@ bool provisionAttestationCertificateParams(const char* filename) { certChainFile = root.get("attest_cert_chain", certChainFile); if (!certChainFile.isNull()) { - ErrorCode errorCode = ErrorCode::OK; - cppbor::Array array; - Instruction ins = Instruction::INS_PROVISION_CERT_PARAMS_CMD; - std::vector response; - X509 *x509 = NULL; - std::vector subject; - std::vector authorityKeyIdentifier; - std::vector notAfter; - std::vector certData; - std::vector> certChain; - - - std::string strCertChain = certChainFile.asString(); - /* Read the Root certificate */ - if(!readDataFromFile(strCertChain.data(), certData)) { - printf("\n Failed to read the Root certificate\n"); - return ret; - } - - // Get first certificate from chain of certificates. - if(ErrorCode::OK != (errorCode =keymaster::V4_1::javacard::getCertificateChain(certData, certChain))) { - printf("\n Failed to parse the certificate chain \n"); - return ret; - } - - if(certChain.size() == 0) { - printf("\n Length of the certificate chain is 0\n"); - return ret; - } + std::vector> certData; - - /* 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(certChain[0]))) { - printf("\n Failed to parse the DER certificate \n"); - return ret; - } - - /* Get subject in DER */ - getDerSubjectName(x509, subject); - /* Get AuthorityKeyIdentifier */ - getAuthorityKeyIdentifier(x509, authorityKeyIdentifier); - /* Get Expirty Time */ - getNotAfter(x509, notAfter); - /*Free X509 */ - X509_free(x509); - - array.add(subject); - array.add(notAfter); - array.add(authorityKeyIdentifier); - std::vector cborData = array.encode(); - - if(ErrorCode::OK != (errorCode = sendProvisionData(ins, cborData, response))) { - printf("\n Failed to provision cert params errorCode:%d\n", static_cast(errorCode)); + if(certChainFile.isArray()) { + if (certChainFile.size() == 0) { + return ret; + } + std::vector tmp; + if(!readDataFromFile(certChainFile[0].asString().data(), tmp)) { + printf("\n Failed to read the Root certificate\n"); + return ret; + } + if (ErrorCode::OK != mProvision.provisionAttestationCertificateParams(tmp)) { + return ret; + } + } else { return ret; } } else { @@ -804,89 +499,88 @@ bool parseJsonFile(const char* filename) { int main(int argc, char* argv[]) { - int c; - struct option longOpts[] = { - {"all", required_argument, NULL, 'a'}, - {"attest_key", required_argument, NULL, 'k'}, - {"cert_chain", required_argument, NULL, 'c'}, - {"cert_params", required_argument, NULL,'p'}, - {"attest_ids", required_argument, NULL, 'i'}, - {"shared_secret", required_argument, NULL, 'r'}, - {"set_boot_params", required_argument, NULL, 'b'}, - {"provision_status", no_argument, NULL, 's'}, - {"lock_provision", no_argument, NULL, 'l'}, - {"help", no_argument, NULL, 'h'}, + int c; + struct option longOpts[] = { + {"all", required_argument, NULL, 'a'}, + {"attest_key", required_argument, NULL, 'k'}, + {"cert_chain", required_argument, NULL, 'c'}, + {"cert_params", required_argument, NULL,'p'}, + {"attest_ids", required_argument, NULL, 'i'}, + {"shared_secret", required_argument, NULL, 'r'}, + {"set_boot_params", required_argument, NULL, 'b'}, + {"provision_status", no_argument, NULL, 's'}, + {"lock_provision", no_argument, NULL, 'l'}, + {"help", no_argument, NULL, 'h'}, {0,0,0,0} - }; - -printf("\n main step0 \n"); - sbKeymaster = IKeymasterDevice::getService(SB_KEYMASTER_SERVICE); - if(NULL == sbKeymaster) { - printf("\n Failed to get StrongBox Keymaster service\n"); - exit(0); - } - pTransportFactory = getTransportFactoryInstance(); - if(NULL == pTransportFactory) { - printf("\n Failed to create transport factory\n"); - exit(0); - } + }; if (argc <= 1) { printf("\n Invalid command \n"); usage(); } -printf("\n main step1 \n"); - /* getopt_long stores the option index here. */ - while ((c = getopt_long(argc, argv, ":slha:k:c:p:i:r:b:", longOpts, NULL)) != -1) { - switch(c) { + /* Initialize provision */ + mProvision.initProvision(); + + /* getopt_long stores the option index here. */ + while ((c = getopt_long(argc, argv, ":slha:k:c:p:i:r:b:", longOpts, NULL)) != -1) { + switch(c) { case 'a': //all provision(optarg); break; case 'k': //attest key - provisionAttestationKey(optarg); + if(!provisionAttestationKey(optarg)) + printf("\n Failed to provision attestaion key\n"); break; case 'c': //attest certchain - provisionAttestationCertificateChain(optarg); + if(!provisionAttestationCertificateChain(optarg)) + printf("\n Failed to provision attestaion certificate chain\n"); break; case 'p': //attest cert params - provisionAttestationCertificateParams(optarg); + if(!provisionAttestationCertificateParams(optarg)) + printf("\n Failed to provision attestaion certificate paramaters\n"); + break; + case 'i': + //attestation ids. + if(!provisionAttestationIds(optarg)) + printf("\n Failed to provision attestaion ids\n"); + break; + //shared secret + case 'r': + if(!provisionSharedSecret(optarg)) + printf("\n Failed to provision shared secret\n"); break; - case 'i': - provisionAttestationIds(optarg); - break; - case 'r': - provisionSharedSecret(optarg); - break; case 'b': //set boot params - setBootParameters(optarg); + if(!setBootParameters(optarg)) + printf("\n Failed to set boot parameters.\n"); break; - case 's': - getProvisionStatus(); - break; - case 'l': + case 's': + if(!getProvisionStatus()) + printf("\n Failed to get provision status \n"); + break; + case 'l': lockProvision(); - break; - case 'h': + break; + case 'h': usage(); - break; - case ':': - printf("\n missing argument\n"); + break; + case ':': + printf("\n missing argument\n"); usage(); - break; - case '?': - default: - printf("\n Invalid option\n"); + break; + case '?': + default: + printf("\n Invalid option\n"); usage(); - break; - } - } + break; + } + } if(optind < argc) { usage(); } - return 0; + return 0; } diff --git a/provisioning_tool/sample_json.txt b/provisioning_tool/sample_json.txt index 1435e133..841c9843 100644 --- a/provisioning_tool/sample_json.txt +++ b/provisioning_tool/sample_json.txt @@ -17,9 +17,12 @@ "boot_patch_level": 0, "verified_boot_key": "0000000000000000000000000000000000000000000000000000000000000000", "verified_boot_key_hash": "0000000000000000000000000000000000000000000000000000000000000000", - "boot_state": 0, + "boot_state": 2, "device_locked": 0 }, "attest_key": "/data/vendor/ec_key.der", - "attest_cert_chain": "/data/vendor/ec_cert_chain.der" + "attest_cert_chain": [ + "/data/vendor/ec_cert.der", + "/data/vendor/ec_root_cert.der" + ] } From 2134a5e8b6ea3233869c085f6976ead0b023188c Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Mon, 25 Jan 2021 15:35:50 +0530 Subject: [PATCH 05/21] Removed sample_json.txt --- HAL/keymaster/sample_json.txt | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100644 HAL/keymaster/sample_json.txt diff --git a/HAL/keymaster/sample_json.txt b/HAL/keymaster/sample_json.txt deleted file mode 100644 index b65164aa..00000000 --- a/HAL/keymaster/sample_json.txt +++ /dev/null @@ -1,25 +0,0 @@ -{ - "attest_ids": { - "brand": "Google", - "device": "Pixel 3A", - "product": "Pixel", - "serial": "UGYJFDjFeRuBEH", - "imei": "987080543071019", - "meid": "27863510227963", - "manufacturer": "Foxconn", - "model": "HD1121" - }, - "shared_secret": "0000000000000000000000000000000000000000000000000000000000000000", - "set_boot_params": { - "os_version": 100, - "os_patch_level": 100, - "vendor_patch_level": 0, - "boot_patch_level": 0, - "verified_boot_key": "0000000000000000000000000000000000000000000000000000000000000000", - "verified_boot_key_hash": "0000000000000000000000000000000000000000000000000000000000000000", - "boot_state": 0, - "device_locked": 0 - }, - "attest_key": "/data/data/ec_key.der", - "attest_cert_chain": "/data/data/ec_cert_chain.der" -} From dc379c7d6ce21535ff6d25bacae047d9f2d0dcd0 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Mon, 25 Jan 2021 19:43:42 +0530 Subject: [PATCH 06/21] Added uninit function --- HAL/keymaster/4.1/Provision.cpp | 11 ++++++++++- HAL/keymaster/include/Provision.h | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/HAL/keymaster/4.1/Provision.cpp b/HAL/keymaster/4.1/Provision.cpp index a896db88..c8f97660 100644 --- a/HAL/keymaster/4.1/Provision.cpp +++ b/HAL/keymaster/4.1/Provision.cpp @@ -197,7 +197,8 @@ ErrorCode Provision::initProvision() { if(pTransportFactory == nullptr) { pTransportFactory = std::unique_ptr(new se_transport::TransportFactory( android::base::GetBoolProperty("ro.kernel.qemu", false))); - pTransportFactory->openConnection(); + if(!pTransportFactory->openConnection()) + return ErrorCode::UNKNOWN_ERROR; } return ErrorCode::OK; } @@ -399,6 +400,14 @@ ErrorCode Provision::lockProvision() { } return errorCode; } + +ErrorCode Provision::uninit() { + if(pTransportFactory != nullptr) { + if(!pTransportFactory->closeConnection()) + return ErrorCode::UNKNOWN_ERROR; + } + return ErrorCode::OK; +} // Provision End } // namespace javacard diff --git a/HAL/keymaster/include/Provision.h b/HAL/keymaster/include/Provision.h index e6b670f2..64b56641 100644 --- a/HAL/keymaster/include/Provision.h +++ b/HAL/keymaster/include/Provision.h @@ -58,6 +58,7 @@ class Provision { ErrorCode provisionBootParameters(BootParams& bootParams ); ErrorCode lockProvision(); ErrorCode getProvisionStatus(uint64_t&); + ErrorCode uninit(); private: std::unique_ptr pTransportFactory; From 697a0405ecb8c59467dea1392c30854d29ea97c2 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Tue, 26 Jan 2021 15:09:55 +0530 Subject: [PATCH 07/21] modified the function to init and uninit --- HAL/keymaster/4.1/Provision.cpp | 4 +--- HAL/keymaster/include/Provision.h | 32 +++++++++++++++++++++++++++- provisioning_tool/provision_tool.cpp | 4 +++- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/HAL/keymaster/4.1/Provision.cpp b/HAL/keymaster/4.1/Provision.cpp index c8f97660..85bdd241 100644 --- a/HAL/keymaster/4.1/Provision.cpp +++ b/HAL/keymaster/4.1/Provision.cpp @@ -191,9 +191,7 @@ extendedOutput) { return ret; } -// Class Provision Start - -ErrorCode Provision::initProvision() { +ErrorCode Provision::init() { if(pTransportFactory == nullptr) { pTransportFactory = std::unique_ptr(new se_transport::TransportFactory( android::base::GetBoolProperty("ro.kernel.qemu", false))); diff --git a/HAL/keymaster/include/Provision.h b/HAL/keymaster/include/Provision.h index 64b56641..e541c496 100644 --- a/HAL/keymaster/include/Provision.h +++ b/HAL/keymaster/include/Provision.h @@ -49,15 +49,45 @@ typedef struct AttestIDParams_ { class Provision { public: - ErrorCode initProvision(); + /** + * Initalizes the transport layer. + */ + ErrorCode init(); + /** + * Provision the Attestation key. + */ ErrorCode provisionAttestationKey(std::vector& batchKey); + /** + * Provision the Attestation certificate chain. + */ ErrorCode provisionAtestationCertificateChain(std::vector>& CertChain); + /** + * Provision the Attestation certificate paramters. + */ ErrorCode provisionAttestationCertificateParams(std::vector& batchCertificate); + /** + * Provision the Attestation ID. + */ ErrorCode provisionAttestationID(AttestIDParams& attestParams); + /** + * Provision the pre-shared secret. + */ ErrorCode provisionPreSharedSecret(std::vector& preSharedSecret); + /** + * Provision the boot parameters. + */ ErrorCode provisionBootParameters(BootParams& bootParams ); + /** + * Locks the provision. After this no more provision commanands are allowed. + */ ErrorCode lockProvision(); + /** + * Get the provision status. + */ ErrorCode getProvisionStatus(uint64_t&); + /** + * Uninitialize the transport layer. + */ ErrorCode uninit(); private: diff --git a/provisioning_tool/provision_tool.cpp b/provisioning_tool/provision_tool.cpp index 820384b1..e3148fec 100644 --- a/provisioning_tool/provision_tool.cpp +++ b/provisioning_tool/provision_tool.cpp @@ -519,7 +519,7 @@ int main(int argc, char* argv[]) usage(); } /* Initialize provision */ - mProvision.initProvision(); + mProvision.init(); /* getopt_long stores the option index here. */ while ((c = getopt_long(argc, argv, ":slha:k:c:p:i:r:b:", longOpts, NULL)) != -1) { @@ -582,5 +582,7 @@ int main(int argc, char* argv[]) if(optind < argc) { usage(); } + /*Uninitalize */ + mProvision.uninit(); return 0; } From 6dcb7ced192a1605972f75d8f4a29f087d27c926 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Wed, 27 Jan 2021 11:17:06 +0530 Subject: [PATCH 08/21] 1. Renamed the certiicate and key file names in sample_json.txt 2. Separated the Provision library from HAL and put it inside the provisioning_tool folder --- HAL/keymaster/Android.bp | 7 ++--- provisioning_tool/Android.bp | 27 +++++++++++++++++++ .../4.1 => provisioning_tool}/Provision.cpp | 0 .../include => provisioning_tool}/Provision.h | 0 provisioning_tool/sample_json.txt | 6 ++--- 5 files changed, 32 insertions(+), 8 deletions(-) rename {HAL/keymaster/4.1 => provisioning_tool}/Provision.cpp (100%) rename {HAL/keymaster/include => provisioning_tool}/Provision.h (100%) diff --git a/HAL/keymaster/Android.bp b/HAL/keymaster/Android.bp index 9db148da..1bcc6e2c 100644 --- a/HAL/keymaster/Android.bp +++ b/HAL/keymaster/Android.bp @@ -25,8 +25,6 @@ cc_binary { "4.1/JavacardKeymaster4Device.cpp", "4.1/JavacardSoftKeymasterContext.cpp", "4.1/JavacardOperationContext.cpp", - "4.1/CommonUtils.cpp", - "4.1/CborConverter.cpp", ], local_include_dirs: [ "include", @@ -46,6 +44,7 @@ cc_binary { "android.hardware.keymaster@4.1", "android.hardware.keymaster@4.0", "libjc_transport", + "libjc_common", "libcrypto", ], product_variables: { @@ -111,12 +110,11 @@ cc_library { } cc_library { - name: "libjc_provision", + name: "libjc_common", vendor_available: true, srcs: [ "4.1/CommonUtils.cpp", "4.1/CborConverter.cpp", - "4.1/Provision.cpp", ], local_include_dirs: [ "include", @@ -138,7 +136,6 @@ cc_library { "libcppbor", "android.hardware.keymaster@4.1", "android.hardware.keymaster@4.0", - "libjc_transport", "libcrypto", ], } diff --git a/provisioning_tool/Android.bp b/provisioning_tool/Android.bp index b9b39808..579d2ff4 100644 --- a/provisioning_tool/Android.bp +++ b/provisioning_tool/Android.bp @@ -36,6 +36,33 @@ cc_binary { "libjc_transport", "libcrypto", "libjsoncpp", + "libjc_common", "libjc_provision", ], } + +cc_library { + name: "libjc_provision", + vendor_available: true, + srcs: [ + "Provision.cpp", + ], + shared_libs: [ + "liblog", + "libcutils", + "libdl", + "libbase", + "libutils", + "libhardware", + "libhidlbase", + "libsoftkeymasterdevice", + "libkeymaster_messages", + "libkeymaster_portable", + "libcppbor", + "android.hardware.keymaster@4.1", + "android.hardware.keymaster@4.0", + "libjc_transport", + "libcrypto", + "libjc_common", + ], +} diff --git a/HAL/keymaster/4.1/Provision.cpp b/provisioning_tool/Provision.cpp similarity index 100% rename from HAL/keymaster/4.1/Provision.cpp rename to provisioning_tool/Provision.cpp diff --git a/HAL/keymaster/include/Provision.h b/provisioning_tool/Provision.h similarity index 100% rename from HAL/keymaster/include/Provision.h rename to provisioning_tool/Provision.h diff --git a/provisioning_tool/sample_json.txt b/provisioning_tool/sample_json.txt index 841c9843..8751c6b4 100644 --- a/provisioning_tool/sample_json.txt +++ b/provisioning_tool/sample_json.txt @@ -20,9 +20,9 @@ "boot_state": 2, "device_locked": 0 }, - "attest_key": "/data/vendor/ec_key.der", + "attest_key": "/data/vendor/batch_key.der", "attest_cert_chain": [ - "/data/vendor/ec_cert.der", - "/data/vendor/ec_root_cert.der" + "/data/vendor/batch_cert.der", + "/data/vendor/root_cert.der" ] } From 8f6e409cc9e34c4aa10405c01ab4b45611b9801e Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Fri, 29 Jan 2021 10:34:08 +0530 Subject: [PATCH 09/21] Store master key as Key object rather than as a byte array --- .../keymaster/KMAndroidSEProvider.java | 4 +- .../javacard/keymaster/KMJCardSimulator.java | 4 +- .../javacard/keymaster/KMKeymasterApplet.java | 12 +++- .../javacard/keymaster/KMRepository.java | 62 ++++++++++++------- 4 files changed, 53 insertions(+), 29 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java index 4b0994f4..20417d0f 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEProvider.java @@ -105,7 +105,7 @@ public class KMAndroidSEProvider implements KMSEProvider { public static final byte KEYSIZE_128_OFFSET = 0x00; public static final byte KEYSIZE_256_OFFSET = 0x01; public static final short TMP_ARRAY_SIZE = 256; - public static final short CERT_CHAIN_MAX_SIZE = 2050;//First 2 bytes for length. + public static final short CERT_CHAIN_MAX_SIZE = 2500;//First 2 bytes for length. final byte[] CIPHER_ALGS = { Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, @@ -1143,7 +1143,7 @@ public void persistPartialCertificateChain(byte[] buf, short offset, short len, // Next single byte holds the array header. // Next 3 bytes holds the Byte array header with the cert1 length. // Next 3 bytes holds the Byte array header with the cert2 length. - if (totalLen > CERT_CHAIN_MAX_SIZE) { + if (totalLen > (short) (CERT_CHAIN_MAX_SIZE - 2)) { KMException.throwIt(KMError.INVALID_INPUT_LENGTH); } short persistedLen = Util.getShort(certificateChain, (short) 0); diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java index a9a6a937..08c3d0ea 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimulator.java @@ -71,7 +71,7 @@ public class KMJCardSimulator implements KMSEProvider { public static final short MAX_RND_NUM_SIZE = 64; public static final short ENTROPY_POOL_SIZE = 16; // simulator does not support 256 bit aes keys public static final byte[] aesICV = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - private static final short CERT_CHAIN_MAX_SIZE = 2050;//First 2 bytes for length. + private static final short CERT_CHAIN_MAX_SIZE = 2500;//First 2 bytes for length. public static boolean jcardSim = false; @@ -1246,7 +1246,7 @@ public void persistPartialCertificateChain(byte[] buf, short offset, // Next single byte holds the array header. // Next 3 bytes holds the Byte array header with the cert1 length. // Next 3 bytes holds the Byte array header with the cert2 length. - if (totalLen > CERT_CHAIN_MAX_SIZE) { + if (totalLen > (short) (CERT_CHAIN_MAX_SIZE - 2)) { KMException.throwIt(KMError.INVALID_INPUT_LENGTH); } short persistedLen = Util.getShort(certificateChain, (short) 0); diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index a85a7243..6074038b 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -1530,7 +1530,11 @@ private void setUniqueId(KMAttestationCert cert, byte[] scratchPad) { } //master key. - tmpVariables[2] = repository.getMasterKeySecret(); + tmpVariables[2] = KMByteBlob.instance(KMRepository.MASTER_KEY_SIZE); + repository.getMasterKeySecret( + KMByteBlob.cast(tmpVariables[2]).getBuffer(), + KMByteBlob.cast(tmpVariables[2]).getStartOff(), + KMByteBlob.cast(tmpVariables[2]).length()); cert.makeUniqueId( scratchPad, (short) 0, @@ -3903,7 +3907,11 @@ private static short deriveKey(byte[] scratchPad) { // Input data - Encrypted output (Generated in step 2). // 4. HMAC Sign generates an output of 32 bytes length. // Consume only first 16 bytes as derived key. - tmpVariables[4] = repository.getMasterKeySecret(); + tmpVariables[4] = KMByteBlob.instance(KMRepository.MASTER_KEY_SIZE); + repository.getMasterKeySecret( + KMByteBlob.cast(tmpVariables[4]).getBuffer(), + KMByteBlob.cast(tmpVariables[4]).getStartOff(), + KMByteBlob.cast(tmpVariables[4]).length()); tmpVariables[5] = repository.alloc(AES_GCM_AUTH_TAG_LENGTH); tmpVariables[3] = seProvider.aesGCMEncrypt( diff --git a/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/src/com/android/javacard/keymaster/KMRepository.java index 4c30a613..94951348 100644 --- a/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/Applet/src/com/android/javacard/keymaster/KMRepository.java @@ -22,6 +22,8 @@ import javacard.framework.ISOException; import javacard.framework.JCSystem; import javacard.framework.Util; +import javacard.security.AESKey; +import javacard.security.KeyBuilder; /** * KMRepository class manages persistent and volatile memory usage by the applet. Note the repository @@ -29,7 +31,7 @@ */ public class KMRepository implements KMUpgradable { // Data table configuration - public static final short DATA_INDEX_SIZE = 24; + public static final short DATA_INDEX_SIZE = 23; public static final short DATA_INDEX_ENTRY_SIZE = 4; public static final short DATA_MEM_SIZE = 2048; public static final short HEAP_SIZE = 10000; @@ -42,10 +44,9 @@ public class KMRepository implements KMUpgradable { private static final short OPERATION_HANDLE_ENTRY_SIZE = OPERATION_HANDLE_SIZE + OPERATION_HANDLE_STATUS_SIZE; // Data table offsets - public static final byte MASTER_KEY = 8; - public static final byte SHARED_KEY = 9; - public static final byte COMPUTED_HMAC_KEY = 10; - public static final byte HMAC_NONCE = 11; + public static final byte SHARED_KEY = 8; + public static final byte COMPUTED_HMAC_KEY = 9; + public static final byte HMAC_NONCE = 10; public static final byte ATT_ID_BRAND = 0; public static final byte ATT_ID_DEVICE = 1; public static final byte ATT_ID_PRODUCT = 2; @@ -54,18 +55,18 @@ public class KMRepository implements KMUpgradable { public static final byte ATT_ID_MEID = 5; public static final byte ATT_ID_MANUFACTURER = 6; public static final byte ATT_ID_MODEL = 7; - public static final byte ATT_EC_KEY = 12; - public static final byte CERT_ISSUER = 13; - public static final byte CERT_EXPIRY_TIME = 14; - public static final byte BOOT_OS_VERSION = 15; - public static final byte BOOT_OS_PATCH = 16; - public static final byte VENDOR_PATCH_LEVEL = 17; - public static final byte BOOT_PATCH_LEVEL = 18; - public static final byte BOOT_VERIFIED_BOOT_KEY = 19; - public static final byte BOOT_VERIFIED_BOOT_HASH = 20; - public static final byte BOOT_VERIFIED_BOOT_STATE = 21; - public static final byte BOOT_DEVICE_LOCKED_STATUS = 22; - public static final byte BOOT_DEVICE_LOCKED_TIME = 23; + public static final byte ATT_EC_KEY = 11; + public static final byte CERT_ISSUER = 12; + public static final byte CERT_EXPIRY_TIME = 13; + public static final byte BOOT_OS_VERSION = 14; + public static final byte BOOT_OS_PATCH = 15; + public static final byte VENDOR_PATCH_LEVEL = 16; + public static final byte BOOT_PATCH_LEVEL = 17; + public static final byte BOOT_VERIFIED_BOOT_KEY = 18; + public static final byte BOOT_VERIFIED_BOOT_HASH = 19; + public static final byte BOOT_VERIFIED_BOOT_STATE = 20; + public static final byte BOOT_DEVICE_LOCKED_STATUS = 21; + public static final byte BOOT_DEVICE_LOCKED_TIME = 22; // Data Item sizes public static final short MASTER_KEY_SIZE = 16; @@ -90,6 +91,7 @@ public class KMRepository implements KMUpgradable { private byte[] dataTable; private short dataIndex; private short reclaimIndex; + private AESKey masterKey; // Singleton instance private static KMRepository repository; @@ -249,9 +251,19 @@ public void releaseOperation(KMOperationState op) { } } - public void initMasterKey(byte[] key, short start, short len) { - if(len != MASTER_KEY_SIZE) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); - writeDataEntry(MASTER_KEY,key, start, len); + /** + * Masterkey is stored as a Javacard Key object instead of byte array. + * When master key is stored as a Key object, the Javacard OS internally + * provides appropriate security measures for the key to protect the key. + * The master key is maintained by Repository class so the Key object is + * created in this class itself rather than creating it in the SEProvider. + */ + public void initMasterKey(byte[] buf, short off, short len) { + if (len != MASTER_KEY_SIZE) + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + masterKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, + (short) (MASTER_KEY_SIZE * 8), false); + masterKey.setKey(buf, off); } public void initHmacSharedSecretKey(byte[] key, short start, short len) { @@ -296,8 +308,10 @@ public void onSelect() { // If write through caching is implemented then this method will restore the data into cache } - public short getMasterKeySecret() { - return readData(MASTER_KEY); + public void getMasterKeySecret(byte[] buffer, short offset, short length) { + if (length != MASTER_KEY_SIZE) + ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + masterKey.getKey(buffer, offset); } // This function uses memory from the back of the heap(transient memory). Call @@ -629,12 +643,14 @@ public void setBootState(byte state){ public void onSave(Element ele) { ele.write(dataIndex); ele.write(dataTable); + ele.write(masterKey); } @Override public void onRestore(Element ele) { dataIndex = ele.readShort(); dataTable = (byte[]) ele.readObject(); + masterKey = (AESKey) ele.readObject(); } @Override @@ -646,6 +662,6 @@ public short getBackupPrimitiveByteCount() { @Override public short getBackupObjectCount() { // dataTable - return (short) 1; + return (short) 2; } } From d32c0c0c38193246522c1bbc16dccfb4ed383593 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Sun, 31 Jan 2021 08:37:33 +0530 Subject: [PATCH 10/21] updated the sample_json.txt to use 3 certificates instead of 2 --- HAL/keymaster/4.1/SocketTransport.cpp | 2 +- provisioning_tool/sample_json.txt | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/HAL/keymaster/4.1/SocketTransport.cpp b/HAL/keymaster/4.1/SocketTransport.cpp index 51c28675..331a00b1 100644 --- a/HAL/keymaster/4.1/SocketTransport.cpp +++ b/HAL/keymaster/4.1/SocketTransport.cpp @@ -24,7 +24,7 @@ #define PORT 8080 #define IPADDR "10.9.40.24" //#define IPADDR "192.168.0.5" -#define MAX_RECV_BUFFER_SIZE 2048 +#define MAX_RECV_BUFFER_SIZE 2500 namespace se_transport { diff --git a/provisioning_tool/sample_json.txt b/provisioning_tool/sample_json.txt index 8751c6b4..fbfd71de 100644 --- a/provisioning_tool/sample_json.txt +++ b/provisioning_tool/sample_json.txt @@ -23,6 +23,7 @@ "attest_key": "/data/vendor/batch_key.der", "attest_cert_chain": [ "/data/vendor/batch_cert.der", - "/data/vendor/root_cert.der" + "/data/vendor/intermediate_cert.der", + "/data/vendor/ca_cert.der" ] } From ee9ddb367472c1fecf173eb5f89ba9dbd20f86c7 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Mon, 1 Feb 2021 10:10:40 +0530 Subject: [PATCH 11/21] Removed the changes relating to storing master key as Key object --- .../javacard/keymaster/KMKeymasterApplet.java | 12 +--- .../javacard/keymaster/KMRepository.java | 62 +++++++------------ 2 files changed, 25 insertions(+), 49 deletions(-) diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 6074038b..a85a7243 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -1530,11 +1530,7 @@ private void setUniqueId(KMAttestationCert cert, byte[] scratchPad) { } //master key. - tmpVariables[2] = KMByteBlob.instance(KMRepository.MASTER_KEY_SIZE); - repository.getMasterKeySecret( - KMByteBlob.cast(tmpVariables[2]).getBuffer(), - KMByteBlob.cast(tmpVariables[2]).getStartOff(), - KMByteBlob.cast(tmpVariables[2]).length()); + tmpVariables[2] = repository.getMasterKeySecret(); cert.makeUniqueId( scratchPad, (short) 0, @@ -3907,11 +3903,7 @@ private static short deriveKey(byte[] scratchPad) { // Input data - Encrypted output (Generated in step 2). // 4. HMAC Sign generates an output of 32 bytes length. // Consume only first 16 bytes as derived key. - tmpVariables[4] = KMByteBlob.instance(KMRepository.MASTER_KEY_SIZE); - repository.getMasterKeySecret( - KMByteBlob.cast(tmpVariables[4]).getBuffer(), - KMByteBlob.cast(tmpVariables[4]).getStartOff(), - KMByteBlob.cast(tmpVariables[4]).length()); + tmpVariables[4] = repository.getMasterKeySecret(); tmpVariables[5] = repository.alloc(AES_GCM_AUTH_TAG_LENGTH); tmpVariables[3] = seProvider.aesGCMEncrypt( diff --git a/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/src/com/android/javacard/keymaster/KMRepository.java index 94951348..4c30a613 100644 --- a/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/Applet/src/com/android/javacard/keymaster/KMRepository.java @@ -22,8 +22,6 @@ import javacard.framework.ISOException; import javacard.framework.JCSystem; import javacard.framework.Util; -import javacard.security.AESKey; -import javacard.security.KeyBuilder; /** * KMRepository class manages persistent and volatile memory usage by the applet. Note the repository @@ -31,7 +29,7 @@ */ public class KMRepository implements KMUpgradable { // Data table configuration - public static final short DATA_INDEX_SIZE = 23; + public static final short DATA_INDEX_SIZE = 24; public static final short DATA_INDEX_ENTRY_SIZE = 4; public static final short DATA_MEM_SIZE = 2048; public static final short HEAP_SIZE = 10000; @@ -44,9 +42,10 @@ public class KMRepository implements KMUpgradable { private static final short OPERATION_HANDLE_ENTRY_SIZE = OPERATION_HANDLE_SIZE + OPERATION_HANDLE_STATUS_SIZE; // Data table offsets - public static final byte SHARED_KEY = 8; - public static final byte COMPUTED_HMAC_KEY = 9; - public static final byte HMAC_NONCE = 10; + public static final byte MASTER_KEY = 8; + public static final byte SHARED_KEY = 9; + public static final byte COMPUTED_HMAC_KEY = 10; + public static final byte HMAC_NONCE = 11; public static final byte ATT_ID_BRAND = 0; public static final byte ATT_ID_DEVICE = 1; public static final byte ATT_ID_PRODUCT = 2; @@ -55,18 +54,18 @@ public class KMRepository implements KMUpgradable { public static final byte ATT_ID_MEID = 5; public static final byte ATT_ID_MANUFACTURER = 6; public static final byte ATT_ID_MODEL = 7; - public static final byte ATT_EC_KEY = 11; - public static final byte CERT_ISSUER = 12; - public static final byte CERT_EXPIRY_TIME = 13; - public static final byte BOOT_OS_VERSION = 14; - public static final byte BOOT_OS_PATCH = 15; - public static final byte VENDOR_PATCH_LEVEL = 16; - public static final byte BOOT_PATCH_LEVEL = 17; - public static final byte BOOT_VERIFIED_BOOT_KEY = 18; - public static final byte BOOT_VERIFIED_BOOT_HASH = 19; - public static final byte BOOT_VERIFIED_BOOT_STATE = 20; - public static final byte BOOT_DEVICE_LOCKED_STATUS = 21; - public static final byte BOOT_DEVICE_LOCKED_TIME = 22; + public static final byte ATT_EC_KEY = 12; + public static final byte CERT_ISSUER = 13; + public static final byte CERT_EXPIRY_TIME = 14; + public static final byte BOOT_OS_VERSION = 15; + public static final byte BOOT_OS_PATCH = 16; + public static final byte VENDOR_PATCH_LEVEL = 17; + public static final byte BOOT_PATCH_LEVEL = 18; + public static final byte BOOT_VERIFIED_BOOT_KEY = 19; + public static final byte BOOT_VERIFIED_BOOT_HASH = 20; + public static final byte BOOT_VERIFIED_BOOT_STATE = 21; + public static final byte BOOT_DEVICE_LOCKED_STATUS = 22; + public static final byte BOOT_DEVICE_LOCKED_TIME = 23; // Data Item sizes public static final short MASTER_KEY_SIZE = 16; @@ -91,7 +90,6 @@ public class KMRepository implements KMUpgradable { private byte[] dataTable; private short dataIndex; private short reclaimIndex; - private AESKey masterKey; // Singleton instance private static KMRepository repository; @@ -251,19 +249,9 @@ public void releaseOperation(KMOperationState op) { } } - /** - * Masterkey is stored as a Javacard Key object instead of byte array. - * When master key is stored as a Key object, the Javacard OS internally - * provides appropriate security measures for the key to protect the key. - * The master key is maintained by Repository class so the Key object is - * created in this class itself rather than creating it in the SEProvider. - */ - public void initMasterKey(byte[] buf, short off, short len) { - if (len != MASTER_KEY_SIZE) - ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); - masterKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, - (short) (MASTER_KEY_SIZE * 8), false); - masterKey.setKey(buf, off); + public void initMasterKey(byte[] key, short start, short len) { + if(len != MASTER_KEY_SIZE) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); + writeDataEntry(MASTER_KEY,key, start, len); } public void initHmacSharedSecretKey(byte[] key, short start, short len) { @@ -308,10 +296,8 @@ public void onSelect() { // If write through caching is implemented then this method will restore the data into cache } - public void getMasterKeySecret(byte[] buffer, short offset, short length) { - if (length != MASTER_KEY_SIZE) - ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); - masterKey.getKey(buffer, offset); + public short getMasterKeySecret() { + return readData(MASTER_KEY); } // This function uses memory from the back of the heap(transient memory). Call @@ -643,14 +629,12 @@ public void setBootState(byte state){ public void onSave(Element ele) { ele.write(dataIndex); ele.write(dataTable); - ele.write(masterKey); } @Override public void onRestore(Element ele) { dataIndex = ele.readShort(); dataTable = (byte[]) ele.readObject(); - masterKey = (AESKey) ele.readObject(); } @Override @@ -662,6 +646,6 @@ public short getBackupPrimitiveByteCount() { @Override public short getBackupObjectCount() { // dataTable - return (short) 2; + return (short) 1; } } From 4c9794e7160140b54c94cb3682e3a723c920eac8 Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Tue, 2 Feb 2021 18:06:17 +0530 Subject: [PATCH 12/21] Added log statements --- provisioning_tool/provision_tool.cpp | 44 ++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/provisioning_tool/provision_tool.cpp b/provisioning_tool/provision_tool.cpp index e3148fec..0f240b3c 100644 --- a/provisioning_tool/provision_tool.cpp +++ b/provisioning_tool/provision_tool.cpp @@ -177,6 +177,7 @@ bool getBootParameterBlobValue(Json::Value& bootParamsObj, const char* key, std: bool setBootParameters(const char* filename) { Json::Value bootParamsObj; bool ret = false; + ErrorCode err = ErrorCode::OK; keymaster::V4_1::javacard::BootParams bootParams; if(!parseJsonFile(filename)) @@ -219,10 +220,12 @@ bool setBootParameters(const char* filename) { } } else { + printf("\n Fail: Improper value found for set_boot_params key inside the json file\n"); return ret; } - if (ErrorCode::OK != mProvision.provisionBootParameters(bootParams)) { + if (ErrorCode::OK != (err = mProvision.provisionBootParameters(bootParams))) { + printf("\n set boot parameters failed with err:%d \n", (int32_t)err); return ret; } @@ -233,6 +236,7 @@ bool setBootParameters(const char* filename) { bool provisionAttestationIds(const char *filename) { Json::Value attestIds; bool ret = false; + ErrorCode err = ErrorCode::OK; keymaster::V4_1::javacard::AttestIDParams params; if(!parseJsonFile(filename)) @@ -248,6 +252,7 @@ bool provisionAttestationIds(const char *filename) { continue; } if (!value.isString()) { + printf("\n Fail: Value for each attest ids key should be a string in the json file \n"); return ret; } @@ -273,10 +278,12 @@ bool provisionAttestationIds(const char *filename) { } } - if (ErrorCode::OK != mProvision.provisionAttestationID(params)) { + if (ErrorCode::OK != (err = mProvision.provisionAttestationID(params))) { + printf("\n Provision attestationID parameters failed with err:%d \n", (int32_t)err); return ret; } } else { + printf("\n Fail: Improper value found for attest_ids key inside the json file \n"); return ret; } printf("\n provisioned attestation ids successfully \n"); @@ -330,6 +337,7 @@ bool getProvisionStatus() { bool provisionSharedSecret(const char* filename) { Json::Value sharedSecret; bool ret = false; + ErrorCode err = ErrorCode::OK; if(!parseJsonFile(filename)) return ret; @@ -338,14 +346,17 @@ bool provisionSharedSecret(const char* filename) { if (!sharedSecret.isNull()) { if (!sharedSecret.isString()) { + printf("\n Fail: Value for shared secret key should be string inside the json file\n"); return ret; } std::string secret = hex2str(sharedSecret.asString()); std::vector data(secret.begin(), secret.end()); - if(ErrorCode::OK != mProvision.provisionPreSharedSecret(data)) { + if(ErrorCode::OK != (err = mProvision.provisionPreSharedSecret(data))) { + printf("\n Provision pre-shared secret failed with err:%d \n", (int32_t)err); return ret; } } else { + printf("\n Fail: Improper value for shared_secret key inside the json file\n"); return ret; } printf("\n Provisioned shared secret successfully \n"); @@ -355,6 +366,7 @@ bool provisionSharedSecret(const char* filename) { static bool provisionAttestationKey(const char* filename) { Json::Value keyFile; bool ret = false; + ErrorCode err = ErrorCode::OK; if(!parseJsonFile(filename)) return ret; @@ -368,10 +380,12 @@ static bool provisionAttestationKey(const char* filename) { printf("\n Failed to read the Root ec key\n"); return ret; } - if(ErrorCode::OK != mProvision.provisionAttestationKey(data)) { + if(ErrorCode::OK != (err = mProvision.provisionAttestationKey(data))) { + printf("\n Provision attestation key failed with error: %d\n", (int32_t)err); return ret; } } else { + printf("\n Improper value for attest_key in json file \n"); return ret; } printf("\n Provisioned attestation key successfully\n"); @@ -381,6 +395,7 @@ static bool provisionAttestationKey(const char* filename) { bool provisionAttestationCertificateChain(const char* filename) { Json::Value certChainFile; bool ret = false; + ErrorCode err = ErrorCode::OK; if(!parseJsonFile(filename)) return ret; @@ -400,16 +415,20 @@ bool provisionAttestationCertificateChain(const char* filename) { } certData.push_back(std::move(tmp)); } else { + printf("\n Fail: Only proper certificate paths as a string is allowed inside the json file. \n"); return ret; } } } else { + printf("\n Fail: cert chain value should be an array inside the json file. \n"); return ret; } - if (ErrorCode::OK != mProvision.provisionAtestationCertificateChain(certData)) { + if (ErrorCode::OK != (err = mProvision.provisionAtestationCertificateChain(certData))) { + printf("\n Provision certificate chain failed with error: %d\n", (int32_t)err); return ret; } } else { + printf("\n Fail: Improper value found for attest_cert_chain key inside json file \n"); return ret; } printf("\n Provisioned attestation certificate chain successfully\n"); @@ -419,6 +438,7 @@ bool provisionAttestationCertificateChain(const char* filename) { bool provisionAttestationCertificateParams(const char* filename) { Json::Value certChainFile; bool ret = false; + ErrorCode err = ErrorCode::OK; if(!parseJsonFile(filename)) return ret; @@ -436,13 +456,16 @@ bool provisionAttestationCertificateParams(const char* filename) { printf("\n Failed to read the Root certificate\n"); return ret; } - if (ErrorCode::OK != mProvision.provisionAttestationCertificateParams(tmp)) { + if (ErrorCode::OK != (err = mProvision.provisionAttestationCertificateParams(tmp))) { + printf("\n Provision certificate params failed with error: %d\n", (int32_t)err); return ret; } } else { + printf("\n Fail: cert chain value should be an array inside the json file. \n"); return ret; } } else { + printf("\n Fail: Improper value found for attest_cert_chain key inside json file \n"); return ret; } printf("\n Provisioned attestation certificate parameters successfully\n"); @@ -452,27 +475,21 @@ bool provisionAttestationCertificateParams(const char* filename) { bool provision(const char* filename) { if(!provisionAttestationKey(filename)) { - printf("\n Failed to provision attestation Key\n"); return false; } if(!provisionAttestationCertificateChain(filename)) { - printf("\n Failed to provision certificate chain\n"); return false; } if(!provisionAttestationCertificateParams(filename)) { - printf("\n Failed to provision certificate paramters\n"); return false; } if(!provisionSharedSecret(filename)) { - printf("\n Failed to provision shared secret\n"); return false; } if(!provisionAttestationIds(filename)) { - printf("\n Failed to provision attestation ids\n"); return false; } if(!setBootParameters(filename)) { - printf("\n Failed to set boot parameters\n"); return false; } return true; @@ -526,7 +543,8 @@ int main(int argc, char* argv[]) switch(c) { case 'a': //all - provision(optarg); + if(!provision(optarg)) + printf("\n Failed to provision the device \n"); break; case 'k': //attest key From e51ab8a0922d868a86eb7769b6f50414fb5bb676 Mon Sep 17 00:00:00 2001 From: bvenkateswarlu Date: Tue, 2 Feb 2021 18:11:17 +0530 Subject: [PATCH 13/21] 1. Corrected the convertToDate algorithm to generate correct time and date. 2. Added new method for UnsignedArrayCompare. --- .../android/javacard/keymaster/KMUtils.java | 172 ++++++++++++++---- .../keymaster/KMRsa2048NoDigestSignature.java | 2 +- .../android/javacard/keymaster/KMUtils.java | 170 +++++++++++++---- .../android/javacard/keymaster/KMInteger.java | 2 +- .../javacard/keymaster/KMKeymasterApplet.java | 4 +- 5 files changed, 281 insertions(+), 69 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java index d9d7e111..cb8df259 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java @@ -14,23 +14,36 @@ public class KMUtils { 0, 0, 0, 0, 0x05, 0x26, 0x5C, 0x00 }; // 86400000 msec public static final byte[] oneMonthMsec = { 0, 0, 0, 0, (byte) 0x9C,(byte) 0xBE, (byte) 0xBD, 0x50}; // 2629746000 msec - public static final byte[] oneYearMsec = { - 0, 0, 0, 0x07, 0x58, (byte) 0xF0, (byte) 0xDF, (byte) 0xC0 }; // 31556952000 msec - // Leap year + 3 yrs + public static final byte[] leapYearMsec = { + 0, 0, 0, 0x07, (byte) 0x5C, (byte) 0xD7, (byte) 0x88, 0x00}; //31622400000; + public static final byte[] yearMsec = { + 0, 0, 0, 0x07, 0x57, (byte) 0xB1, 0x2C, 0x00}; //31536000000 + //Leap year(366) + 3 * 365 public static final byte[] fourYrsMsec = { - 0, 0, 0, 0x1D, 0x63, (byte) 0xC3, 0x7F, 0x00 }; // 126227808000 msec + 0, 0, 0, 0x1D, 0x63, (byte) 0xEB, 0x0C, 0x00};//126230400000 public static final byte[] firstJan2020 = { - 0, 0, 0x01, 0x6F, 0x5E, 0x66, (byte)0xE8, 0x00 }; // 1577836800000 msec + 0, 0, 0x01, 0x6F, 0x5E, 0x66, (byte)0xE8, 0x00 }; // 1577836800000 msec public static final byte[] firstJan2051 = { 0, 0, 0x02, 0x53, 0x26, (byte) 0x0E, (byte) 0x1C, 0x00 }; // 2556144000000 // msec + public static final byte[] febMonthLeapMSec = { + 0, 0, 0, 0, (byte) 0x95, 0x58, 0x6C, 0x00 }; //2505600000 + public static final byte[] febMonthMsec = { + 0, 0, 0, 0, (byte) 0x90, 0x32, 0x10, 0x00 }; //2419200000 + public static final byte[] ThirtyOneDaysMonthMsec = { + 0, 0, 0, 0, (byte) 0x9F, (byte) 0xA5, 0x24, 0x00 };//2678400000 + public static final byte[] ThirtDaysMonthMsec = { + 0, 0, 0, 0, (byte) 0x9A, 0x7E, (byte) 0xC8, 0x00 };//2592000000 + public static final short year2051 = 2051; + public static final short year2020 = 2020; // -------------------------------------- public static short convertToDate(short time, byte[] scratchPad, boolean utcFlag) { + short yrsCount = 0; short monthCount = 1; - short dayCount = 0; + short dayCount = 1; short hhCount = 0; short mmCount = 0; short ssCount = 0; @@ -42,17 +55,17 @@ public static short convertToDate(short time, byte[] scratchPad, (short) (8 - KMInteger.cast(time).length()), KMInteger.cast(time) .length()); // If the time is less then 1 Jan 2020 then it is an error - if (Util.arrayCompare(scratchPad, (short) 0, firstJan2020, (short) 0, + if (unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2020, (short) 0, (short) 8) < 0) { KMException.throwIt(KMError.INVALID_ARGUMENT); } if (utcFlag - && Util.arrayCompare(scratchPad, (short) 0, firstJan2051, + && unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, (short) 0, (short) 8) >= 0) { KMException.throwIt(KMError.INVALID_ARGUMENT); } - if (Util.arrayCompare(scratchPad, (short) 0, firstJan2051, (short) 0, + if (unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, (short) 0, (short) 8) < 0) { Util.arrayCopyNonAtomic(firstJan2020, (short) 0, scratchPad, (short) 8, (short) 8); @@ -68,7 +81,7 @@ public static short convertToDate(short time, byte[] scratchPad, (short) 8); } // divide the given time with four yrs msec count - if (Util.arrayCompare(scratchPad, (short) 0, fourYrsMsec, (short) 0, + if (unsignedByteArrayCompare(scratchPad, (short) 0, fourYrsMsec, (short) 0, (short) 8) >= 0) { Util.arrayCopyNonAtomic(fourYrsMsec, (short) 0, scratchPad, (short) 8, (short) 8); @@ -81,44 +94,97 @@ public static short convertToDate(short time, byte[] scratchPad, Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, (short) 8); } - // divide the given time with one yr msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneYearMsec, (short) 0, - (short) 8) >= 0) { - Util.arrayCopyNonAtomic(oneYearMsec, (short) 0, scratchPad, (short) 8, - (short) 8); - yrsCount += divide(scratchPad, (short) 0, (short) 8, (short) 16); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); + + //Get the leap year index starting from the (base Year + yrsCount) Year. + short leapYrIdx = getLeapYrIndex(from2020, yrsCount); + + // if leap year index is 0, then the number of days for the 1st year will be 366 days. + // if leap year index is not 0, then the number of days for the 1st year will be 365 days. + if (((leapYrIdx == 0) && + (unsignedByteArrayCompare(scratchPad, (short) 0, leapYearMsec, (short) 0,(short) 8) >= 0)) || + ((leapYrIdx != 0) && + (unsignedByteArrayCompare(scratchPad, (short) 0, yearMsec, (short) 0,(short) 8) >= 0))) { + for (short i = 0; i < 4; i++) { + yrsCount++; + if (i == leapYrIdx) { + Util.arrayCopyNonAtomic(leapYearMsec, (short) 0, scratchPad, + (short) 8, (short) 8); + } else { + Util.arrayCopyNonAtomic(yearMsec, (short) 0, scratchPad, (short) 8, + (short) 8); + } + subtract(scratchPad, (short) 0, (short) 8, (short) 16); + Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, + (short) 8); + if (((short) (i + 1) == leapYrIdx)) { + if (unsignedByteArrayCompare(scratchPad, (short) 0, leapYearMsec, + (short) 0, (short) 8) < 0) { + break; + } + } else { + if (unsignedByteArrayCompare(scratchPad, (short) 0, yearMsec, + (short) 0, (short) 8) < 0) { + break; + } + } + } } + // total yrs from 1970 if (from2020) - yrsCount = (short) (2020 + yrsCount); + yrsCount = (short) (year2020 + yrsCount); else - yrsCount = (short) (2051 + yrsCount); + yrsCount = (short) (year2051 + yrsCount); // divide the given time with one month msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneMonthMsec, (short) 0, + if (unsignedByteArrayCompare(scratchPad, (short) 0, oneMonthMsec, (short) 0, (short) 8) >= 0) { - Util.arrayCopyNonAtomic(oneMonthMsec, (short) 0, scratchPad, (short) 8, - (short) 8); - monthCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); - monthCount++; - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); + for (short i = 0; i < 12; i++) { + if (i == 1) { + // Feb month + if (isLeapYear(yrsCount)) { + // Leap year 29 days + Util.arrayCopyNonAtomic(febMonthLeapMSec, (short) 0, scratchPad, + (short) 8, (short) 8); + } else { + // 28 days + Util.arrayCopyNonAtomic(febMonthMsec, (short) 0, scratchPad, + (short) 8, (short) 8); + } + } else if (((i <= 6) && ((i % 2 == 0))) || ((i > 6) && ((i % 2 == 1)))) { + Util.arrayCopyNonAtomic(ThirtyOneDaysMonthMsec, (short) 0, + scratchPad, (short) 8, (short) 8); + } else { + // 30 Days + Util.arrayCopyNonAtomic(ThirtDaysMonthMsec, (short) 0, scratchPad, + (short) 8, (short) 8); + } + + if (unsignedByteArrayCompare(scratchPad, (short) 0, scratchPad, (short) 8, + (short) 8) >= 0) { + subtract(scratchPad, (short) 0, (short) 8, (short) 16); + Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, + (short) 8); + } else { + break; + } + monthCount++; + } } // divide the given time with one day msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneDayMsec, (short) 0, + if (unsignedByteArrayCompare(scratchPad, (short) 0, oneDayMsec, (short) 0, (short) 8) >= 0) { Util.arrayCopyNonAtomic(oneDayMsec, (short) 0, scratchPad, (short) 8, (short) 8); dayCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); + dayCount++; Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, (short) 8); } // divide the given time with one hour msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneHourMsec, (short) 0, + if (unsignedByteArrayCompare(scratchPad, (short) 0, oneHourMsec, (short) 0, (short) 8) >= 0) { Util.arrayCopyNonAtomic(oneHourMsec, (short) 0, scratchPad, (short) 8, (short) 8); @@ -128,7 +194,7 @@ public static short convertToDate(short time, byte[] scratchPad, } // divide the given time with one minute msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneMinMsec, (short) 0, + if (unsignedByteArrayCompare(scratchPad, (short) 0, oneMinMsec, (short) 0, (short) 8) >= 0) { Util.arrayCopyNonAtomic(oneMinMsec, (short) 0, scratchPad, (short) 8, (short) 8); @@ -138,7 +204,7 @@ public static short convertToDate(short time, byte[] scratchPad, } // divide the given time with one second msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneSecMsec, (short) 0, + if (unsignedByteArrayCompare(scratchPad, (short) 0, oneSecMsec, (short) 0, (short) 8) >= 0) { Util.arrayCopyNonAtomic(oneSecMsec, (short) 0, scratchPad, (short) 8, (short) 8); @@ -163,6 +229,25 @@ public static short convertToDate(short time, byte[] scratchPad, return KMByteBlob.instance(scratchPad, (short) 0, len); // YYYY } + public static byte unsignedByteArrayCompare(byte[] a1, short offset1, byte[] a2, short offset2, short length) { + byte count = (byte) 0; + short val1 = (short)0; + short val2 = (short)0; + + for (; count < length; count++) { + val1 = (short) (a1[(short) (count + offset1)] & 0x00FF); + val2 = (short) (a2[(short) (count + offset2)] & 0x00FF); + + if (val1 < val2) { + return -1; + } + if (val1 > val2) { + return 1; + } + } + return 0; + } + public static short numberToString(short number, byte[] scratchPad, short offset) { byte zero = 0x30; @@ -211,7 +296,7 @@ public static void copy(byte[] buf, short from, short to) { } public static byte compare(byte[] buf, short lhs, short rhs) { - return Util.arrayCompare(buf, lhs, buf, rhs, (short) 8); + return unsignedByteArrayCompare(buf, lhs, buf, rhs, (short) 8); } public static void shiftLeft(byte[] buf, short start) { @@ -319,4 +404,25 @@ public static short countTemporalCount(byte[] bufTime, short timeOff, return divide(scratchPad, (short) 0, (short) 8, (short) 16); } -} + public static boolean isLeapYear(short year) { + if ((short)(year%4) == (short) 0) { + if (((short)(year % 100) == (short) 0) && + ((short) (year % 400)) != (short) 0) { + return false; + } + return true; + } + return false; + } + + public static short getLeapYrIndex(boolean from2020, short yrsCount) { + short newBaseYr = (short) (from2020 ? (year2020 + yrsCount) : (year2051 + yrsCount)); + for(short i = 0; i < 4; i++) { + if(isLeapYear((short)(newBaseYr + i))) { + return i; + } + } + return -1; + } + +} \ No newline at end of file diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java index 38e9a3bc..3ebf5fe0 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMRsa2048NoDigestSignature.java @@ -107,7 +107,7 @@ private boolean isValidData(byte[] buf, short start, short len) { if (padding == KMType.PADDING_NONE) { if (len > 256) return false; else if (len == 256) { - short v = Util.arrayCompare(buf, start, rsaModulus, (short) 0, len); + short v = KMUtils.unsignedByteArrayCompare(buf, start, rsaModulus, (short) 0, len); if (v > 0) return false; } } else {//pkcs1 no digest diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java index 41bbe1ff..cb8df259 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java @@ -14,23 +14,36 @@ public class KMUtils { 0, 0, 0, 0, 0x05, 0x26, 0x5C, 0x00 }; // 86400000 msec public static final byte[] oneMonthMsec = { 0, 0, 0, 0, (byte) 0x9C,(byte) 0xBE, (byte) 0xBD, 0x50}; // 2629746000 msec - public static final byte[] oneYearMsec = { - 0, 0, 0, 0x07, 0x58, (byte) 0xF0, (byte) 0xDF, (byte) 0xC0 }; // 31556952000 msec - // Leap year + 3 yrs + public static final byte[] leapYearMsec = { + 0, 0, 0, 0x07, (byte) 0x5C, (byte) 0xD7, (byte) 0x88, 0x00}; //31622400000; + public static final byte[] yearMsec = { + 0, 0, 0, 0x07, 0x57, (byte) 0xB1, 0x2C, 0x00}; //31536000000 + //Leap year(366) + 3 * 365 public static final byte[] fourYrsMsec = { - 0, 0, 0, 0x1D, 0x63, (byte) 0xC3, 0x7F, 0x00 }; // 126227808000 msec + 0, 0, 0, 0x1D, 0x63, (byte) 0xEB, 0x0C, 0x00};//126230400000 public static final byte[] firstJan2020 = { 0, 0, 0x01, 0x6F, 0x5E, 0x66, (byte)0xE8, 0x00 }; // 1577836800000 msec public static final byte[] firstJan2051 = { 0, 0, 0x02, 0x53, 0x26, (byte) 0x0E, (byte) 0x1C, 0x00 }; // 2556144000000 // msec + public static final byte[] febMonthLeapMSec = { + 0, 0, 0, 0, (byte) 0x95, 0x58, 0x6C, 0x00 }; //2505600000 + public static final byte[] febMonthMsec = { + 0, 0, 0, 0, (byte) 0x90, 0x32, 0x10, 0x00 }; //2419200000 + public static final byte[] ThirtyOneDaysMonthMsec = { + 0, 0, 0, 0, (byte) 0x9F, (byte) 0xA5, 0x24, 0x00 };//2678400000 + public static final byte[] ThirtDaysMonthMsec = { + 0, 0, 0, 0, (byte) 0x9A, 0x7E, (byte) 0xC8, 0x00 };//2592000000 + public static final short year2051 = 2051; + public static final short year2020 = 2020; // -------------------------------------- public static short convertToDate(short time, byte[] scratchPad, boolean utcFlag) { + short yrsCount = 0; short monthCount = 1; - short dayCount = 0; + short dayCount = 1; short hhCount = 0; short mmCount = 0; short ssCount = 0; @@ -42,17 +55,17 @@ public static short convertToDate(short time, byte[] scratchPad, (short) (8 - KMInteger.cast(time).length()), KMInteger.cast(time) .length()); // If the time is less then 1 Jan 2020 then it is an error - if (Util.arrayCompare(scratchPad, (short) 0, firstJan2020, (short) 0, + if (unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2020, (short) 0, (short) 8) < 0) { KMException.throwIt(KMError.INVALID_ARGUMENT); } if (utcFlag - && Util.arrayCompare(scratchPad, (short) 0, firstJan2051, + && unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, (short) 0, (short) 8) >= 0) { KMException.throwIt(KMError.INVALID_ARGUMENT); } - if (Util.arrayCompare(scratchPad, (short) 0, firstJan2051, (short) 0, + if (unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, (short) 0, (short) 8) < 0) { Util.arrayCopyNonAtomic(firstJan2020, (short) 0, scratchPad, (short) 8, (short) 8); @@ -68,7 +81,7 @@ public static short convertToDate(short time, byte[] scratchPad, (short) 8); } // divide the given time with four yrs msec count - if (Util.arrayCompare(scratchPad, (short) 0, fourYrsMsec, (short) 0, + if (unsignedByteArrayCompare(scratchPad, (short) 0, fourYrsMsec, (short) 0, (short) 8) >= 0) { Util.arrayCopyNonAtomic(fourYrsMsec, (short) 0, scratchPad, (short) 8, (short) 8); @@ -81,44 +94,97 @@ public static short convertToDate(short time, byte[] scratchPad, Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, (short) 8); } - // divide the given time with one yr msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneYearMsec, (short) 0, - (short) 8) >= 0) { - Util.arrayCopyNonAtomic(oneYearMsec, (short) 0, scratchPad, (short) 8, - (short) 8); - yrsCount += divide(scratchPad, (short) 0, (short) 8, (short) 16); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); + + //Get the leap year index starting from the (base Year + yrsCount) Year. + short leapYrIdx = getLeapYrIndex(from2020, yrsCount); + + // if leap year index is 0, then the number of days for the 1st year will be 366 days. + // if leap year index is not 0, then the number of days for the 1st year will be 365 days. + if (((leapYrIdx == 0) && + (unsignedByteArrayCompare(scratchPad, (short) 0, leapYearMsec, (short) 0,(short) 8) >= 0)) || + ((leapYrIdx != 0) && + (unsignedByteArrayCompare(scratchPad, (short) 0, yearMsec, (short) 0,(short) 8) >= 0))) { + for (short i = 0; i < 4; i++) { + yrsCount++; + if (i == leapYrIdx) { + Util.arrayCopyNonAtomic(leapYearMsec, (short) 0, scratchPad, + (short) 8, (short) 8); + } else { + Util.arrayCopyNonAtomic(yearMsec, (short) 0, scratchPad, (short) 8, + (short) 8); + } + subtract(scratchPad, (short) 0, (short) 8, (short) 16); + Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, + (short) 8); + if (((short) (i + 1) == leapYrIdx)) { + if (unsignedByteArrayCompare(scratchPad, (short) 0, leapYearMsec, + (short) 0, (short) 8) < 0) { + break; + } + } else { + if (unsignedByteArrayCompare(scratchPad, (short) 0, yearMsec, + (short) 0, (short) 8) < 0) { + break; + } + } + } } + // total yrs from 1970 if (from2020) - yrsCount = (short) (2020 + yrsCount); + yrsCount = (short) (year2020 + yrsCount); else - yrsCount = (short) (2051 + yrsCount); + yrsCount = (short) (year2051 + yrsCount); // divide the given time with one month msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneMonthMsec, (short) 0, + if (unsignedByteArrayCompare(scratchPad, (short) 0, oneMonthMsec, (short) 0, (short) 8) >= 0) { - Util.arrayCopyNonAtomic(oneMonthMsec, (short) 0, scratchPad, (short) 8, - (short) 8); - monthCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); - monthCount++; - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); + for (short i = 0; i < 12; i++) { + if (i == 1) { + // Feb month + if (isLeapYear(yrsCount)) { + // Leap year 29 days + Util.arrayCopyNonAtomic(febMonthLeapMSec, (short) 0, scratchPad, + (short) 8, (short) 8); + } else { + // 28 days + Util.arrayCopyNonAtomic(febMonthMsec, (short) 0, scratchPad, + (short) 8, (short) 8); + } + } else if (((i <= 6) && ((i % 2 == 0))) || ((i > 6) && ((i % 2 == 1)))) { + Util.arrayCopyNonAtomic(ThirtyOneDaysMonthMsec, (short) 0, + scratchPad, (short) 8, (short) 8); + } else { + // 30 Days + Util.arrayCopyNonAtomic(ThirtDaysMonthMsec, (short) 0, scratchPad, + (short) 8, (short) 8); + } + + if (unsignedByteArrayCompare(scratchPad, (short) 0, scratchPad, (short) 8, + (short) 8) >= 0) { + subtract(scratchPad, (short) 0, (short) 8, (short) 16); + Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, + (short) 8); + } else { + break; + } + monthCount++; + } } // divide the given time with one day msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneDayMsec, (short) 0, + if (unsignedByteArrayCompare(scratchPad, (short) 0, oneDayMsec, (short) 0, (short) 8) >= 0) { Util.arrayCopyNonAtomic(oneDayMsec, (short) 0, scratchPad, (short) 8, (short) 8); dayCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); + dayCount++; Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, (short) 8); } // divide the given time with one hour msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneHourMsec, (short) 0, + if (unsignedByteArrayCompare(scratchPad, (short) 0, oneHourMsec, (short) 0, (short) 8) >= 0) { Util.arrayCopyNonAtomic(oneHourMsec, (short) 0, scratchPad, (short) 8, (short) 8); @@ -128,7 +194,7 @@ public static short convertToDate(short time, byte[] scratchPad, } // divide the given time with one minute msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneMinMsec, (short) 0, + if (unsignedByteArrayCompare(scratchPad, (short) 0, oneMinMsec, (short) 0, (short) 8) >= 0) { Util.arrayCopyNonAtomic(oneMinMsec, (short) 0, scratchPad, (short) 8, (short) 8); @@ -138,7 +204,7 @@ public static short convertToDate(short time, byte[] scratchPad, } // divide the given time with one second msec count - if (Util.arrayCompare(scratchPad, (short) 0, oneSecMsec, (short) 0, + if (unsignedByteArrayCompare(scratchPad, (short) 0, oneSecMsec, (short) 0, (short) 8) >= 0) { Util.arrayCopyNonAtomic(oneSecMsec, (short) 0, scratchPad, (short) 8, (short) 8); @@ -163,6 +229,25 @@ public static short convertToDate(short time, byte[] scratchPad, return KMByteBlob.instance(scratchPad, (short) 0, len); // YYYY } + public static byte unsignedByteArrayCompare(byte[] a1, short offset1, byte[] a2, short offset2, short length) { + byte count = (byte) 0; + short val1 = (short)0; + short val2 = (short)0; + + for (; count < length; count++) { + val1 = (short) (a1[(short) (count + offset1)] & 0x00FF); + val2 = (short) (a2[(short) (count + offset2)] & 0x00FF); + + if (val1 < val2) { + return -1; + } + if (val1 > val2) { + return 1; + } + } + return 0; + } + public static short numberToString(short number, byte[] scratchPad, short offset) { byte zero = 0x30; @@ -211,7 +296,7 @@ public static void copy(byte[] buf, short from, short to) { } public static byte compare(byte[] buf, short lhs, short rhs) { - return Util.arrayCompare(buf, lhs, buf, rhs, (short) 8); + return unsignedByteArrayCompare(buf, lhs, buf, rhs, (short) 8); } public static void shiftLeft(byte[] buf, short start) { @@ -319,4 +404,25 @@ public static short countTemporalCount(byte[] bufTime, short timeOff, return divide(scratchPad, (short) 0, (short) 8, (short) 16); } -} + public static boolean isLeapYear(short year) { + if ((short)(year%4) == (short) 0) { + if (((short)(year % 100) == (short) 0) && + ((short) (year % 400)) != (short) 0) { + return false; + } + return true; + } + return false; + } + + public static short getLeapYrIndex(boolean from2020, short yrsCount) { + short newBaseYr = (short) (from2020 ? (year2020 + yrsCount) : (year2051 + yrsCount)); + for(short i = 0; i < 4; i++) { + if(isLeapYear((short)(newBaseYr + i))) { + return i; + } + } + return -1; + } + +} \ No newline at end of file diff --git a/Applet/src/com/android/javacard/keymaster/KMInteger.java b/Applet/src/com/android/javacard/keymaster/KMInteger.java index 090f6e86..18944e4d 100644 --- a/Applet/src/com/android/javacard/keymaster/KMInteger.java +++ b/Applet/src/com/android/javacard/keymaster/KMInteger.java @@ -162,7 +162,7 @@ public static short compare(short num1, short num2){ KMInteger.cast(num1).getValue(repository.getHeap(),(short)(num1Buf+(short)(8-len)),len); len = KMInteger.cast(num2).length(); KMInteger.cast(num2).getValue(repository.getHeap(),(short)(num2Buf+(short)(8-len)),len); - return Util.arrayCompare( + return KMUtils.unsignedByteArrayCompare( repository.getHeap(), num1Buf, repository.getHeap(), num2Buf, (short)8); diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index a85a7243..adedf6f5 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -3611,7 +3611,7 @@ private void checkVersionAndPatchLevel(byte[] scratchPad) { if (tmpVariables[0] != KMType.INVALID_VALUE) { tmpVariables[1] = repository.getOsVersion(); tmpVariables[1] = - Util.arrayCompare( + KMUtils.unsignedByteArrayCompare( KMInteger.cast(tmpVariables[1]).getBuffer(), KMInteger.cast(tmpVariables[1]).getStartOff(), scratchPad, @@ -3644,7 +3644,7 @@ private void checkVersionAndPatchLevel(byte[] scratchPad) { if (tmpVariables[0] != KMType.INVALID_VALUE) { tmpVariables[1] = repository.getOsPatch(); tmpVariables[1] = - Util.arrayCompare( + KMUtils.unsignedByteArrayCompare( KMInteger.cast(tmpVariables[1]).getBuffer(), KMInteger.cast(tmpVariables[1]).getStartOff(), scratchPad, From 5d3413efcb15c149cf18e75a76b6101934d275c6 Mon Sep 17 00:00:00 2001 From: BKSSMVenkateswarlu <40534495+BKSSMVenkateswarlu@users.noreply.github.com> Date: Tue, 2 Feb 2021 19:35:03 +0530 Subject: [PATCH 14/21] Update README.md --- provisioning_tool/README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/provisioning_tool/README.md b/provisioning_tool/README.md index feb804cb..b2960204 100644 --- a/provisioning_tool/README.md +++ b/provisioning_tool/README.md @@ -1 +1,9 @@ -jlkjs +# Provisioning tool +This directory contains provisioning tool which helps in provisioning +the secure element by using the APIs exposed by Provision library. +This tool takes the input parameters from json file. A sample +json file is located in this directory with name sample_json.txt for +your reference. + +#### Build +This tool has dependency on [libjc_common](https://github.com/BKSSMVenkateswarlu/JavaCardKeymaster/blob/master/HAL/keymaster/Android.bp) From 4fed4281663622627a9b7a835cf55eb03adf5db2 Mon Sep 17 00:00:00 2001 From: BKSSMVenkateswarlu <40534495+BKSSMVenkateswarlu@users.noreply.github.com> Date: Tue, 2 Feb 2021 19:39:44 +0530 Subject: [PATCH 15/21] Update README.md --- provisioning_tool/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/provisioning_tool/README.md b/provisioning_tool/README.md index b2960204..295dba93 100644 --- a/provisioning_tool/README.md +++ b/provisioning_tool/README.md @@ -6,4 +6,6 @@ json file is located in this directory with name sample_json.txt for your reference. #### Build -This tool has dependency on [libjc_common](https://github.com/BKSSMVenkateswarlu/JavaCardKeymaster/blob/master/HAL/keymaster/Android.bp) +This tool can be built along with aosp build. It has dependency on +[libjc_common](https://github.com/BKSSMVenkateswarlu/JavaCardKeymaster/blob/master/HAL/keymaster/Android.bp) and +libjc_provision. From f8ae39f913b013fc8d6a746b993889209ff166fc Mon Sep 17 00:00:00 2001 From: BKSSMVenkateswarlu <40534495+BKSSMVenkateswarlu@users.noreply.github.com> Date: Tue, 2 Feb 2021 19:49:13 +0530 Subject: [PATCH 16/21] Update README.md --- provisioning_tool/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/provisioning_tool/README.md b/provisioning_tool/README.md index 295dba93..2b9d5a23 100644 --- a/provisioning_tool/README.md +++ b/provisioning_tool/README.md @@ -9,3 +9,17 @@ your reference. This tool can be built along with aosp build. It has dependency on [libjc_common](https://github.com/BKSSMVenkateswarlu/JavaCardKeymaster/blob/master/HAL/keymaster/Android.bp) and libjc_provision. + +#### Usage +Usage: provision_tool *options* +Valid options are: +-h, --help show the help message and exit. +-a, --all jsonFile Executes all the provision commands. +-k, --attest_key jsonFile Provision attestation key. +-c, --cert_chain jsonFile Provision attestation certificate chain. +-p, --cert_params jsonFile Provision attestation certificate parameters. +-i, --attest_ids jsonFile Provision attestation IDs. +-r, --shared_secret jsonFile Provision pre-shared secret. +-b, --set_boot_params jsonFile Provision boot parameters. +-s, --provision_stautus Prints the current provision status. +-l, --lock_provision Locks the provision commands. From be8e975835970c5d4aa7d78bb7e13df9f86ec713 Mon Sep 17 00:00:00 2001 From: BKSSMVenkateswarlu <40534495+BKSSMVenkateswarlu@users.noreply.github.com> Date: Tue, 2 Feb 2021 19:52:15 +0530 Subject: [PATCH 17/21] Update README.md --- provisioning_tool/README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/provisioning_tool/README.md b/provisioning_tool/README.md index 2b9d5a23..1d69731a 100644 --- a/provisioning_tool/README.md +++ b/provisioning_tool/README.md @@ -11,15 +11,15 @@ This tool can be built along with aosp build. It has dependency on libjc_provision. #### Usage -Usage: provision_tool *options* -Valid options are: --h, --help show the help message and exit. --a, --all jsonFile Executes all the provision commands. --k, --attest_key jsonFile Provision attestation key. --c, --cert_chain jsonFile Provision attestation certificate chain. --p, --cert_params jsonFile Provision attestation certificate parameters. --i, --attest_ids jsonFile Provision attestation IDs. --r, --shared_secret jsonFile Provision pre-shared secret. --b, --set_boot_params jsonFile Provision boot parameters. --s, --provision_stautus Prints the current provision status. +Usage: provision_tool *options*\ +Valid options are:\ +-h, --help show the help message and exit.\ +-a, --all jsonFile Executes all the provision commands.\ +-k, --attest_key jsonFile Provision attestation key.\ +-c, --cert_chain jsonFile Provision attestation certificate chain.\ +-p, --cert_params jsonFile Provision attestation certificate parameters.\ +-i, --attest_ids jsonFile Provision attestation IDs.\ +-r, --shared_secret jsonFile Provision pre-shared secret.\ +-b, --set_boot_params jsonFile Provision boot parameters.\ +-s, --provision_stautus Prints the current provision status.\ -l, --lock_provision Locks the provision commands. From 7899e3b3925f684d34ee502da32bf665920a3d39 Mon Sep 17 00:00:00 2001 From: BKSSMVenkateswarlu <40534495+BKSSMVenkateswarlu@users.noreply.github.com> Date: Tue, 2 Feb 2021 19:55:33 +0530 Subject: [PATCH 18/21] Update README.md --- provisioning_tool/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/provisioning_tool/README.md b/provisioning_tool/README.md index 1d69731a..a6a15908 100644 --- a/provisioning_tool/README.md +++ b/provisioning_tool/README.md @@ -11,6 +11,7 @@ This tool can be built along with aosp build. It has dependency on libjc_provision. #### Usage +
 Usage: provision_tool *options*\
 Valid options are:\
 -h, --help                        show the help message and exit.\
@@ -23,3 +24,4 @@ Valid options are:\
 -b, --set_boot_params jsonFile    Provision boot parameters.\
 -s, --provision_stautus           Prints the current provision status.\
 -l, --lock_provision              Locks the provision commands.
+
From 91cc7fbb271d9934a520415a7ec888804c4fd661 Mon Sep 17 00:00:00 2001 From: BKSSMVenkateswarlu <40534495+BKSSMVenkateswarlu@users.noreply.github.com> Date: Tue, 2 Feb 2021 19:56:15 +0530 Subject: [PATCH 19/21] Update README.md --- provisioning_tool/README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/provisioning_tool/README.md b/provisioning_tool/README.md index a6a15908..b2954495 100644 --- a/provisioning_tool/README.md +++ b/provisioning_tool/README.md @@ -12,16 +12,16 @@ libjc_provision. #### Usage
-Usage: provision_tool *options*\
-Valid options are:\
--h, --help                        show the help message and exit.\
--a, --all jsonFile                Executes all the provision commands.\
--k, --attest_key jsonFile         Provision attestation key.\
--c, --cert_chain jsonFile         Provision attestation certificate chain.\
--p, --cert_params jsonFile        Provision attestation certificate parameters.\
--i, --attest_ids jsonFile         Provision attestation IDs.\
--r, --shared_secret jsonFile      Provision pre-shared secret.\
--b, --set_boot_params jsonFile    Provision boot parameters.\
--s, --provision_stautus           Prints the current provision status.\
+Usage: provision_tool options
+Valid options are:
+-h, --help                        show the help message and exit.
+-a, --all jsonFile                Executes all the provision commands.
+-k, --attest_key jsonFile         Provision attestation key.
+-c, --cert_chain jsonFile         Provision attestation certificate chain.
+-p, --cert_params jsonFile        Provision attestation certificate parameters.
+-i, --attest_ids jsonFile         Provision attestation IDs.
+-r, --shared_secret jsonFile      Provision pre-shared secret.
+-b, --set_boot_params jsonFile    Provision boot parameters.
+-s, --provision_stautus           Prints the current provision status.
 -l, --lock_provision              Locks the provision commands.
 
From 8d32e8061f1c4fec35f7c29dab9b8610dc151b5c Mon Sep 17 00:00:00 2001 From: BKSSMVenkateswarlu <40534495+BKSSMVenkateswarlu@users.noreply.github.com> Date: Tue, 2 Feb 2021 19:57:23 +0530 Subject: [PATCH 20/21] Update README.md --- provisioning_tool/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/provisioning_tool/README.md b/provisioning_tool/README.md index b2954495..9f0dfbb4 100644 --- a/provisioning_tool/README.md +++ b/provisioning_tool/README.md @@ -2,7 +2,7 @@ This directory contains provisioning tool which helps in provisioning the secure element by using the APIs exposed by Provision library. This tool takes the input parameters from json file. A sample -json file is located in this directory with name sample_json.txt for +json file is located in this directory with name [sample_json.txt](https://github.com/BKSSMVenkateswarlu/JavaCardKeymaster/blob/master/provisioning_tool/sample_json.txt) for your reference. #### Build From 66d366aabba4f07583be5ce393546acf195cc40c Mon Sep 17 00:00:00 2001 From: BKSSM Venkateswarlu Date: Wed, 3 Feb 2021 10:34:29 +0530 Subject: [PATCH 21/21] Corrected the tag EARLY_BOOT_ENDED to EARLY_BOOT_ONLY --- Applet/src/com/android/javacard/keymaster/KMBoolTag.java | 2 +- .../src/com/android/javacard/keymaster/KMKeymasterApplet.java | 2 +- Applet/src/com/android/javacard/keymaster/KMType.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Applet/src/com/android/javacard/keymaster/KMBoolTag.java b/Applet/src/com/android/javacard/keymaster/KMBoolTag.java index d3b916e9..4396470b 100644 --- a/Applet/src/com/android/javacard/keymaster/KMBoolTag.java +++ b/Applet/src/com/android/javacard/keymaster/KMBoolTag.java @@ -42,7 +42,7 @@ public class KMBoolTag extends KMTag { TRUSTED_CONFIRMATION_REQUIRED, UNLOCKED_DEVICE_REQUIRED, RESET_SINCE_ID_ROTATION, - EARLY_BOOT_ENDED, + EARLY_BOOT_ONLY, DEVICE_UNIQUE_ATTESTATION }; diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index adedf6f5..1b156d53 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -3315,7 +3315,7 @@ private static void processGenerateKey(APDU apdu) { data[KEY_PARAMETERS] = KMArray.cast(tmpVariables[2]).get((short) 0); // Check if EarlyBootEnded tag is present. tmpVariables[0] = - KMKeyParameters.findTag(KMType.BOOL_TAG, KMType.EARLY_BOOT_ENDED, data[KEY_PARAMETERS]); + KMKeyParameters.findTag(KMType.BOOL_TAG, KMType.EARLY_BOOT_ONLY, data[KEY_PARAMETERS]); if (tmpVariables[0] != KMType.INVALID_VALUE) { KMException.throwIt(KMError.EARLY_BOOT_ENDED); } diff --git a/Applet/src/com/android/javacard/keymaster/KMType.java b/Applet/src/com/android/javacard/keymaster/KMType.java index bf6b12e5..4d81de45 100644 --- a/Applet/src/com/android/javacard/keymaster/KMType.java +++ b/Applet/src/com/android/javacard/keymaster/KMType.java @@ -231,7 +231,7 @@ public abstract class KMType { // Reset Since Id Rotation public static final short RESET_SINCE_ID_ROTATION = (short) 0x03EC; //Early boot ended. - public static final short EARLY_BOOT_ENDED = (short) 0x0131; + public static final short EARLY_BOOT_ONLY = (short) 0x0131; //Device unique attestation. public static final short DEVICE_UNIQUE_ATTESTATION = (short) 0x02D0;