1 /*
2 * Copyright (c) 2019, 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 #include <iterator>
18 #include <tuple>
19
20 #include <aidl/android/hardware/security/keymint/RpcHardwareInfo.h>
21 #include <android-base/properties.h>
22 #include <cppbor.h>
23 #include <json/json.h>
24 #include <keymaster/km_openssl/ec_key.h>
25 #include <keymaster/km_openssl/ecdsa_operation.h>
26 #include <keymaster/km_openssl/openssl_err.h>
27 #include <keymaster/km_openssl/openssl_utils.h>
28 #include <openssl/base64.h>
29 #include <openssl/evp.h>
30 #include <openssl/rand.h>
31 #include <remote_prov/remote_prov_utils.h>
32
33 namespace aidl::android::hardware::security::keymint::remote_prov {
34
35 constexpr uint32_t kBccPayloadIssuer = 1;
36 constexpr uint32_t kBccPayloadSubject = 2;
37 constexpr int32_t kBccPayloadSubjPubKey = -4670552;
38 constexpr int32_t kBccPayloadKeyUsage = -4670553;
39 constexpr int kP256AffinePointSize = 32;
40
41 using EC_KEY_Ptr = bssl::UniquePtr<EC_KEY>;
42 using EVP_PKEY_Ptr = bssl::UniquePtr<EVP_PKEY>;
43 using EVP_PKEY_CTX_Ptr = bssl::UniquePtr<EVP_PKEY_CTX>;
44
ecKeyGetPrivateKey(const EC_KEY * ecKey)45 ErrMsgOr<bytevec> ecKeyGetPrivateKey(const EC_KEY* ecKey) {
46 // Extract private key.
47 const BIGNUM* bignum = EC_KEY_get0_private_key(ecKey);
48 if (bignum == nullptr) {
49 return "Error getting bignum from private key";
50 }
51 // Pad with zeros in case the length is lesser than 32.
52 bytevec privKey(32, 0);
53 BN_bn2binpad(bignum, privKey.data(), privKey.size());
54 return privKey;
55 }
56
ecKeyGetPublicKey(const EC_KEY * ecKey)57 ErrMsgOr<bytevec> ecKeyGetPublicKey(const EC_KEY* ecKey) {
58 // Extract public key.
59 auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
60 if (group.get() == nullptr) {
61 return "Error creating EC group by curve name";
62 }
63 const EC_POINT* point = EC_KEY_get0_public_key(ecKey);
64 if (point == nullptr) return "Error getting ecpoint from public key";
65
66 int size =
67 EC_POINT_point2oct(group.get(), point, POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr);
68 if (size == 0) {
69 return "Error generating public key encoding";
70 }
71
72 bytevec publicKey;
73 publicKey.resize(size);
74 EC_POINT_point2oct(group.get(), point, POINT_CONVERSION_UNCOMPRESSED, publicKey.data(),
75 publicKey.size(), nullptr);
76 return publicKey;
77 }
78
getAffineCoordinates(const bytevec & pubKey)79 ErrMsgOr<std::tuple<bytevec, bytevec>> getAffineCoordinates(const bytevec& pubKey) {
80 auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
81 if (group.get() == nullptr) {
82 return "Error creating EC group by curve name";
83 }
84 auto point = EC_POINT_Ptr(EC_POINT_new(group.get()));
85 if (EC_POINT_oct2point(group.get(), point.get(), pubKey.data(), pubKey.size(), nullptr) != 1) {
86 return "Error decoding publicKey";
87 }
88 BIGNUM_Ptr x(BN_new());
89 BIGNUM_Ptr y(BN_new());
90 BN_CTX_Ptr ctx(BN_CTX_new());
91 if (!ctx.get()) return "Failed to create BN_CTX instance";
92
93 if (!EC_POINT_get_affine_coordinates_GFp(group.get(), point.get(), x.get(), y.get(),
94 ctx.get())) {
95 return "Failed to get affine coordinates from ECPoint";
96 }
97 bytevec pubX(kP256AffinePointSize);
98 bytevec pubY(kP256AffinePointSize);
99 if (BN_bn2binpad(x.get(), pubX.data(), kP256AffinePointSize) != kP256AffinePointSize) {
100 return "Error in converting absolute value of x coordinate to big-endian";
101 }
102 if (BN_bn2binpad(y.get(), pubY.data(), kP256AffinePointSize) != kP256AffinePointSize) {
103 return "Error in converting absolute value of y coordinate to big-endian";
104 }
105 return std::make_tuple(std::move(pubX), std::move(pubY));
106 }
107
generateEc256KeyPair()108 ErrMsgOr<std::tuple<bytevec, bytevec>> generateEc256KeyPair() {
109 auto ec_key = EC_KEY_Ptr(EC_KEY_new());
110 if (ec_key.get() == nullptr) {
111 return "Failed to allocate ec key";
112 }
113
114 auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
115 if (group.get() == nullptr) {
116 return "Error creating EC group by curve name";
117 }
118
119 if (EC_KEY_set_group(ec_key.get(), group.get()) != 1 ||
120 EC_KEY_generate_key(ec_key.get()) != 1 || EC_KEY_check_key(ec_key.get()) < 0) {
121 return "Error generating key";
122 }
123
124 auto privKey = ecKeyGetPrivateKey(ec_key.get());
125 if (!privKey) return privKey.moveMessage();
126
127 auto pubKey = ecKeyGetPublicKey(ec_key.get());
128 if (!pubKey) return pubKey.moveMessage();
129
130 return std::make_tuple(pubKey.moveValue(), privKey.moveValue());
131 }
132
generateX25519KeyPair()133 ErrMsgOr<std::tuple<bytevec, bytevec>> generateX25519KeyPair() {
134 /* Generate X25519 key pair */
135 bytevec pubKey(X25519_PUBLIC_VALUE_LEN);
136 bytevec privKey(X25519_PRIVATE_KEY_LEN);
137 X25519_keypair(pubKey.data(), privKey.data());
138 return std::make_tuple(std::move(pubKey), std::move(privKey));
139 }
140
generateED25519KeyPair()141 ErrMsgOr<std::tuple<bytevec, bytevec>> generateED25519KeyPair() {
142 /* Generate ED25519 key pair */
143 bytevec pubKey(ED25519_PUBLIC_KEY_LEN);
144 bytevec privKey(ED25519_PRIVATE_KEY_LEN);
145 ED25519_keypair(pubKey.data(), privKey.data());
146 return std::make_tuple(std::move(pubKey), std::move(privKey));
147 }
148
generateKeyPair(int32_t supportedEekCurve,bool isEek)149 ErrMsgOr<std::tuple<bytevec, bytevec>> generateKeyPair(int32_t supportedEekCurve, bool isEek) {
150 switch (supportedEekCurve) {
151 case RpcHardwareInfo::CURVE_25519:
152 if (isEek) {
153 return generateX25519KeyPair();
154 }
155 return generateED25519KeyPair();
156 case RpcHardwareInfo::CURVE_P256:
157 return generateEc256KeyPair();
158 default:
159 return "Unknown EEK Curve.";
160 }
161 }
162
constructCoseKey(int32_t supportedEekCurve,const bytevec & eekId,const bytevec & pubKey)163 ErrMsgOr<bytevec> constructCoseKey(int32_t supportedEekCurve, const bytevec& eekId,
164 const bytevec& pubKey) {
165 CoseKeyType keyType;
166 CoseKeyAlgorithm algorithm;
167 CoseKeyCurve curve;
168 bytevec pubX;
169 bytevec pubY;
170 switch (supportedEekCurve) {
171 case RpcHardwareInfo::CURVE_25519:
172 keyType = OCTET_KEY_PAIR;
173 algorithm = (eekId.empty()) ? EDDSA : ECDH_ES_HKDF_256;
174 curve = (eekId.empty()) ? ED25519 : cppcose::X25519;
175 pubX = pubKey;
176 break;
177 case RpcHardwareInfo::CURVE_P256: {
178 keyType = EC2;
179 algorithm = (eekId.empty()) ? ES256 : ECDH_ES_HKDF_256;
180 curve = P256;
181 auto affineCoordinates = getAffineCoordinates(pubKey);
182 if (!affineCoordinates) return affineCoordinates.moveMessage();
183 std::tie(pubX, pubY) = affineCoordinates.moveValue();
184 } break;
185 default:
186 return "Unknown EEK Curve.";
187 }
188 cppbor::Map coseKey = cppbor::Map()
189 .add(CoseKey::KEY_TYPE, keyType)
190 .add(CoseKey::ALGORITHM, algorithm)
191 .add(CoseKey::CURVE, curve)
192 .add(CoseKey::PUBKEY_X, pubX);
193
194 if (!pubY.empty()) coseKey.add(CoseKey::PUBKEY_Y, pubY);
195 if (!eekId.empty()) coseKey.add(CoseKey::KEY_ID, eekId);
196
197 return coseKey.canonicalize().encode();
198 }
199
200 bytevec kTestMacKey(32 /* count */, 0 /* byte value */);
201
randomBytes(size_t numBytes)202 bytevec randomBytes(size_t numBytes) {
203 bytevec retval(numBytes);
204 RAND_bytes(retval.data(), numBytes);
205 return retval;
206 }
207
constructCoseSign1(int32_t supportedEekCurve,const bytevec & key,const bytevec & payload,const bytevec & aad)208 ErrMsgOr<cppbor::Array> constructCoseSign1(int32_t supportedEekCurve, const bytevec& key,
209 const bytevec& payload, const bytevec& aad) {
210 if (supportedEekCurve == RpcHardwareInfo::CURVE_P256) {
211 return constructECDSACoseSign1(key, {} /* protectedParams */, payload, aad);
212 } else {
213 return cppcose::constructCoseSign1(key, payload, aad);
214 }
215 }
216
generateEekChain(int32_t supportedEekCurve,size_t length,const bytevec & eekId)217 ErrMsgOr<EekChain> generateEekChain(int32_t supportedEekCurve, size_t length,
218 const bytevec& eekId) {
219 if (length < 2) {
220 return "EEK chain must contain at least 2 certs.";
221 }
222
223 auto eekChain = cppbor::Array();
224
225 bytevec prev_priv_key;
226 for (size_t i = 0; i < length - 1; ++i) {
227 auto keyPair = generateKeyPair(supportedEekCurve, false);
228 if (!keyPair) return keyPair.moveMessage();
229 auto [pub_key, priv_key] = keyPair.moveValue();
230
231 // The first signing key is self-signed.
232 if (prev_priv_key.empty()) prev_priv_key = priv_key;
233
234 auto coseKey = constructCoseKey(supportedEekCurve, {}, pub_key);
235 if (!coseKey) return coseKey.moveMessage();
236
237 auto coseSign1 =
238 constructCoseSign1(supportedEekCurve, prev_priv_key, coseKey.moveValue(), {} /* AAD */);
239 if (!coseSign1) return coseSign1.moveMessage();
240 eekChain.add(coseSign1.moveValue());
241
242 prev_priv_key = priv_key;
243 }
244 auto keyPair = generateKeyPair(supportedEekCurve, true);
245 if (!keyPair) return keyPair.moveMessage();
246 auto [pub_key, priv_key] = keyPair.moveValue();
247
248 auto coseKey = constructCoseKey(supportedEekCurve, eekId, pub_key);
249 if (!coseKey) return coseKey.moveMessage();
250
251 auto coseSign1 =
252 constructCoseSign1(supportedEekCurve, prev_priv_key, coseKey.moveValue(), {} /* AAD */);
253 if (!coseSign1) return coseSign1.moveMessage();
254 eekChain.add(coseSign1.moveValue());
255
256 if (supportedEekCurve == RpcHardwareInfo::CURVE_P256) {
257 // convert ec public key to x and y co-ordinates.
258 auto affineCoordinates = getAffineCoordinates(pub_key);
259 if (!affineCoordinates) return affineCoordinates.moveMessage();
260 auto [pubX, pubY] = affineCoordinates.moveValue();
261 pub_key.clear();
262 pub_key.insert(pub_key.begin(), pubX.begin(), pubX.end());
263 pub_key.insert(pub_key.end(), pubY.begin(), pubY.end());
264 }
265
266 return EekChain{eekChain.encode(), pub_key, priv_key};
267 }
268
getProdEekChain(int32_t supportedEekCurve)269 bytevec getProdEekChain(int32_t supportedEekCurve) {
270 cppbor::Array chain;
271 if (supportedEekCurve == RpcHardwareInfo::CURVE_P256) {
272 chain.add(cppbor::EncodedItem(bytevec(std::begin(kCoseEncodedEcdsa256RootCert),
273 std::end(kCoseEncodedEcdsa256RootCert))));
274 chain.add(cppbor::EncodedItem(bytevec(std::begin(kCoseEncodedEcdsa256GeekCert),
275 std::end(kCoseEncodedEcdsa256GeekCert))));
276 } else {
277 chain.add(cppbor::EncodedItem(
278 bytevec(std::begin(kCoseEncodedRootCert), std::end(kCoseEncodedRootCert))));
279 chain.add(cppbor::EncodedItem(
280 bytevec(std::begin(kCoseEncodedGeekCert), std::end(kCoseEncodedGeekCert))));
281 }
282 return chain.encode();
283 }
284
validatePayloadAndFetchPubKey(const cppbor::Map * payload)285 ErrMsgOr<bytevec> validatePayloadAndFetchPubKey(const cppbor::Map* payload) {
286 const auto& issuer = payload->get(kBccPayloadIssuer);
287 if (!issuer || !issuer->asTstr()) return "Issuer is not present or not a tstr.";
288 const auto& subject = payload->get(kBccPayloadSubject);
289 if (!subject || !subject->asTstr()) return "Subject is not present or not a tstr.";
290 const auto& keyUsage = payload->get(kBccPayloadKeyUsage);
291 if (!keyUsage || !keyUsage->asBstr()) return "Key usage is not present or not a bstr.";
292 const auto& serializedKey = payload->get(kBccPayloadSubjPubKey);
293 if (!serializedKey || !serializedKey->asBstr()) return "Key is not present or not a bstr.";
294 return serializedKey->asBstr()->value();
295 }
296
verifyAndParseCoseSign1Cwt(const cppbor::Array * coseSign1,const bytevec & signingCoseKey,const bytevec & aad)297 ErrMsgOr<bytevec> verifyAndParseCoseSign1Cwt(const cppbor::Array* coseSign1,
298 const bytevec& signingCoseKey, const bytevec& aad) {
299 if (!coseSign1 || coseSign1->size() != kCoseSign1EntryCount) {
300 return "Invalid COSE_Sign1";
301 }
302
303 const cppbor::Bstr* protectedParams = coseSign1->get(kCoseSign1ProtectedParams)->asBstr();
304 const cppbor::Map* unprotectedParams = coseSign1->get(kCoseSign1UnprotectedParams)->asMap();
305 const cppbor::Bstr* payload = coseSign1->get(kCoseSign1Payload)->asBstr();
306 const cppbor::Bstr* signature = coseSign1->get(kCoseSign1Signature)->asBstr();
307
308 if (!protectedParams || !unprotectedParams || !payload || !signature) {
309 return "Invalid COSE_Sign1";
310 }
311
312 auto [parsedProtParams, _, errMsg] = cppbor::parse(protectedParams);
313 if (!parsedProtParams) {
314 return errMsg + " when parsing protected params.";
315 }
316 if (!parsedProtParams->asMap()) {
317 return "Protected params must be a map";
318 }
319
320 auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM);
321 if (!algorithm || !algorithm->asInt() ||
322 (algorithm->asInt()->value() != EDDSA && algorithm->asInt()->value() != ES256)) {
323 return "Unsupported signature algorithm";
324 }
325
326 auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(payload);
327 if (!parsedPayload) return payloadErrMsg + " when parsing key";
328 if (!parsedPayload->asMap()) return "CWT must be a map";
329 auto serializedKey = validatePayloadAndFetchPubKey(parsedPayload->asMap());
330 if (!serializedKey) {
331 return "CWT validation failed: " + serializedKey.moveMessage();
332 }
333
334 bool selfSigned = signingCoseKey.empty();
335 bytevec signatureInput =
336 cppbor::Array().add("Signature1").add(*protectedParams).add(aad).add(*payload).encode();
337
338 if (algorithm->asInt()->value() == EDDSA) {
339 auto key = CoseKey::parseEd25519(selfSigned ? *serializedKey : signingCoseKey);
340
341 if (!key) return "Bad signing key: " + key.moveMessage();
342
343 if (!ED25519_verify(signatureInput.data(), signatureInput.size(), signature->value().data(),
344 key->getBstrValue(CoseKey::PUBKEY_X)->data())) {
345 return "Signature verification failed";
346 }
347 } else { // P256
348 auto key = CoseKey::parseP256(selfSigned ? *serializedKey : signingCoseKey);
349 if (!key || key->getBstrValue(CoseKey::PUBKEY_X)->empty() ||
350 key->getBstrValue(CoseKey::PUBKEY_Y)->empty()) {
351 return "Bad signing key: " + key.moveMessage();
352 }
353 auto publicKey = key->getEcPublicKey();
354 if (!publicKey) return publicKey.moveMessage();
355
356 auto ecdsaDerSignature = ecdsaCoseSignatureToDer(signature->value());
357 if (!ecdsaDerSignature) return ecdsaDerSignature.moveMessage();
358
359 // convert public key to uncompressed form.
360 publicKey->insert(publicKey->begin(), 0x04);
361
362 if (!verifyEcdsaDigest(publicKey.moveValue(), sha256(signatureInput), *ecdsaDerSignature)) {
363 return "Signature verification failed";
364 }
365 }
366
367 return serializedKey.moveValue();
368 }
369
validateBcc(const cppbor::Array * bcc)370 ErrMsgOr<std::vector<BccEntryData>> validateBcc(const cppbor::Array* bcc) {
371 if (!bcc || bcc->size() == 0) return "Invalid BCC";
372
373 std::vector<BccEntryData> result;
374
375 const auto& devicePubKey = bcc->get(0);
376 if (!devicePubKey->asMap()) return "Invalid device public key at the 1st entry in the BCC";
377
378 bytevec prevKey;
379
380 for (size_t i = 1; i < bcc->size(); ++i) {
381 const cppbor::Array* entry = bcc->get(i)->asArray();
382 if (!entry || entry->size() != kCoseSign1EntryCount) {
383 return "Invalid BCC entry " + std::to_string(i) + ": " + prettyPrint(entry);
384 }
385 auto payload = verifyAndParseCoseSign1Cwt(entry, std::move(prevKey), bytevec{} /* AAD */);
386 if (!payload) {
387 return "Failed to verify entry " + std::to_string(i) + ": " + payload.moveMessage();
388 }
389
390 auto& certProtParms = entry->get(kCoseSign1ProtectedParams);
391 if (!certProtParms || !certProtParms->asBstr()) return "Invalid prot params";
392 auto [parsedProtParms, _, errMsg] = cppbor::parse(certProtParms->asBstr()->value());
393 if (!parsedProtParms || !parsedProtParms->asMap()) return "Invalid prot params";
394
395 result.push_back(BccEntryData{*payload});
396
397 // This entry's public key is the signing key for the next entry.
398 prevKey = payload.moveValue();
399 if (i == 1) {
400 auto [parsedRootKey, _, errMsg] = cppbor::parse(prevKey);
401 if (!parsedRootKey || !parsedRootKey->asMap()) return "Invalid payload entry in BCC.";
402 if (*parsedRootKey != *devicePubKey) {
403 return "Device public key doesn't match BCC root.";
404 }
405 }
406 }
407
408 return result;
409 }
410
jsonEncodeCsrWithBuild(const std::string instance_name,const cppbor::Array & csr)411 JsonOutput jsonEncodeCsrWithBuild(const std::string instance_name, const cppbor::Array& csr) {
412 const std::string kFingerprintProp = "ro.build.fingerprint";
413
414 if (!::android::base::WaitForPropertyCreation(kFingerprintProp)) {
415 return JsonOutput::Error("Unable to read build fingerprint");
416 }
417
418 bytevec csrCbor = csr.encode();
419 size_t base64Length;
420 int rc = EVP_EncodedLength(&base64Length, csrCbor.size());
421 if (!rc) {
422 return JsonOutput::Error("Error getting base64 length. Size overflow?");
423 }
424
425 std::vector<char> base64(base64Length);
426 rc = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(base64.data()), csrCbor.data(), csrCbor.size());
427 ++rc; // Account for NUL, which BoringSSL does not for some reason.
428 if (rc != base64Length) {
429 return JsonOutput::Error("Error writing base64. Expected " + std::to_string(base64Length) +
430 " bytes to be written, but " + std::to_string(rc) +
431 " bytes were actually written.");
432 }
433
434 Json::Value json(Json::objectValue);
435 json["name"] = instance_name;
436 json["build_fingerprint"] = ::android::base::GetProperty(kFingerprintProp, /*default=*/"");
437 json["csr"] = base64.data(); // Boring writes a NUL-terminated c-string
438
439 Json::StreamWriterBuilder factory;
440 factory["indentation"] = ""; // disable pretty formatting
441 return JsonOutput::Ok(Json::writeString(factory, json));
442 }
443
444 } // namespace aidl::android::hardware::security::keymint::remote_prov
445