/* * 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. */ /****************************************************************************** * * The original Work has been changed by NXP. * * 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. * * Copyright 2024 NXP * ******************************************************************************/ #define LOG_TAG "javacard.keymint.device.strongbox-impl" #include "JavacardSecureElement.h" #include #include #include #include #include #include #include #ifdef INIT_USING_SEHAL_TRANSPORT #include #endif #include #include #include #include #include "keymint_utils.h" namespace keymint::javacard { using ::aidl::android::hardware::security::keymint::ErrorCode; const std::vector gStrongBoxAppletAID = {0xA0, 0x00, 0x00, 0x00, 0x62}; namespace { keymaster_error_t aidlEnumErrorCode2km(ErrorCode err) { return static_cast(err); } } // namespace keymaster_error_t JavacardSecureElement::initializeJavacard() { Array request; request.add(Uint(getOsVersion())); request.add(Uint(getOsPatchlevel())); request.add(Uint(getVendorPatchlevel())); auto [item, err] = sendRequest(Instruction::INS_INIT_STRONGBOX_CMD, request); return err; } void JavacardSecureElement::setDeleteAllKeysPending() { isDeleteAllKeysPending = true; } void JavacardSecureElement::setEarlyBootEndedPending() { isEarlyBootEndedPending = true; } void JavacardSecureElement::sendPendingEvents() { if (isCardInitPending) { if (KM_ERROR_OK == initializeJavacard()) { isCardInitPending = false; } else { LOG(ERROR) << "Error in sending system properties(OS_VERSION, OS_PATCH, VENDOR_PATCH)."; } } if (isDeleteAllKeysPending) { auto [_, err] = sendRequest(Instruction::INS_DELETE_ALL_KEYS_CMD); if (err == KM_ERROR_OK) { isDeleteAllKeysPending = false; } else { LOG(ERROR) << "Error in sending deleteAllKeys."; } } if (isEarlyBootEndedPending) { auto [_, err] = sendRequest(Instruction::INS_EARLY_BOOT_ENDED_CMD); if (err == KM_ERROR_OK) { isEarlyBootEndedPending = false; } else { LOG(ERROR) << "Error in sending earlyBootEnded."; } } } keymaster_error_t JavacardSecureElement::constructApduMessage(Instruction& ins, const std::vector& inputData, std::vector& apduOut) { 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 (USHRT_MAX >= inputData.size()) { // Send extended length APDU always as response size is not known to HAL. // Case 1: Lc > 0 CLS | INS | P1 | P2 | 00 | 2 bytes of Lc | CommandData | // 2 bytes of Le all set to 00. Case 2: Lc = 0 CLS | INS | P1 | P2 | 3 // bytes of Le all set to 00. Extended length 3 bytes, starts with 0x00 apduOut.push_back(static_cast(0x00)); if (inputData.size() > 0) { 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. // Accepting complete length of output every time. apduOut.push_back(static_cast(0x00)); apduOut.push_back(static_cast(0x00)); } else { LOG(ERROR) << "Error in constructApduMessage."; return (KM_ERROR_INVALID_INPUT_LENGTH); } return (KM_ERROR_OK); // success } keymaster_error_t JavacardSecureElement::sendData(const std::shared_ptr& transport, Instruction ins, const std::vector& inData, std::vector& response) { keymaster_error_t ret = KM_ERROR_UNKNOWN_ERROR; std::vector apdu; ret = constructApduMessage(ins, inData, apdu); if (ret != KM_ERROR_OK) { return ret; } if (!transport->sendData(apdu, response) && (response.size() < 2)) { LOG(ERROR) << "Error in sending C-APDU"; return (KM_ERROR_SECURE_HW_COMMUNICATION_FAILED); } // Response size should be greater than 2. Cbor output data followed by two // bytes of APDU status. if (getApduStatus(response) != APDU_RESP_STATUS_OK) { LOG(ERROR) << "ERROR Response apdu status = " << std::uppercase << std::hex << getApduStatus(response); return (KM_ERROR_UNKNOWN_ERROR); } // remove the status bytes response.pop_back(); response.pop_back(); return (KM_ERROR_OK); // success } keymaster_error_t JavacardSecureElement::sendData(Instruction ins, const std::vector& inData, std::vector& response) { return sendData(transport_, ins, inData, response); } std::tuple, keymaster_error_t> JavacardSecureElement::sendRequest( Instruction ins, const Array& request) { return sendRequest(transport_, ins, request.encode()); } std::tuple, keymaster_error_t> JavacardSecureElement::sendRequest( Instruction ins, const std::vector& command) { return sendRequest(transport_, ins, command); } std::tuple, keymaster_error_t> JavacardSecureElement::sendRequest( Instruction ins) { return sendRequest(transport_, ins, std::vector()); } #ifdef INIT_USING_SEHAL_TRANSPORT bool JavacardSecureElement::initSEHal() { if (seHalTransport == nullptr) { seHalTransport = std::make_shared(gStrongBoxAppletAID); } return seHalTransport->openConnection(); } bool JavacardSecureElement::closeSEHal() { bool ret = true; if (seHalTransport != nullptr) { ret = seHalTransport->closeConnection(); if (!ret) { LOG(INFO) << "Failed to close SE Hal."; } seHalTransport = nullptr; } return ret; } #endif std::tuple, keymaster_error_t> JavacardSecureElement::sendRequestSeHal( Instruction ins, const std::vector& command) { if (seHalTransport != nullptr) { return sendRequest(seHalTransport, ins, command); } else { auto [item, err] = sendRequest(ins, command); if (err != KM_ERROR_OK) { #ifdef INIT_USING_SEHAL_TRANSPORT if (err == aidlEnumErrorCode2km(ErrorCode::SECURE_HW_COMMUNICATION_FAILED)) { LOG(DEBUG) << "OMAPI is not yet available. Send INS: " << static_cast(ins) << " via SE Hal."; if (initSEHal()) { return sendRequest(seHalTransport, ins, command); } LOG(ERROR) << "Failed to initialize SE HAL"; } #endif } return {std::move(item), std::move(err)}; } } std::tuple, keymaster_error_t> JavacardSecureElement::sendRequestSeHal( Instruction ins) { return sendRequestSeHal(ins, std::vector()); } std::tuple, keymaster_error_t> JavacardSecureElement::sendRequest( const std::shared_ptr& transport, Instruction ins, const std::vector& command) { vector response; auto sendError = sendData(transport, ins, command, response); if (sendError != KM_ERROR_OK) { return {unique_ptr(nullptr), sendError}; } // decode the response and send that back return cbor_.decodeData(response); } #ifdef NXP_EXTNS void JavacardSecureElement::setOperationState(CryptoOperationState state) { transport_->setCryptoOperationState(state); } #endif } // namespace keymint::javacard