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 NXP
33 **
34 *********************************************************************************/
35
36 #define LOG_TAG "javacard.keymint.device.rkp.strongbox-impl"
37 #include <JavacardRemotelyProvisionedComponentDevice.h>
38 #include <android-base/logging.h>
39 #include <JavacardKeyMintUtils.h>
40 #include <aidl/android/hardware/security/keymint/MacedPublicKey.h>
41 #include <keymaster/cppcose/cppcose.h>
42 #include <keymaster/remote_provisioning_utils.h>
43
44 #ifdef NXP_EXTNS
45 #define KM_RKP_VERSION_1 0x01
46 #endif
47
48 namespace aidl::android::hardware::security::keymint {
49 using namespace cppcose;
50 using namespace keymaster;
51 using namespace cppbor;
52 // RKP error codes defined in keymint applet.
53 constexpr keymaster_error_t kStatusFailed = static_cast<keymaster_error_t>(32000);
54 constexpr keymaster_error_t kStatusInvalidMac = static_cast<keymaster_error_t>(32001);
55 constexpr keymaster_error_t kStatusProductionKeyInTestRequest = static_cast<keymaster_error_t>(32002);
56 constexpr keymaster_error_t kStatusTestKeyInProductionRequest = static_cast<keymaster_error_t>(32003);
57 constexpr keymaster_error_t kStatusInvalidEek = static_cast<keymaster_error_t>(32004);
58 constexpr keymaster_error_t kStatusInvalidState = static_cast<keymaster_error_t>(32005);
59
60 namespace {
61
translateRkpErrorCode(keymaster_error_t error)62 keymaster_error_t translateRkpErrorCode(keymaster_error_t error) {
63 switch(static_cast<int32_t>(-error)) {
64 case kStatusFailed:
65 case kStatusInvalidState:
66 return static_cast<keymaster_error_t>(BnRemotelyProvisionedComponent::STATUS_FAILED);
67 case kStatusInvalidMac:
68 return static_cast<keymaster_error_t>(BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
69 case kStatusProductionKeyInTestRequest:
70 return static_cast<keymaster_error_t>(BnRemotelyProvisionedComponent::STATUS_PRODUCTION_KEY_IN_TEST_REQUEST);
71 case kStatusTestKeyInProductionRequest:
72 return static_cast<keymaster_error_t>(BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST);
73 case kStatusInvalidEek:
74 return static_cast<keymaster_error_t>(BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
75 }
76 return error;
77 }
78
defaultHwInfo(RpcHardwareInfo * info)79 ScopedAStatus defaultHwInfo(RpcHardwareInfo* info) {
80 info->versionNumber = 1;
81 info->rpcAuthorName = "Google";
82 info->supportedEekCurve = RpcHardwareInfo::CURVE_P256;
83 return ScopedAStatus::ok();
84 }
85
coseKeyEncodedSize(const std::vector<MacedPublicKey> & keysToSign)86 uint32_t coseKeyEncodedSize(const std::vector<MacedPublicKey>& keysToSign) {
87 uint32_t size = 0;
88 for(auto& macKey : keysToSign) {
89 auto [macedKeyItem, _, coseMacErrMsg] =
90 cppbor::parse(macKey.macedKey);
91 if (!macedKeyItem || !macedKeyItem->asArray() ||
92 macedKeyItem->asArray()->size() != kCoseMac0EntryCount) {
93 LOG(ERROR) << "Invalid COSE_Mac0 structure";
94 return 0;
95 }
96 auto payload = macedKeyItem->asArray()->get(kCoseMac0Payload)->asBstr();
97 if (!payload) return 0;
98 size += payload->value().size();
99 }
100 return size;
101 }
102
103 } // namespace
104
105 ScopedAStatus
getHardwareInfo(RpcHardwareInfo * info)106 JavacardRemotelyProvisionedComponentDevice::getHardwareInfo(RpcHardwareInfo* info) {
107 auto [item, err] = card_->sendRequest(Instruction::INS_GET_RKP_HARDWARE_INFO);
108 uint32_t versionNumber;
109 uint32_t supportedEekCurve;
110 if (err != KM_ERROR_OK ||
111 !cbor_.getUint64<uint32_t>(item, 1, versionNumber) ||
112 !cbor_.getBinaryArray(item, 2, info->rpcAuthorName ) ||
113 !cbor_.getUint64<uint32_t>(item, 3, supportedEekCurve)) {
114 LOG(ERROR) << "Error in response of getHardwareInfo.";
115 LOG(INFO) << "Returning defaultHwInfo in getHardwareInfo.";
116 return defaultHwInfo(info);
117 }
118 info->versionNumber = static_cast<int32_t>(versionNumber);
119 #ifdef NXP_EXTNS
120 if (info->versionNumber > KM_RKP_VERSION_1) {
121 std::string uniqueId;
122 if (!cbor_.getBinaryArray(item, 4, uniqueId)) {
123 LOG(ERROR) << "Error in uniqueId response of getHardwareInfo.";
124 LOG(INFO) << "Returning defaultHwInfo in getHardwareInfo.";
125 return defaultHwInfo(info);
126 }
127 info->uniqueId = static_cast<::std::optional<::std::string>>(uniqueId);
128 }
129 #endif
130 info->supportedEekCurve = static_cast<int32_t>(supportedEekCurve);
131 return ScopedAStatus::ok();
132 }
133
134 ScopedAStatus
generateEcdsaP256KeyPair(bool testMode,MacedPublicKey * macedPublicKey,std::vector<uint8_t> * privateKeyHandle)135 JavacardRemotelyProvisionedComponentDevice::generateEcdsaP256KeyPair(bool testMode,
136 MacedPublicKey* macedPublicKey,
137 std::vector<uint8_t>* privateKeyHandle) {
138 cppbor::Array array;
139 array.add(testMode);
140 auto [item, err] = card_->sendRequest(Instruction::INS_GENERATE_RKP_KEY_CMD, array);
141 if (err != KM_ERROR_OK) {
142 LOG(ERROR) << "Error in sending generateEcdsaP256KeyPair.";
143 return km_utils::kmError2ScopedAStatus(translateRkpErrorCode(err));
144 }
145 if (!cbor_.getBinaryArray(item, 1, macedPublicKey->macedKey) ||
146 !cbor_.getBinaryArray(item, 2, *privateKeyHandle)) {
147 LOG(ERROR) << "Error in decoding og response in generateEcdsaP256KeyPair.";
148 return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR);
149 }
150 return ScopedAStatus::ok();
151 }
152
153 ScopedAStatus
beginSendData(bool testMode,const std::vector<MacedPublicKey> & keysToSign)154 JavacardRemotelyProvisionedComponentDevice::beginSendData(
155 bool testMode, const std::vector<MacedPublicKey>& keysToSign) {
156 uint32_t totalEncodedSize = coseKeyEncodedSize(keysToSign);
157 cppbor::Array array;
158 array.add(keysToSign.size());
159 array.add(totalEncodedSize);
160 array.add(testMode);
161 auto [_, err] = card_->sendRequest(Instruction::INS_BEGIN_SEND_DATA_CMD, array);
162 if (err != KM_ERROR_OK) {
163 LOG(ERROR) << "Error in beginSendData.";
164 return km_utils::kmError2ScopedAStatus(translateRkpErrorCode(err));
165 }
166 return ScopedAStatus::ok();
167 }
168
169 ScopedAStatus
updateMacedKey(const std::vector<MacedPublicKey> & keysToSign)170 JavacardRemotelyProvisionedComponentDevice::updateMacedKey(
171 const std::vector<MacedPublicKey>& keysToSign) {
172 for(auto& macedPublicKey : keysToSign) {
173 cppbor::Array array;
174 array.add(EncodedItem(macedPublicKey.macedKey));
175 auto [_, err] = card_->sendRequest(Instruction::INS_UPDATE_KEY_CMD, array);
176 if (err != KM_ERROR_OK) {
177 LOG(ERROR) << "Error in updateMacedKey.";
178 return km_utils::kmError2ScopedAStatus(translateRkpErrorCode(err));
179 }
180 }
181 return ScopedAStatus::ok();
182 }
183
184 ScopedAStatus
updateChallenge(const std::vector<uint8_t> & challenge)185 JavacardRemotelyProvisionedComponentDevice::updateChallenge(
186 const std::vector<uint8_t>& challenge) {
187 Array array;
188 array.add(challenge);
189 auto [_, err] = card_->sendRequest(Instruction::INS_UPDATE_CHALLENGE_CMD, array);
190 if (err != KM_ERROR_OK) {
191 LOG(ERROR) << "Error in updateChallenge.";
192 return km_utils::kmError2ScopedAStatus(translateRkpErrorCode(err));
193 }
194 return ScopedAStatus::ok();
195 }
196
197 ScopedAStatus
updateEEK(const std::vector<uint8_t> & endpointEncCertChain)198 JavacardRemotelyProvisionedComponentDevice::updateEEK(
199 const std::vector<uint8_t>& endpointEncCertChain) {
200 std::vector<uint8_t> eekChain = endpointEncCertChain;
201 auto [_, err] = card_->sendRequest(Instruction::INS_UPDATE_EEK_CHAIN_CMD, eekChain);
202 if (err != KM_ERROR_OK) {
203 LOG(ERROR) << "Error in updateEEK.";
204 return km_utils::kmError2ScopedAStatus(translateRkpErrorCode(err));
205 }
206 return ScopedAStatus::ok();
207 }
208
209 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)210 JavacardRemotelyProvisionedComponentDevice::finishSendData(
211 std::vector<uint8_t>* keysToSignMac, DeviceInfo* deviceInfo,
212 std::vector<uint8_t>& coseEncryptProtectedHeader, cppbor::Map& coseEncryptUnProtectedHeader,
213 std::vector<uint8_t>& partialCipheredData, uint32_t& respFlag) {
214
215 std::vector<uint8_t> decodedKeysToSignMac;
216 std::vector<uint8_t> decodedDeviceInfo;
217 auto [item, err] = card_->sendRequest(Instruction::INS_FINISH_SEND_DATA_CMD);
218 if (err != KM_ERROR_OK) {
219 LOG(ERROR) << "Error in finishSendData.";
220 return km_utils::kmError2ScopedAStatus(translateRkpErrorCode(err));
221 }
222 if (!cbor_.getBinaryArray(item, 1, decodedKeysToSignMac) ||
223 !cbor_.getBinaryArray(item, 2, decodedDeviceInfo) ||
224 !cbor_.getBinaryArray(item, 3, coseEncryptProtectedHeader) ||
225 !cbor_.getMapItem(item, 4, coseEncryptUnProtectedHeader) ||
226 !cbor_.getBinaryArray(item, 5, partialCipheredData) ||
227 !cbor_.getUint64(item, 6, respFlag)) {
228 LOG(ERROR) << "Error in decoding og response in finishSendData.";
229 return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR);
230 }
231 *keysToSignMac = decodedKeysToSignMac;
232 deviceInfo->deviceInfo = decodedDeviceInfo;
233 return ScopedAStatus::ok();
234 }
235
236 ScopedAStatus
getResponse(std::vector<uint8_t> & partialCipheredData,cppbor::Array & recipientStructure,uint32_t & respFlag)237 JavacardRemotelyProvisionedComponentDevice::getResponse(
238 std::vector<uint8_t>& partialCipheredData, cppbor::Array& recipientStructure,
239 uint32_t& respFlag) {
240 auto [item, err] = card_->sendRequest(Instruction::INS_GET_RESPONSE_CMD);
241 if (err != KM_ERROR_OK) {
242 LOG(ERROR) << "Error in getResponse.";
243 return km_utils::kmError2ScopedAStatus(translateRkpErrorCode(err));
244 }
245 if (!cbor_.getBinaryArray(item, 1, partialCipheredData) ||
246 !cbor_.getArrayItem(item, 2, recipientStructure) ||
247 !cbor_.getUint64(item, 3, respFlag)) {
248 LOG(ERROR) << "Error in decoding og response in getResponse.";
249 return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR);
250 }
251 return ScopedAStatus::ok();
252 }
253
254 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)255 JavacardRemotelyProvisionedComponentDevice::generateCertificateRequest(bool testMode,
256 const std::vector<MacedPublicKey>& keysToSign,
257 const std::vector<uint8_t>& endpointEncCertChain,
258 const std::vector<uint8_t>& challenge,
259 DeviceInfo* deviceInfo, ProtectedData* protectedData,
260 std::vector<uint8_t>* keysToSignMac) {
261 std::vector<uint8_t> coseEncryptProtectedHeader;
262 cppbor::Map coseEncryptUnProtectedHeader;
263 cppbor::Array recipients;
264 std::vector<uint8_t> cipheredData;
265 uint32_t respFlag;
266 auto ret = beginSendData(testMode, keysToSign);
267 if (!ret.isOk()) return ret;
268
269 ret = updateMacedKey(keysToSign);
270 if (!ret.isOk()) return ret;
271
272 ret = updateChallenge(challenge);
273 if (!ret.isOk()) return ret;
274
275 ret = updateEEK(endpointEncCertChain);
276 if (!ret.isOk()) return ret;
277
278 ret = finishSendData(keysToSignMac, deviceInfo, coseEncryptProtectedHeader,
279 coseEncryptUnProtectedHeader, cipheredData,
280 respFlag);
281 if (!ret.isOk()) return ret;
282
283 while (respFlag != 0) { // more data is pending to receive
284 ret = getResponse(cipheredData, recipients, respFlag);
285 if (!ret.isOk()) return ret;
286 }
287 // Create ConseEncrypt structure.
288 protectedData->protectedData =
289 cppbor::Array()
290 .add(coseEncryptProtectedHeader) // Protected
291 .add(std::move(coseEncryptUnProtectedHeader)) // Unprotected
292 .add(cipheredData) // Payload
293 .add(std::move(recipients))
294 .encode();
295 return ScopedAStatus::ok();
296 }
297
298 } // namespace aidl::android::hardware::security::keymint
299