MCCI Trusted Bootloader
Simple trusted bootloader and tools for small embedded systems
mccibootloader_checkstorageimage.c
Go to the documentation of this file.
1/*
2
3Module: mccibootloader_checkstorageimage.c
4
5Function:
6 McciBootloader_checkStorageImage()
7
8Copyright and License:
9 This file copyright (C) 2021 by
10
11 MCCI Corporation
12 3520 Krums Corners Road
13 Ithaca, NY 14850
14
15 See accompanying LICENSE file for copyright and license information.
16
17Author:
18 Terry Moore, MCCI Corporation March 2021
19
20*/
21
22#include "mcci_bootloader.h"
23
26#include "mcci_tweetnacl_hash.h"
27#include "mcci_tweetnacl_sign.h"
28
29#include <string.h>
30
31/****************************************************************************\
32|
33| Manifest constants & typedefs.
34|
35\****************************************************************************/
36
37
38
39/****************************************************************************\
40|
41| Read-only data.
42|
43\****************************************************************************/
44
45
46/****************************************************************************\
47|
48| Variables.
49|
50\****************************************************************************/
51
52uint8_t
54
55/*
56
57Name: McciBootloader_checkStorageImage()
58
59Function:
60 Validate signature and layout of image from storage.
61
62Definition:
63 bool McciBootloader_checkStorageImage(
64 McciBootloaderStorageAddress_t address,
65 McciBootloader_AppInfo_t *pIncomingAppInfo, // OUT
66 const mcci_tweetnacl_sign_publickey_t *pPublicKey
67 );
68
69Description:
70 Read the header of the image and lightly validate it. Then
71 scan through the image, calculating the SHA512, and finallly
72 check the signature on the hash.
73
74Returns:
75 true for success, false for failure.
76
77 If true, pIncomingAppInfo is set to the app info block read from the app.
78
79Notes:
80 This is slow, so we try to update the LED state with a progress
81 indication.
82
83*/
84
85bool
88 McciBootloader_AppInfo_t *pIncomingAppInfo,
89 const mcci_tweetnacl_sign_publickey_t *pPublicKey
90 )
91 {
92 /* read the header */
94 address,
96 ))
97 return false;
98
99 const McciBootloader_AppInfo_t * const pAppInfoIn =
101
102 if (pAppInfoIn == NULL)
103 return false;
104
105 *pIncomingAppInfo = *pAppInfoIn;
106
107 uint32_t targetAddress = pIncomingAppInfo->targetAddress;
108 uint32_t targetSize = pIncomingAppInfo->imagesize + pIncomingAppInfo->authsize;
110 g_McciBootloader_imageBlock, sizeof(g_McciBootloader_imageBlock), targetAddress, targetSize
111 ))
112 return false;
113
114 mcci_tweetnacl_sha512_t imageHash;
115
116 mcci_tweetnacl_hashblocks_sha512_init(&imageHash);
117
118 // read up to, but not including, the hash
119 McciBootloaderStorageAddress_t addressCurrent;
120 McciBootloaderStorageAddress_t const addressEnd =
121 address +
122 pIncomingAppInfo->imagesize +
123 sizeof(mcci_tweetnacl_sign_publickey_t);
124
125 /* loop post condition: nThisTime is the result of the last hash */
126 uint32_t nRemaining = 0; /* initalize to zero because addressCurrent might be >= addressEnd */
127 const uint8_t *pRemaining = g_McciBootloader_imageBlock;
128
129 for (addressCurrent = address; addressCurrent < addressEnd; )
130 {
131 /* detect bizarre failures */
132 if (nRemaining != 0)
133 return false;
134
135 /* consume one gulp */
136 uint32_t nThisTime = addressEnd - addressCurrent;
137
138 if (nThisTime > sizeof(g_McciBootloader_imageBlock))
139 nThisTime = sizeof(g_McciBootloader_imageBlock);
140
141 /* optimize: don't re-read block 0 of image */
142 if (addressCurrent != address)
143 {
145 addressCurrent,
147 nThisTime
148 ))
149 return false;
150 }
151
152 /* update the hash */
153 nRemaining = mcci_tweetnacl_hashblocks_sha512(
154 &imageHash,
156 nThisTime
157 );
158
159 /* advance pointer, */
160 uint32_t const nConsumed = nThisTime - nRemaining;
161 addressCurrent += nThisTime;
162 pRemaining = g_McciBootloader_imageBlock + nConsumed;
163 }
164
165 mcci_tweetnacl_hashblocks_sha512_finish(
166 &imageHash,
167 pRemaining,
168 nRemaining,
169 addressEnd - address
170 );
171
172 // read the signature block
174 address + pIncomingAppInfo->imagesize,
176 sizeof(McciBootloader_SignatureBlock_t)
177 ))
178 return false;
179
180 const size_t nsig = sizeof(mcci_tweetnacl_sign_signature_t);
181 const size_t nsigned = sizeof(imageHash) + nsig;
182 size_t nActual;
183
184 // set up a pointer for convenience
185 const McciBootloader_SignatureBlock_t * const pSigBlock = (const void *)g_McciBootloader_imageBlock;
186
187 // append the imageHash
188 memcpy(
189 g_McciBootloader_imageBlock + sizeof(McciBootloader_SignatureBlock_t),
190 imageHash.bytes,
191 sizeof(imageHash.bytes)
192 );
193
194 // the TweetNaCl crypto_sign_open requires that output buffer
195 // have an allocation size that's equal to nsigned. We can
196 // conveniently do this in the block buffer.
197 mcci_tweetnacl_sha512_t *pSignedHash =
198 (void *)((uint8_t *)pSigBlock->signature.bytes + nsigned);
199
200 // result = non-zero for failure or zero for success.
201 volatile mcci_tweetnacl_result_t result;
202
203 // check the signature, which will update signedHash.
204 result = mcci_tweetnacl_sign_open(
205 /* output */ pSignedHash->bytes,
206 &nActual,
207 pSigBlock->signature.bytes,
208 nsigned,
209 pPublicKey
210 );
211
212 // constant time compares and checks.
213 // make sure the size is right.
214 result |= nActual ^ sizeof(pSignedHash->bytes);
215
216 // make sure the hashes match
217 result |= mcci_tweetnacl_verify_64(
218 imageHash.bytes,
219 pSignedHash->bytes
220 );
221
222 // Make sure the key in the image matches ours. It should but still...
223 result |= mcci_tweetnacl_verify_32(
224 pPublicKey->bytes,
225 pSigBlock->publicKey.bytes
226 );
227
228 // finally return the result.
229 return mcci_tweetnacl_result_is_success(result);
230 }
231
232/**** end of mccibootloader_checkstorageimage.c ****/
static bool McciBootloaderPlatform_storageRead(McciBootloaderStorageAddress_t hAddress, uint8_t *pBuffer, size_t nBuffer)
uint32_t McciBootloaderStorageAddress_t
Abstract type for storage byte addresses.
bool McciBootloader_checkStorageImage(McciBootloaderStorageAddress_t address, McciBootloader_AppInfo_t *pIncomingAppInfo, const mcci_tweetnacl_sign_publickey_t *pPublicKey)
uint8_t g_McciBootloader_imageBlock[4096]
const McciBootloader_AppInfo_t * McciBootloaderPlatform_checkImageValid(const void *pHeader, size_t nHeader, uintptr_t targetAddress, size_t targetSize)
const McciBootloader_AppInfo_t * McciBootloaderPlatform_getAppInfo(const void *pHeader, size_t nHeader)