158 lines
5.8 KiB
C++
158 lines
5.8 KiB
C++
/*
|
|
* 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.
|
|
*/
|
|
|
|
#define LOG_TAG "javacard.keymint.device.strongbox-impl"
|
|
#include "JavacardSecureElement.h"
|
|
|
|
#include <algorithm>
|
|
#include <iostream>
|
|
#include <iterator>
|
|
#include <memory>
|
|
#include <regex.h>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <android-base/logging.h>
|
|
#include <android-base/properties.h>
|
|
#include <keymaster/android_keymaster_messages.h>
|
|
|
|
#include "keymint_utils.h"
|
|
|
|
namespace keymint::javacard {
|
|
|
|
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;
|
|
}
|
|
|
|
keymaster_error_t JavacardSecureElement::sendEarlyBootEndedEvent(bool eventTriggered) {
|
|
isEarlyBootEventPending |= eventTriggered;
|
|
if (!isEarlyBootEventPending) {
|
|
return KM_ERROR_OK;
|
|
}
|
|
auto [item, err] = sendRequest(Instruction::INS_EARLY_BOOT_ENDED_CMD);
|
|
if (err != KM_ERROR_OK) {
|
|
// Incase of failure cache the event and send in the next immediate request to Applet.
|
|
isEarlyBootEventPending = true;
|
|
return err;
|
|
}
|
|
isEarlyBootEventPending = false;
|
|
return KM_ERROR_OK;
|
|
}
|
|
|
|
keymaster_error_t JavacardSecureElement::constructApduMessage(Instruction& ins,
|
|
std::vector<uint8_t>& inputData,
|
|
std::vector<uint8_t>& apduOut) {
|
|
apduOut.push_back(static_cast<uint8_t>(APDU_CLS)); // CLS
|
|
apduOut.push_back(static_cast<uint8_t>(ins)); // INS
|
|
apduOut.push_back(static_cast<uint8_t>(APDU_P1)); // P1
|
|
apduOut.push_back(static_cast<uint8_t>(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<uint8_t>(0x00));
|
|
if (inputData.size() > 0) {
|
|
apduOut.push_back(static_cast<uint8_t>(inputData.size() >> 8));
|
|
apduOut.push_back(static_cast<uint8_t>(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<uint8_t>(0x00));
|
|
apduOut.push_back(static_cast<uint8_t>(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<uint8_t>& inData,
|
|
std::vector<uint8_t>& response) {
|
|
keymaster_error_t ret = KM_ERROR_UNKNOWN_ERROR;
|
|
std::vector<uint8_t> apdu;
|
|
|
|
ret = constructApduMessage(ins, inData, apdu);
|
|
|
|
if (ret != KM_ERROR_OK) {
|
|
return ret;
|
|
}
|
|
|
|
ret = transport_->sendData(apdu, response);
|
|
if (ret != KM_ERROR_OK) {
|
|
LOG(ERROR) << "Error in sending data in sendData. " << static_cast<int>(ret);
|
|
return ret;
|
|
}
|
|
|
|
// Response size should be greater than 2. Cbor output data followed by two bytes of APDU
|
|
// status.
|
|
if ((response.size() <= 2) || (getApduStatus(response) != APDU_RESP_STATUS_OK)) {
|
|
LOG(ERROR) << "Response of the sendData is wrong: response size = " << response.size()
|
|
<< " apdu status = " << getApduStatus(response);
|
|
return (KM_ERROR_UNKNOWN_ERROR);
|
|
}
|
|
// remove the status bytes
|
|
response.pop_back();
|
|
response.pop_back();
|
|
return (KM_ERROR_OK); // success
|
|
}
|
|
|
|
std::tuple<std::unique_ptr<Item>, keymaster_error_t>
|
|
JavacardSecureElement::sendRequest(Instruction ins, Array& request) {
|
|
vector<uint8_t> response;
|
|
// encode request
|
|
std::vector<uint8_t> command = request.encode();
|
|
auto sendError = sendData(ins, command, response);
|
|
if (sendError != KM_ERROR_OK) {
|
|
return {unique_ptr<Item>(nullptr), sendError};
|
|
}
|
|
// decode the response and send that back
|
|
return cbor_.decodeData(response);
|
|
}
|
|
|
|
std::tuple<std::unique_ptr<Item>, keymaster_error_t>
|
|
JavacardSecureElement::sendRequest(Instruction ins, std::vector<uint8_t>& command) {
|
|
vector<uint8_t> response;
|
|
auto sendError = sendData(ins, command, response);
|
|
if (sendError != KM_ERROR_OK) {
|
|
return {unique_ptr<Item>(nullptr), sendError};
|
|
}
|
|
// decode the response and send that back
|
|
return cbor_.decodeData(response);
|
|
}
|
|
|
|
std::tuple<std::unique_ptr<Item>, keymaster_error_t>
|
|
JavacardSecureElement::sendRequest(Instruction ins) {
|
|
vector<uint8_t> response;
|
|
vector<uint8_t> emptyRequest;
|
|
auto sendError = sendData(ins, emptyRequest, response);
|
|
if (sendError != KM_ERROR_OK) {
|
|
return {unique_ptr<Item>(nullptr), sendError};
|
|
}
|
|
// decode the response and send that back
|
|
return cbor_.decodeData(response);
|
|
}
|
|
|
|
} // namespace keymint::javacard
|