/* * 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 2023-2024 NXP * ******************************************************************************/ #define LOG_TAG "javacard.keymint.device.strongbox-impl" #include "JavacardSecureElement.h" #include "keymint_utils.h" #include #include #include #include #include #include #include #include #include #include namespace keymint::javacard { keymaster_error_t JavacardSecureElement::initializeJavacard() { keymaster_error_t ret = KM_ERROR_OK; if (!isCardInitialized_) { Array request; request.add(Uint(getOsVersion())); request.add(Uint(getOsPatchlevel())); request.add(Uint(getVendorPatchlevel())); auto [item, err] = sendRequest(Instruction::INS_SET_BOOT_PARAMS_CMD, request); if (err == KM_ERROR_OK) { isCardInitialized_ = true; } ret = err; } return ret; } keymaster_error_t JavacardSecureElement::constructApduMessage(Instruction& ins, 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(Instruction ins, 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 } std::tuple, keymaster_error_t> JavacardSecureElement::sendRequest(Instruction ins, Array& request) { vector response; // encode request std::vector command = request.encode(); auto sendError = sendData(ins, command, response); if (sendError != KM_ERROR_OK) { return {unique_ptr(nullptr), sendError}; } // decode the response and send that back return cbor_.decodeData(response); } std::tuple, keymaster_error_t> JavacardSecureElement::sendRequest(Instruction ins, std::vector& command) { vector response; auto sendError = sendData(ins, command, response); if (sendError != KM_ERROR_OK) { return {unique_ptr(nullptr), sendError}; } // decode the response and send that back return cbor_.decodeData(response); } std::tuple, keymaster_error_t> JavacardSecureElement::sendRequest(Instruction ins) { vector response; vector emptyRequest; auto sendError = sendData(ins, emptyRequest, 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