1 /*
2 * Copyright 2021, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 /******************************************************************************
17 **
18 ** The original Work has been changed by NXP.
19 **
20 ** Licensed under the Apache License, Version 2.0 (the "License");
21 ** you may not use this file except in compliance with the License.
22 ** You may obtain a copy of the License at
23 **
24 ** http://www.apache.org/licenses/LICENSE-2.0
25 **
26 ** Unless required by applicable law or agreed to in writing, software
27 ** distributed under the License is distributed on an "AS IS" BASIS,
28 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29 ** See the License for the specific language governing permissions and
30 ** limitations under the License.
31 **
32 ** Copyright 2022-2024 NXP
33 **
34 *********************************************************************************/
35
36 #define LOG_TAG "javacard.keymint.device.rkp.strongbox-impl"
37 #include <JavacardKeyMintUtils.h>
38 #include <JavacardRemotelyProvisionedComponentDevice.h>
39 #include <aidl/android/hardware/security/keymint/MacedPublicKey.h>
40 #include <android-base/logging.h>
41 #include <keymaster/cppcose/cppcose.h>
42 #include <keymaster/remote_provisioning_utils.h>
43 #include <memunreachable/memunreachable.h>
44
45 #ifdef NXP_EXTNS
46 #define KM_RKP_VERSION_1 0x01
47 #endif
48
49 namespace aidl::android::hardware::security::keymint {
50 using cppbor::Array;
51 using cppbor::EncodedItem;
52 using cppcose::kCoseMac0EntryCount;
53 using cppcose::kCoseMac0Payload;
54 using ::keymint::javacard::Instruction;
55 // RKP error codes defined in keymint applet.
56 constexpr int32_t kStatusFailed = 32000;
57 constexpr int32_t kStatusInvalidMac = 32001;
58 constexpr int32_t kStatusProductionKeyInTestRequest = 32002;
59 constexpr int32_t kStatusTestKeyInProductionRequest = 32003;
60 constexpr int32_t kStatusInvalidEek = 32004;
61 constexpr int32_t kStatusInvalidState = 32005;
62
63 namespace {
64
translateRkpErrorCode(keymaster_error_t error)65 keymaster_error_t translateRkpErrorCode(keymaster_error_t error) {
66 switch(static_cast<int32_t>(-error)) {
67 case kStatusFailed:
68 case kStatusInvalidState:
69 return static_cast<keymaster_error_t>(BnRemotelyProvisionedComponent::STATUS_FAILED);
70 case kStatusInvalidMac:
71 return static_cast<keymaster_error_t>(BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
72 case kStatusProductionKeyInTestRequest:
73 return static_cast<keymaster_error_t>(BnRemotelyProvisionedComponent::STATUS_PRODUCTION_KEY_IN_TEST_REQUEST);
74 case kStatusTestKeyInProductionRequest:
75 return static_cast<keymaster_error_t>(BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST);
76 case kStatusInvalidEek:
77 return static_cast<keymaster_error_t>(BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
78 }
79 return error;
80 }
81
defaultHwInfo(RpcHardwareInfo * info)82 ScopedAStatus defaultHwInfo(RpcHardwareInfo* info) {
83 info->versionNumber = 1;
84 info->rpcAuthorName = "Google";
85 info->supportedEekCurve = RpcHardwareInfo::CURVE_P256;
86 return ScopedAStatus::ok();
87 }
88
coseKeyEncodedSize(const std::vector<MacedPublicKey> & keysToSign)89 uint32_t coseKeyEncodedSize(const std::vector<MacedPublicKey>& keysToSign) {
90 uint32_t size = 0;
91 for(auto& macKey : keysToSign) {
92 auto [macedKeyItem, _, coseMacErrMsg] =
93 cppbor::parse(macKey.macedKey);
94 if (!macedKeyItem || !macedKeyItem->asArray() ||
95 macedKeyItem->asArray()->size() != kCoseMac0EntryCount) {
96 LOG(ERROR) << "Invalid COSE_Mac0 structure";
97 return 0;
98 }
99 auto payload = macedKeyItem->asArray()->get(kCoseMac0Payload)->asBstr();
100 if (!payload) return 0;
101 size += payload->value().size();
102 }
103 return size;
104 }
105
106 } // namespace
107
108 ScopedAStatus
getHardwareInfo(RpcHardwareInfo * info)109 JavacardRemotelyProvisionedComponentDevice::getHardwareInfo(RpcHardwareInfo* info) {
110 auto [item, err] = card_->sendRequest(Instruction::INS_GET_RKP_HARDWARE_INFO);
111 uint32_t versionNumber;
112 uint32_t supportedEekCurve;
113 if (err != KM_ERROR_OK ||
114 !cbor_.getUint64<uint32_t>(item, 1, versionNumber) ||
115 !cbor_.getBinaryArray(item, 2, info->rpcAuthorName ) ||
116 !cbor_.getUint64<uint32_t>(item, 3, supportedEekCurve)) {
117 LOG(ERROR) << "Error in response of getHardwareInfo.";
118 LOG(INFO) << "Returning defaultHwInfo in getHardwareInfo.";
119 return defaultHwInfo(info);
120 }
121 info->versionNumber = static_cast<int32_t>(versionNumber);
122 #ifdef NXP_EXTNS
123 if (info->versionNumber > KM_RKP_VERSION_1) {
124 std::string uniqueId;
125 if (!cbor_.getBinaryArray(item, 4, uniqueId)) {
126 LOG(ERROR) << "Error in uniqueId response of getHardwareInfo.";
127 LOG(INFO) << "Returning defaultHwInfo in getHardwareInfo.";
128 return defaultHwInfo(info);
129 }
130 info->uniqueId = static_cast<::std::optional<::std::string>>(uniqueId);
131 }
132 #endif
133 info->supportedEekCurve = static_cast<int32_t>(supportedEekCurve);
134 return ScopedAStatus::ok();
135 }
136
137 ScopedAStatus
generateEcdsaP256KeyPair(bool testMode,MacedPublicKey * macedPublicKey,std::vector<uint8_t> * privateKeyHandle)138 JavacardRemotelyProvisionedComponentDevice::generateEcdsaP256KeyPair(bool testMode,
139 MacedPublicKey* macedPublicKey,
140 std::vector<uint8_t>* privateKeyHandle) {
141 cppbor::Array array;
142 array.add(testMode);
143 auto [item, err] = card_->sendRequest(Instruction::INS_GENERATE_RKP_KEY_CMD, array);
144 if (err != KM_ERROR_OK) {
145 LOG(ERROR) << "Error in sending generateEcdsaP256KeyPair.";
146 return km_utils::kmError2ScopedAStatus(translateRkpErrorCode(err));
147 }
148 if (!cbor_.getBinaryArray(item, 1, macedPublicKey->macedKey) ||
149 !cbor_.getBinaryArray(item, 2, *privateKeyHandle)) {
150 LOG(ERROR) << "Error in decoding og response in generateEcdsaP256KeyPair.";
151 return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR);
152 }
153 return ScopedAStatus::ok();
154 }
155
156 ScopedAStatus
beginSendData(bool testMode,const std::vector<MacedPublicKey> & keysToSign)157 JavacardRemotelyProvisionedComponentDevice::beginSendData(
158 bool testMode, const std::vector<MacedPublicKey>& keysToSign) {
159 uint32_t totalEncodedSize = coseKeyEncodedSize(keysToSign);
160 cppbor::Array array;
161 array.add(keysToSign.size());
162 array.add(totalEncodedSize);
163 array.add(testMode);
164 auto [_, err] = card_->sendRequest(Instruction::INS_BEGIN_SEND_DATA_CMD, array);
165 if (err != KM_ERROR_OK) {
166 LOG(ERROR) << "Error in beginSendData.";
167 return km_utils::kmError2ScopedAStatus(translateRkpErrorCode(err));
168 }
169 return ScopedAStatus::ok();
170 }
171
172 ScopedAStatus
updateMacedKey(const std::vector<MacedPublicKey> & keysToSign)173 JavacardRemotelyProvisionedComponentDevice::updateMacedKey(
174 const std::vector<MacedPublicKey>& keysToSign) {
175 for(auto& macedPublicKey : keysToSign) {
176 cppbor::Array array;
177 array.add(EncodedItem(macedPublicKey.macedKey));
178 auto [_, err] = card_->sendRequest(Instruction::INS_UPDATE_KEY_CMD, array);
179 if (err != KM_ERROR_OK) {
180 LOG(ERROR) << "Error in updateMacedKey.";
181 return km_utils::kmError2ScopedAStatus(translateRkpErrorCode(err));
182 }
183 }
184 return ScopedAStatus::ok();
185 }
186
187 ScopedAStatus
updateChallenge(const std::vector<uint8_t> & challenge)188 JavacardRemotelyProvisionedComponentDevice::updateChallenge(
189 const std::vector<uint8_t>& challenge) {
190 Array array;
191 array.add(challenge);
192 auto [_, err] = card_->sendRequest(Instruction::INS_UPDATE_CHALLENGE_CMD, array);
193 if (err != KM_ERROR_OK) {
194 LOG(ERROR) << "Error in updateChallenge.";
195 return km_utils::kmError2ScopedAStatus(translateRkpErrorCode(err));
196 }
197 return ScopedAStatus::ok();
198 }
199
200 ScopedAStatus
updateEEK(const std::vector<uint8_t> & endpointEncCertChain)201 JavacardRemotelyProvisionedComponentDevice::updateEEK(
202 const std::vector<uint8_t>& endpointEncCertChain) {
203 std::vector<uint8_t> eekChain = endpointEncCertChain;
204 auto [_, err] = card_->sendRequest(Instruction::INS_UPDATE_EEK_CHAIN_CMD, eekChain);
205 if (err != KM_ERROR_OK) {
206 LOG(ERROR) << "Error in updateEEK.";
207 return km_utils::kmError2ScopedAStatus(translateRkpErrorCode(err));
208 }
209 return ScopedAStatus::ok();
210 }
211
212 ScopedAStatus
finishSendData(std::vector<uint8_t> * keysToSignMac,DeviceInfo * deviceInfo,std::vector<uint8_t> & coseEncryptProtectedHeader,cppbor::Map & coseEncryptUnProtectedHeader,std::vector<uint8_t> & partialCipheredData,uint32_t & respFlag)213 JavacardRemotelyProvisionedComponentDevice::finishSendData(
214 std::vector<uint8_t>* keysToSignMac, DeviceInfo* deviceInfo,
215 std::vector<uint8_t>& coseEncryptProtectedHeader, cppbor::Map& coseEncryptUnProtectedHeader,
216 std::vector<uint8_t>& partialCipheredData, uint32_t& respFlag) {
217
218 std::vector<uint8_t> decodedKeysToSignMac;
219 std::vector<uint8_t> decodedDeviceInfo;
220 auto [item, err] = card_->sendRequest(Instruction::INS_FINISH_SEND_DATA_CMD);
221 if (err != KM_ERROR_OK) {
222 LOG(ERROR) << "Error in finishSendData.";
223 return km_utils::kmError2ScopedAStatus(translateRkpErrorCode(err));
224 }
225 if (!cbor_.getBinaryArray(item, 1, decodedKeysToSignMac) ||
226 !cbor_.getBinaryArray(item, 2, decodedDeviceInfo) ||
227 !cbor_.getBinaryArray(item, 3, coseEncryptProtectedHeader) ||
228 !cbor_.getMapItem(item, 4, coseEncryptUnProtectedHeader) ||
229 !cbor_.getBinaryArray(item, 5, partialCipheredData) ||
230 !cbor_.getUint64(item, 6, respFlag)) {
231 LOG(ERROR) << "Error in decoding og response in finishSendData.";
232 return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR);
233 }
234 *keysToSignMac = decodedKeysToSignMac;
235 deviceInfo->deviceInfo = decodedDeviceInfo;
236 return ScopedAStatus::ok();
237 }
238
239 ScopedAStatus
getResponse(std::vector<uint8_t> & partialCipheredData,cppbor::Array & recipientStructure,uint32_t & respFlag)240 JavacardRemotelyProvisionedComponentDevice::getResponse(
241 std::vector<uint8_t>& partialCipheredData, cppbor::Array& recipientStructure,
242 uint32_t& respFlag) {
243 auto [item, err] = card_->sendRequest(Instruction::INS_GET_RESPONSE_CMD);
244 if (err != KM_ERROR_OK) {
245 LOG(ERROR) << "Error in getResponse.";
246 return km_utils::kmError2ScopedAStatus(translateRkpErrorCode(err));
247 }
248 if (!cbor_.getBinaryArray(item, 1, partialCipheredData) ||
249 !cbor_.getArrayItem(item, 2, recipientStructure) ||
250 !cbor_.getUint64(item, 3, respFlag)) {
251 LOG(ERROR) << "Error in decoding og response in getResponse.";
252 return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR);
253 }
254 return ScopedAStatus::ok();
255 }
256
257 ScopedAStatus
generateCertificateRequest(bool testMode,const std::vector<MacedPublicKey> & keysToSign,const std::vector<uint8_t> & endpointEncCertChain,const std::vector<uint8_t> & challenge,DeviceInfo * deviceInfo,ProtectedData * protectedData,std::vector<uint8_t> * keysToSignMac)258 JavacardRemotelyProvisionedComponentDevice::generateCertificateRequest(bool testMode,
259 const std::vector<MacedPublicKey>& keysToSign,
260 const std::vector<uint8_t>& endpointEncCertChain,
261 const std::vector<uint8_t>& challenge,
262 DeviceInfo* deviceInfo, ProtectedData* protectedData,
263 std::vector<uint8_t>* keysToSignMac) {
264 std::vector<uint8_t> coseEncryptProtectedHeader;
265 cppbor::Map coseEncryptUnProtectedHeader;
266 cppbor::Array recipients;
267 std::vector<uint8_t> cipheredData;
268 uint32_t respFlag;
269 auto ret = beginSendData(testMode, keysToSign);
270 if (!ret.isOk()) return ret;
271
272 ret = updateMacedKey(keysToSign);
273 if (!ret.isOk()) return ret;
274
275 ret = updateChallenge(challenge);
276 if (!ret.isOk()) return ret;
277
278 ret = updateEEK(endpointEncCertChain);
279 if (!ret.isOk()) return ret;
280
281 ret = finishSendData(keysToSignMac, deviceInfo, coseEncryptProtectedHeader,
282 coseEncryptUnProtectedHeader, cipheredData,
283 respFlag);
284 if (!ret.isOk()) return ret;
285
286 while (respFlag != 0) { // more data is pending to receive
287 ret = getResponse(cipheredData, recipients, respFlag);
288 if (!ret.isOk()) return ret;
289 }
290 // Create ConseEncrypt structure.
291 protectedData->protectedData =
292 cppbor::Array()
293 .add(coseEncryptProtectedHeader) // Protected
294 .add(std::move(coseEncryptUnProtectedHeader)) // Unprotected
295 .add(cipheredData) // Payload
296 .add(std::move(recipients))
297 .encode();
298 return ScopedAStatus::ok();
299 }
300
dump(int,const char **,uint32_t)301 binder_status_t JavacardRemotelyProvisionedComponentDevice::dump(int /* fd */, const char** /* p */,
302 uint32_t /* q */) {
303 LOG(INFO) << "\n KeyMint-JavacardRemotelyProvisionedComponentDevice Info = \n"
304 << ::android::GetUnreachableMemoryString(true, 10000).c_str();
305 return STATUS_OK;
306 }
307
308 } // namespace aidl::android::hardware::security::keymint
309