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