1 /*
2 * Copyright (C) 2022 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 <inttypes.h>
18 #include <cstdint>
19
20 #include "chre/platform/log.h"
21 #include "chre/platform/shared/authentication.h"
22 #include "chre/util/macros.h"
23
24 #include "mbedtls/pk.h"
25 #include "mbedtls/sha256.h"
26
27 namespace chre {
28 namespace {
29
30 // All the size below are in bytes
31 constexpr uint32_t kEcdsaP256SigSize = 64;
32 constexpr uint32_t kEcdsaP256PublicKeySize = 64;
33 constexpr uint32_t kHeaderSize = 0x1000;
34 constexpr uint32_t kSha256HashSize = 32;
35
36 // ASCII of "CHRE", in BE
37 constexpr uint32_t kChreMagicNumber = 0x45524843;
38
39 // Production public key
40 const uint8_t kGooglePublicKey[kEcdsaP256PublicKeySize] = {
41 0x97, 0x66, 0x1f, 0xe7, 0x26, 0xc5, 0xc3, 0x9c, 0xe6, 0x71, 0x59,
42 0x1f, 0x26, 0x3b, 0x1c, 0x87, 0x50, 0x7f, 0xad, 0x4f, 0xeb, 0x4b,
43 0xe5, 0x3b, 0xee, 0x76, 0xff, 0x80, 0x6a, 0x8b, 0x6d, 0xed, 0x58,
44 0xd7, 0xed, 0xf3, 0x18, 0x9e, 0x9a, 0xac, 0xcf, 0xfc, 0xd2, 0x7,
45 0x35, 0x64, 0x54, 0xcc, 0xbc, 0x8b, 0xe0, 0x6c, 0x77, 0xbe, 0xbb,
46 0x1b, 0xdd, 0x18, 0x6d, 0x77, 0xfe, 0xb7, 0x0, 0xd5};
47
48 const uint8_t *const kTrustedPublicKeys[] = {kGooglePublicKey};
49
50 /**
51 * A data structure encapsulating metadata necessary for nanoapp binary
52 * signature verification.
53 *
54 * Note that the structure field names that start with 'reserved' are currently
55 * unused.
56 */
57 struct HeaderInfo {
58 /**
59 * A magic number indicating the start of the header info, ASCII decodes to
60 * 'CHRE'.
61 */
62 uint32_t magic;
63
64 uint32_t headerVersion;
65
66 // TODO(b/260099197): We should have a hardware backed rollback info check.
67 uint32_t reservedRollbackInfo;
68
69 /** The size in bytes of the actual nanoapp binary. */
70 uint32_t binaryLength;
71
72 /** The flag indicating the public key size. */
73 uint64_t flags[2];
74
75 /** The SHA-256 hash of the actual nanoapp binary. */
76 uint8_t binarySha256[kSha256HashSize];
77
78 uint8_t reservedChipId[32];
79
80 uint8_t reservedAuthConfig[256];
81
82 uint8_t reservedImageConfig[256];
83 };
84
85 /**
86 * A header containing information relevant to nanoapp signature authentication
87 * that is tacked onto every signed nanoapp.
88 */
89 struct ImageHeader {
90 /** The zero-padded signature of the nanoapp binary. */
91 uint8_t signature[512];
92
93 /** The zero-padded public key for the key pair used to sign the hash, which
94 * we use to verify whether we trust the signer or not. */
95 uint8_t publicKey[512];
96
97 /** @see struct HeaderInfo. */
98 HeaderInfo headerInfo;
99 };
100
101 class Authenticator {
102 public:
Authenticator()103 Authenticator() {
104 mbedtls_ecp_group_init(&mGroup);
105 mbedtls_ecp_point_init(&mQ);
106 mbedtls_mpi_init(&mR);
107 mbedtls_mpi_init(&mS);
108 }
109
~Authenticator()110 ~Authenticator() {
111 mbedtls_mpi_free(&mS);
112 mbedtls_mpi_free(&mR);
113 mbedtls_ecp_point_free(&mQ);
114 mbedtls_ecp_group_free(&mGroup);
115 }
116
loadEcpGroup()117 bool loadEcpGroup() {
118 int result = mbedtls_ecp_group_load(&mGroup, MBEDTLS_ECP_DP_SECP256R1);
119 if (result != 0) {
120 LOGE("Failed to load ecp group. Error code: %d", result);
121 return false;
122 }
123 return true;
124 }
125
loadPublicKey(const uint8_t * publicKey)126 bool loadPublicKey(const uint8_t *publicKey) {
127 // 0x04 prefix is required by mbedtls
128 constexpr uint8_t kPublicKeyPrefix = 0x04;
129 uint8_t buffer[kEcdsaP256PublicKeySize + 1] = {kPublicKeyPrefix};
130 memcpy(buffer + 1, publicKey, kEcdsaP256PublicKeySize);
131 int result =
132 mbedtls_ecp_point_read_binary(&mGroup, &mQ, buffer, ARRAY_SIZE(buffer));
133 if (result != 0) {
134 LOGE("Failed to load the public key. Error code: %d", result);
135 return false;
136 }
137 return true;
138 }
139
loadSignature(const ImageHeader * header)140 bool loadSignature(const ImageHeader *header) {
141 constexpr uint32_t kRSigSize = kEcdsaP256SigSize / 2;
142 constexpr uint32_t kSSigSize = kEcdsaP256SigSize / 2;
143 int result = mbedtls_mpi_read_binary(&mR, header->signature, kRSigSize);
144 if (result != 0) {
145 LOGE("Failed to read r signature. Error code: %d", result);
146 return false;
147 }
148 result =
149 mbedtls_mpi_read_binary(&mS, header->signature + kRSigSize, kSSigSize);
150 if (result != 0) {
151 LOGE("Failed to read s signature. Error code: %d", result);
152 return false;
153 }
154 return true;
155 }
156
authenticate(const void * binary)157 bool authenticate(const void *binary) {
158 constexpr size_t kDataOffset = 0x200;
159 constexpr size_t kDataSize = kHeaderSize - kDataOffset;
160 auto data = static_cast<const uint8_t *>(binary) + kDataOffset;
161 unsigned char digest[kSha256HashSize] = {};
162 mbedtls_sha256(data, kDataSize, digest, /* is224= */ 0);
163 int result = mbedtls_ecdsa_verify(&mGroup, digest, ARRAY_SIZE(digest), &mQ,
164 &mR, &mS);
165 if (result != 0) {
166 LOGE("Signature verification failed. Error code: %d", result);
167 return false;
168 }
169 return true;
170 }
171
172 private:
173 mbedtls_ecp_group mGroup;
174 mbedtls_ecp_point mQ;
175 mbedtls_mpi mR;
176 mbedtls_mpi mS;
177 };
178
179 /** Retrieves the public key length based on the flag. */
getPublicKeyLength(const uint64_t * flag)180 uint32_t getPublicKeyLength(const uint64_t *flag) {
181 constexpr int kPkSizeMaskPosition = 9;
182 constexpr uint64_t kPkSizeMask = 0x3;
183 uint8_t keySizeFlag = ((*flag) >> kPkSizeMaskPosition) & kPkSizeMask;
184 switch (keySizeFlag) {
185 case 0:
186 return 64;
187 case 1:
188 return 96;
189 case 2:
190 return 132;
191 default:
192 LOGE("Unsupported flags in nanoapp header!");
193 return 0;
194 }
195 }
196
197 /** Checks if the hash prvided in the header is derived from the image. */
hasCorrectHash(const void * head,size_t realImageSize,const uint8_t * hashProvided)198 bool hasCorrectHash(const void *head, size_t realImageSize,
199 const uint8_t *hashProvided) {
200 auto image = static_cast<const uint8_t *>(head) + kHeaderSize;
201 uint8_t hashCalculated[kSha256HashSize] = {};
202 mbedtls_sha256(image, realImageSize, hashCalculated, /* is224= */ 0);
203 return memcmp(hashCalculated, hashProvided, kSha256HashSize) == 0;
204 }
205
206 /** Checks if the public key in the header matches the production public key. */
isValidProductionPublicKey(const uint8_t * publicKey,size_t publicKeyLength)207 bool isValidProductionPublicKey(const uint8_t *publicKey,
208 size_t publicKeyLength) {
209 if (publicKeyLength != kEcdsaP256PublicKeySize) {
210 LOGE("Public key length %zu is unexpected.", publicKeyLength);
211 return false;
212 }
213 for (size_t i = 0; i < ARRAY_SIZE(kTrustedPublicKeys); i++) {
214 if (memcmp(kTrustedPublicKeys[i], publicKey, kEcdsaP256PublicKeySize) ==
215 0) {
216 return true;
217 }
218 }
219 return false;
220 }
221 } // anonymous namespace
222
authenticateBinary(const void * binary,size_t appBinaryLen,void ** realBinaryStart)223 bool authenticateBinary(const void *binary, size_t appBinaryLen,
224 void **realBinaryStart) {
225 #ifndef CHRE_NAPP_AUTHENTICATION_ENABLED
226 UNUSED_VAR(binary);
227 UNUSED_VAR(realBinaryStart);
228 LOGW(
229 "Nanoapp authentication is disabled, which exposes the device to "
230 "security risks!");
231 return true;
232 #endif
233 if (appBinaryLen <= kHeaderSize) {
234 LOGE("Binary size %zu is too short.", appBinaryLen);
235 return false;
236 }
237 Authenticator authenticator;
238 auto *header = static_cast<const ImageHeader *>(binary);
239 const uint8_t *imageHash = header->headerInfo.binarySha256;
240 const uint8_t *publicKey = header->publicKey;
241 const uint32_t expectedAppBinaryLength =
242 header->headerInfo.binaryLength + kHeaderSize;
243
244 if (header->headerInfo.magic != kChreMagicNumber) {
245 LOGE("Mismatched magic number.");
246 } else if (header->headerInfo.headerVersion != 1) {
247 LOGE("Header version %" PRIu32 " is unsupported.",
248 header->headerInfo.headerVersion);
249 } else if (expectedAppBinaryLength != appBinaryLen) {
250 LOGE("Invalid binary length %zu. Expected %" PRIu32, appBinaryLen,
251 expectedAppBinaryLength);
252 } else if (!isValidProductionPublicKey(
253 publicKey, getPublicKeyLength(header->headerInfo.flags))) {
254 LOGE("Invalid public key attached on the image.");
255 } else if (!hasCorrectHash(binary, header->headerInfo.binaryLength,
256 imageHash)) {
257 LOGE("Hash of the nanoapp image is incorrect.");
258 } else if (!authenticator.loadEcpGroup() ||
259 !authenticator.loadPublicKey(publicKey) ||
260 !authenticator.loadSignature(header)) {
261 LOGE("Failed to load authentication data.");
262 } else if (!authenticator.authenticate(binary)) {
263 LOGE("Failed to authenticate the image.");
264 } else {
265 *realBinaryStart = reinterpret_cast<void *>(
266 reinterpret_cast<uintptr_t>(binary) + kHeaderSize);
267 LOGI("Image is authenticated successfully!");
268 return true;
269 }
270 return false;
271 }
272 } // namespace chre
273