1*789431f2SAndroid Build Coastguard Worker /*
2*789431f2SAndroid Build Coastguard Worker * Copyright 2021 The Android Open Source Project
3*789431f2SAndroid Build Coastguard Worker *
4*789431f2SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*789431f2SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*789431f2SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*789431f2SAndroid Build Coastguard Worker *
8*789431f2SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*789431f2SAndroid Build Coastguard Worker *
10*789431f2SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*789431f2SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*789431f2SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*789431f2SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*789431f2SAndroid Build Coastguard Worker * limitations under the License.
15*789431f2SAndroid Build Coastguard Worker */
16*789431f2SAndroid Build Coastguard Worker
17*789431f2SAndroid Build Coastguard Worker #include <keymaster/remote_provisioning_utils.h>
18*789431f2SAndroid Build Coastguard Worker
19*789431f2SAndroid Build Coastguard Worker #include <algorithm>
20*789431f2SAndroid Build Coastguard Worker #include <span>
21*789431f2SAndroid Build Coastguard Worker
22*789431f2SAndroid Build Coastguard Worker #include <keymaster/cppcose/cppcose.h>
23*789431f2SAndroid Build Coastguard Worker #include <keymaster/logger.h>
24*789431f2SAndroid Build Coastguard Worker
25*789431f2SAndroid Build Coastguard Worker namespace keymaster {
26*789431f2SAndroid Build Coastguard Worker
27*789431f2SAndroid Build Coastguard Worker using cppcose::ALGORITHM;
28*789431f2SAndroid Build Coastguard Worker using cppcose::COSE_KEY;
29*789431f2SAndroid Build Coastguard Worker using cppcose::CoseKey;
30*789431f2SAndroid Build Coastguard Worker using cppcose::CoseKeyCurve;
31*789431f2SAndroid Build Coastguard Worker using cppcose::EC2;
32*789431f2SAndroid Build Coastguard Worker using cppcose::ECDH_ES_HKDF_256;
33*789431f2SAndroid Build Coastguard Worker using cppcose::ES256;
34*789431f2SAndroid Build Coastguard Worker using cppcose::generateCoseMac0Mac;
35*789431f2SAndroid Build Coastguard Worker using cppcose::HMAC_256;
36*789431f2SAndroid Build Coastguard Worker using cppcose::kCoseMac0EntryCount;
37*789431f2SAndroid Build Coastguard Worker using cppcose::kCoseMac0Payload;
38*789431f2SAndroid Build Coastguard Worker using cppcose::kCoseMac0ProtectedParams;
39*789431f2SAndroid Build Coastguard Worker using cppcose::kCoseMac0Tag;
40*789431f2SAndroid Build Coastguard Worker using cppcose::kCoseMac0UnprotectedParams;
41*789431f2SAndroid Build Coastguard Worker using cppcose::KEY_ID;
42*789431f2SAndroid Build Coastguard Worker using cppcose::OCTET_KEY_PAIR;
43*789431f2SAndroid Build Coastguard Worker using cppcose::P256;
44*789431f2SAndroid Build Coastguard Worker using cppcose::verifyAndParseCoseSign1;
45*789431f2SAndroid Build Coastguard Worker
46*789431f2SAndroid Build Coastguard Worker using byte_view = std::span<const uint8_t>;
47*789431f2SAndroid Build Coastguard Worker
48*789431f2SAndroid Build Coastguard Worker struct KeyInfo {
49*789431f2SAndroid Build Coastguard Worker CoseKeyCurve curve;
50*789431f2SAndroid Build Coastguard Worker byte_view pubkey;
51*789431f2SAndroid Build Coastguard Worker // Note: There's no need to include algorithm here, since it is assumed
52*789431f2SAndroid Build Coastguard Worker // that all root keys are EDDSA.
53*789431f2SAndroid Build Coastguard Worker
operator ==keymaster::KeyInfo54*789431f2SAndroid Build Coastguard Worker bool operator==(const KeyInfo& other) const {
55*789431f2SAndroid Build Coastguard Worker return curve == other.curve &&
56*789431f2SAndroid Build Coastguard Worker std::equal(pubkey.begin(), pubkey.end(), other.pubkey.begin(), other.pubkey.end());
57*789431f2SAndroid Build Coastguard Worker }
58*789431f2SAndroid Build Coastguard Worker };
59*789431f2SAndroid Build Coastguard Worker
60*789431f2SAndroid Build Coastguard Worker // The production root signing key for Google Endpoint Encryption Key cert chains.
61*789431f2SAndroid Build Coastguard Worker inline constexpr uint8_t kGeekRoot[] = {
62*789431f2SAndroid Build Coastguard Worker 0x99, 0xB9, 0xEE, 0xDD, 0x5E, 0xE4, 0x52, 0xF6, 0x85, 0xC6, 0x4C, 0x62, 0xDC, 0x3E, 0x61, 0xAB,
63*789431f2SAndroid Build Coastguard Worker 0x57, 0x48, 0x7D, 0x75, 0x37, 0x29, 0xAD, 0x76, 0x80, 0x32, 0xD2, 0xB3, 0xCB, 0x63, 0x58, 0xD9};
64*789431f2SAndroid Build Coastguard Worker
65*789431f2SAndroid Build Coastguard Worker // Hard-coded set of acceptable public COSE_Keys that can act as roots of EEK chains.
66*789431f2SAndroid Build Coastguard Worker inline constexpr KeyInfo kAuthorizedEekRoots[] = {
67*789431f2SAndroid Build Coastguard Worker {CoseKeyCurve::ED25519, byte_view(kGeekRoot, sizeof(kGeekRoot))},
68*789431f2SAndroid Build Coastguard Worker };
69*789431f2SAndroid Build Coastguard Worker
70*789431f2SAndroid Build Coastguard Worker StatusOr<std::pair<std::vector<uint8_t> /* EEK pub */, std::vector<uint8_t> /* EEK ID */>>
validateAndExtractEekPubAndId(bool testMode,const KeymasterBlob & endpointEncryptionCertChain)71*789431f2SAndroid Build Coastguard Worker validateAndExtractEekPubAndId(bool testMode, const KeymasterBlob& endpointEncryptionCertChain) {
72*789431f2SAndroid Build Coastguard Worker auto [item, newPos, errMsg] =
73*789431f2SAndroid Build Coastguard Worker cppbor::parse(endpointEncryptionCertChain.begin(), endpointEncryptionCertChain.end());
74*789431f2SAndroid Build Coastguard Worker
75*789431f2SAndroid Build Coastguard Worker if (!item || !item->asArray()) {
76*789431f2SAndroid Build Coastguard Worker LOG_E("Error parsing EEK chain: %s", errMsg.c_str());
77*789431f2SAndroid Build Coastguard Worker return kStatusFailed;
78*789431f2SAndroid Build Coastguard Worker }
79*789431f2SAndroid Build Coastguard Worker
80*789431f2SAndroid Build Coastguard Worker const cppbor::Array* certArr = item->asArray();
81*789431f2SAndroid Build Coastguard Worker std::vector<uint8_t> lastPubKey;
82*789431f2SAndroid Build Coastguard Worker for (size_t i = 0; i < certArr->size(); ++i) {
83*789431f2SAndroid Build Coastguard Worker auto cosePubKey =
84*789431f2SAndroid Build Coastguard Worker verifyAndParseCoseSign1(certArr->get(i)->asArray(), lastPubKey, {} /* AAD */);
85*789431f2SAndroid Build Coastguard Worker if (!cosePubKey) {
86*789431f2SAndroid Build Coastguard Worker LOG_E("Failed to validate EEK chain: %s", cosePubKey.moveMessage().c_str());
87*789431f2SAndroid Build Coastguard Worker return kStatusInvalidEek;
88*789431f2SAndroid Build Coastguard Worker }
89*789431f2SAndroid Build Coastguard Worker lastPubKey = *std::move(cosePubKey);
90*789431f2SAndroid Build Coastguard Worker
91*789431f2SAndroid Build Coastguard Worker // In prod mode the first pubkey should match a well-known Google public key.
92*789431f2SAndroid Build Coastguard Worker if (!testMode && i == 0) {
93*789431f2SAndroid Build Coastguard Worker auto parsedPubKey = CoseKey::parse(lastPubKey);
94*789431f2SAndroid Build Coastguard Worker if (!parsedPubKey) {
95*789431f2SAndroid Build Coastguard Worker LOG_E("%s", parsedPubKey.moveMessage().c_str());
96*789431f2SAndroid Build Coastguard Worker return kStatusFailed;
97*789431f2SAndroid Build Coastguard Worker }
98*789431f2SAndroid Build Coastguard Worker
99*789431f2SAndroid Build Coastguard Worker auto curve = parsedPubKey->getIntValue(CoseKey::CURVE);
100*789431f2SAndroid Build Coastguard Worker if (!curve) {
101*789431f2SAndroid Build Coastguard Worker LOG_E("Key is missing required label 'CURVE'");
102*789431f2SAndroid Build Coastguard Worker return kStatusInvalidEek;
103*789431f2SAndroid Build Coastguard Worker }
104*789431f2SAndroid Build Coastguard Worker
105*789431f2SAndroid Build Coastguard Worker auto rawPubKey = parsedPubKey->getBstrValue(CoseKey::PUBKEY_X);
106*789431f2SAndroid Build Coastguard Worker if (!rawPubKey) {
107*789431f2SAndroid Build Coastguard Worker LOG_E("Key is missing required label 'PUBKEY_X'");
108*789431f2SAndroid Build Coastguard Worker return kStatusInvalidEek;
109*789431f2SAndroid Build Coastguard Worker }
110*789431f2SAndroid Build Coastguard Worker
111*789431f2SAndroid Build Coastguard Worker KeyInfo matcher = {static_cast<CoseKeyCurve>(*curve),
112*789431f2SAndroid Build Coastguard Worker byte_view(rawPubKey->data(), rawPubKey->size())};
113*789431f2SAndroid Build Coastguard Worker if (std::find(std::begin(kAuthorizedEekRoots), std::end(kAuthorizedEekRoots),
114*789431f2SAndroid Build Coastguard Worker matcher) == std::end(kAuthorizedEekRoots)) {
115*789431f2SAndroid Build Coastguard Worker LOG_E("Unrecognized root of EEK chain");
116*789431f2SAndroid Build Coastguard Worker return kStatusInvalidEek;
117*789431f2SAndroid Build Coastguard Worker }
118*789431f2SAndroid Build Coastguard Worker }
119*789431f2SAndroid Build Coastguard Worker }
120*789431f2SAndroid Build Coastguard Worker
121*789431f2SAndroid Build Coastguard Worker auto eek = CoseKey::parseX25519(lastPubKey, true /* requireKid */);
122*789431f2SAndroid Build Coastguard Worker if (!eek) {
123*789431f2SAndroid Build Coastguard Worker LOG_E("Failed to get EEK: %s", eek.moveMessage().c_str());
124*789431f2SAndroid Build Coastguard Worker return kStatusInvalidEek;
125*789431f2SAndroid Build Coastguard Worker }
126*789431f2SAndroid Build Coastguard Worker
127*789431f2SAndroid Build Coastguard Worker return std::make_pair(eek->getBstrValue(CoseKey::PUBKEY_X).value(),
128*789431f2SAndroid Build Coastguard Worker eek->getBstrValue(CoseKey::KEY_ID).value());
129*789431f2SAndroid Build Coastguard Worker }
130*789431f2SAndroid Build Coastguard Worker
131*789431f2SAndroid Build Coastguard Worker StatusOr<cppbor::Array /* pubkeys */>
validateAndExtractPubkeys(bool testMode,uint32_t numKeys,KeymasterBlob * keysToSign,const cppcose::HmacSha256Function & macFunction)132*789431f2SAndroid Build Coastguard Worker validateAndExtractPubkeys(bool testMode, uint32_t numKeys, KeymasterBlob* keysToSign,
133*789431f2SAndroid Build Coastguard Worker const cppcose::HmacSha256Function& macFunction) {
134*789431f2SAndroid Build Coastguard Worker auto pubKeysToMac = cppbor::Array();
135*789431f2SAndroid Build Coastguard Worker for (size_t i = 0; i < numKeys; i++) {
136*789431f2SAndroid Build Coastguard Worker auto [macedKeyItem, _, coseMacErrMsg] =
137*789431f2SAndroid Build Coastguard Worker cppbor::parse(keysToSign[i].begin(), keysToSign[i].end());
138*789431f2SAndroid Build Coastguard Worker if (!macedKeyItem || !macedKeyItem->asArray() ||
139*789431f2SAndroid Build Coastguard Worker macedKeyItem->asArray()->size() != kCoseMac0EntryCount) {
140*789431f2SAndroid Build Coastguard Worker LOG_E("Invalid COSE_Mac0 structure");
141*789431f2SAndroid Build Coastguard Worker return kStatusFailed;
142*789431f2SAndroid Build Coastguard Worker }
143*789431f2SAndroid Build Coastguard Worker
144*789431f2SAndroid Build Coastguard Worker auto protectedParms = macedKeyItem->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
145*789431f2SAndroid Build Coastguard Worker auto unprotectedParms = macedKeyItem->asArray()->get(kCoseMac0UnprotectedParams)->asMap();
146*789431f2SAndroid Build Coastguard Worker auto payload = macedKeyItem->asArray()->get(kCoseMac0Payload)->asBstr();
147*789431f2SAndroid Build Coastguard Worker auto tag = macedKeyItem->asArray()->get(kCoseMac0Tag)->asBstr();
148*789431f2SAndroid Build Coastguard Worker if (!protectedParms || !unprotectedParms || !payload || !tag) {
149*789431f2SAndroid Build Coastguard Worker LOG_E("Invalid COSE_Mac0 contents");
150*789431f2SAndroid Build Coastguard Worker return kStatusFailed;
151*789431f2SAndroid Build Coastguard Worker }
152*789431f2SAndroid Build Coastguard Worker
153*789431f2SAndroid Build Coastguard Worker auto [protectedMap, __, errMsg] = cppbor::parse(protectedParms);
154*789431f2SAndroid Build Coastguard Worker if (!protectedMap || !protectedMap->asMap()) {
155*789431f2SAndroid Build Coastguard Worker LOG_E("Invalid Mac0 protected: %s", errMsg.c_str());
156*789431f2SAndroid Build Coastguard Worker return kStatusFailed;
157*789431f2SAndroid Build Coastguard Worker }
158*789431f2SAndroid Build Coastguard Worker auto& algo = protectedMap->asMap()->get(ALGORITHM);
159*789431f2SAndroid Build Coastguard Worker if (!algo || !algo->asInt() || algo->asInt()->value() != HMAC_256) {
160*789431f2SAndroid Build Coastguard Worker LOG_E("Unsupported Mac0 algorithm");
161*789431f2SAndroid Build Coastguard Worker return kStatusFailed;
162*789431f2SAndroid Build Coastguard Worker }
163*789431f2SAndroid Build Coastguard Worker
164*789431f2SAndroid Build Coastguard Worker auto pubKey = CoseKey::parse(payload->value(), EC2, ES256, P256);
165*789431f2SAndroid Build Coastguard Worker if (!pubKey) {
166*789431f2SAndroid Build Coastguard Worker LOG_E("%s", pubKey.moveMessage().c_str());
167*789431f2SAndroid Build Coastguard Worker return kStatusFailed;
168*789431f2SAndroid Build Coastguard Worker }
169*789431f2SAndroid Build Coastguard Worker
170*789431f2SAndroid Build Coastguard Worker bool testKey = static_cast<bool>(pubKey->getMap().get(CoseKey::TEST_KEY));
171*789431f2SAndroid Build Coastguard Worker if (testMode && !testKey) {
172*789431f2SAndroid Build Coastguard Worker LOG_E("Production key in test request");
173*789431f2SAndroid Build Coastguard Worker return kStatusProductionKeyInTestRequest;
174*789431f2SAndroid Build Coastguard Worker } else if (!testMode && testKey) {
175*789431f2SAndroid Build Coastguard Worker LOG_E("Test key in production request");
176*789431f2SAndroid Build Coastguard Worker return kStatusTestKeyInProductionRequest;
177*789431f2SAndroid Build Coastguard Worker }
178*789431f2SAndroid Build Coastguard Worker
179*789431f2SAndroid Build Coastguard Worker auto macTag = generateCoseMac0Mac(macFunction, {} /* external_aad */, payload->value());
180*789431f2SAndroid Build Coastguard Worker if (!macTag) {
181*789431f2SAndroid Build Coastguard Worker LOG_E("%s", macTag.moveMessage().c_str());
182*789431f2SAndroid Build Coastguard Worker return kStatusInvalidMac;
183*789431f2SAndroid Build Coastguard Worker }
184*789431f2SAndroid Build Coastguard Worker if (macTag->size() != tag->value().size() ||
185*789431f2SAndroid Build Coastguard Worker CRYPTO_memcmp(macTag->data(), tag->value().data(), macTag->size()) != 0) {
186*789431f2SAndroid Build Coastguard Worker LOG_E("MAC tag mismatch");
187*789431f2SAndroid Build Coastguard Worker return kStatusInvalidMac;
188*789431f2SAndroid Build Coastguard Worker }
189*789431f2SAndroid Build Coastguard Worker
190*789431f2SAndroid Build Coastguard Worker pubKeysToMac.add(pubKey->moveMap());
191*789431f2SAndroid Build Coastguard Worker }
192*789431f2SAndroid Build Coastguard Worker
193*789431f2SAndroid Build Coastguard Worker return pubKeysToMac;
194*789431f2SAndroid Build Coastguard Worker }
195*789431f2SAndroid Build Coastguard Worker
buildCertReqRecipients(const std::vector<uint8_t> & pubkey,const std::vector<uint8_t> & kid)196*789431f2SAndroid Build Coastguard Worker cppbor::Array buildCertReqRecipients(const std::vector<uint8_t>& pubkey,
197*789431f2SAndroid Build Coastguard Worker const std::vector<uint8_t>& kid) {
198*789431f2SAndroid Build Coastguard Worker return cppbor::Array() // Array of recipients
199*789431f2SAndroid Build Coastguard Worker .add(cppbor::Array() // Recipient
200*789431f2SAndroid Build Coastguard Worker .add(cppbor::Map() // Protected
201*789431f2SAndroid Build Coastguard Worker .add(ALGORITHM, ECDH_ES_HKDF_256)
202*789431f2SAndroid Build Coastguard Worker .canonicalize()
203*789431f2SAndroid Build Coastguard Worker .encode())
204*789431f2SAndroid Build Coastguard Worker .add(cppbor::Map() // Unprotected
205*789431f2SAndroid Build Coastguard Worker .add(COSE_KEY, cppbor::Map()
206*789431f2SAndroid Build Coastguard Worker .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
207*789431f2SAndroid Build Coastguard Worker .add(CoseKey::CURVE, cppcose::X25519)
208*789431f2SAndroid Build Coastguard Worker .add(CoseKey::PUBKEY_X, pubkey)
209*789431f2SAndroid Build Coastguard Worker .canonicalize())
210*789431f2SAndroid Build Coastguard Worker .add(KEY_ID, kid)
211*789431f2SAndroid Build Coastguard Worker .canonicalize())
212*789431f2SAndroid Build Coastguard Worker .add(cppbor::Null())); // No ciphertext
213*789431f2SAndroid Build Coastguard Worker }
214*789431f2SAndroid Build Coastguard Worker
215*789431f2SAndroid Build Coastguard Worker } // namespace keymaster
216