summaryrefslogtreecommitdiff
path: root/vfirmware/firmware_image_fw.c
blob: 5387d95b259df2136a5ad3427a66c22cc6391bdc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 *
 * Functions for verifying a verified boot firmware image.
 * (Firmware Portion)
 */

#include "firmware_image_fw.h"

#include "cryptolib.h"
#include "rollback_index.h"
#include "utility.h"

/* Macro to determine the size of a field structure in the FirmwareImage
 * structure. */
#define FIELD_LEN(field) (sizeof(((FirmwareImage*)0)->field))

char* kVerifyFirmwareErrors[VERIFY_FIRMWARE_MAX] = {
  "Success.",
  "Invalid Image.",
  "Root Key Signature Failed.",
  "Invalid Verification Algorithm.",
  "Preamble Signature Failed.",
  "Firmware Signature Failed.",
  "Wrong Firmware Magic.",
  "Invalid Firmware Header Checksum.",
  "Firmware Signing Key Rollback.",
  "Firmware Version Rollback."
};

int VerifyFirmwareHeader(const uint8_t* root_key_blob,
                         const uint8_t* header_blob,
                         int* algorithm,
                         int* header_len) {
  int firmware_sign_key_len;
  int root_key_len;
  uint16_t hlen, algo;
  uint8_t* header_checksum = NULL;

  /* Base Offset for the header_checksum field. Actual offset is
   * this + firmware_sign_key_len. */
  int base_header_checksum_offset = (FIELD_LEN(header_len) +
                                     FIELD_LEN(firmware_sign_algorithm) +
                                     FIELD_LEN(firmware_key_version));


  root_key_len = RSAProcessedKeySize(ROOT_SIGNATURE_ALGORITHM);
  Memcpy(&hlen, header_blob, sizeof(hlen));
  Memcpy(&algo,
         header_blob + FIELD_LEN(firmware_sign_algorithm),
         sizeof(algo));
  if (algo >= kNumAlgorithms)
    return VERIFY_FIRMWARE_INVALID_ALGORITHM;
  *algorithm = (int) algo;
  firmware_sign_key_len = RSAProcessedKeySize(*algorithm);

  /* Verify that header len is correct. */
  if (hlen != (base_header_checksum_offset +
               firmware_sign_key_len +
               FIELD_LEN(header_checksum)))
    return VERIFY_FIRMWARE_INVALID_IMAGE;

  *header_len = (int) hlen;

  /* Verify if the hash of the header is correct. */
  header_checksum = DigestBuf(header_blob,
                              *header_len - FIELD_LEN(header_checksum),
                              SHA512_DIGEST_ALGORITHM);
  if (SafeMemcmp(header_checksum,
                  header_blob + (base_header_checksum_offset +
                                 firmware_sign_key_len),
                  FIELD_LEN(header_checksum))) {
    Free(header_checksum);
    return VERIFY_FIRMWARE_WRONG_HEADER_CHECKSUM;
  }
  Free(header_checksum);

  /* Root key signature on the firmware signing key is always checked
   * irrespective of dev mode. */
  if (!RSAVerifyBinary_f(root_key_blob, NULL,  /* Key to use */
                         header_blob,  /* Data to verify */
                         *header_len, /* Length of data */
                         header_blob + *header_len,  /* Expected Signature */
                         ROOT_SIGNATURE_ALGORITHM))
    return VERIFY_FIRMWARE_ROOT_SIGNATURE_FAILED;
  return 0;
}

int VerifyFirmwarePreamble(RSAPublicKey* firmware_sign_key,
                           const uint8_t* preamble_blob,
                           int algorithm,
                           uint64_t* firmware_len) {
  uint64_t len;
  int preamble_len;
  uint16_t firmware_version;

  Memcpy(&firmware_version, preamble_blob, sizeof(firmware_version));

  preamble_len = (FIELD_LEN(firmware_version) +
                  FIELD_LEN(firmware_len) +
                  FIELD_LEN(preamble));
  if (!RSAVerifyBinary_f(NULL, firmware_sign_key,  /* Key to use */
                         preamble_blob,  /* Data to verify */
                         preamble_len,  /* Length of data */
                         preamble_blob + preamble_len,  /* Expected Signature */
                         algorithm))
    return VERIFY_FIRMWARE_PREAMBLE_SIGNATURE_FAILED;

  Memcpy(&len, preamble_blob + FIELD_LEN(firmware_version),
         sizeof(len));
  *firmware_len = len;
  return 0;
}

int VerifyFirmwareData(RSAPublicKey* firmware_sign_key,
                       const uint8_t* preamble_start,
                       const uint8_t* firmware_data_start,
                       uint64_t firmware_len,
                       int algorithm) {
  int signature_len = siglen_map[algorithm];
  uint8_t* digest;
  DigestContext ctx;

  /* Since the firmware signature is over the preamble and the firmware data,
   * which does not form a contiguous region of memory, we calculate the
   * message digest ourselves. */
  DigestInit(&ctx, algorithm);
  DigestUpdate(&ctx, preamble_start,
               (FIELD_LEN(firmware_version) +
                FIELD_LEN(firmware_len) +
                FIELD_LEN(preamble)));
  DigestUpdate(&ctx, firmware_data_start + signature_len, firmware_len);
  digest = DigestFinal(&ctx);
  if (!RSAVerifyBinaryWithDigest_f(
          NULL, firmware_sign_key,  /* Key to use. */
          digest,  /* Digest of the data to verify. */
          firmware_data_start,  /* Expected Signature */
          algorithm)) {
    Free(digest);
    return VERIFY_FIRMWARE_SIGNATURE_FAILED;
  }
  Free(digest);
  return 0;
}

int VerifyFirmware(const uint8_t* root_key_blob,
                   const uint8_t* firmware_blob) {
  int error_code = 0;
  int algorithm;  /* Signing key algorithm. */
  RSAPublicKey* firmware_sign_key = NULL;
  int firmware_sign_key_len, signature_len, header_len;
  uint64_t firmware_len;
  const uint8_t* header_ptr = NULL;  /* Pointer to header. */
  const uint8_t* firmware_sign_key_ptr = NULL;  /* Pointer to signing key. */
  const uint8_t* preamble_ptr = NULL;  /* Pointer to preamble block. */
  const uint8_t* firmware_ptr = NULL;  /* Pointer to firmware signature/data. */

  /* Note: All the offset calculations are based on struct FirmwareImage which
   * is defined in include/firmware_image.h. */

  /* Compare magic bytes. */
  if (SafeMemcmp(firmware_blob, FIRMWARE_MAGIC, FIRMWARE_MAGIC_SIZE))
    return VERIFY_FIRMWARE_WRONG_MAGIC;
  header_ptr = firmware_blob + FIRMWARE_MAGIC_SIZE;

  /* Only continue if header verification succeeds. */
  if ((error_code = VerifyFirmwareHeader(root_key_blob, header_ptr,
                                         &algorithm, &header_len)))
    return error_code;  /* AKA jump to revovery. */

  /* Parse signing key into RSAPublicKey structure since it is required multiple
   * times. */
  firmware_sign_key_len = RSAProcessedKeySize(algorithm);
  firmware_sign_key_ptr = header_ptr + (FIELD_LEN(header_len) +
                                        FIELD_LEN(firmware_sign_algorithm) +
                                        FIELD_LEN(firmware_key_version));
  firmware_sign_key = RSAPublicKeyFromBuf(firmware_sign_key_ptr,
                                          firmware_sign_key_len);
  signature_len = siglen_map[algorithm];

  /* Only continue if preamble verification succeeds. */
  preamble_ptr = (header_ptr + header_len +
                  FIELD_LEN(firmware_key_signature));
  if ((error_code = VerifyFirmwarePreamble(firmware_sign_key, preamble_ptr,
                                           algorithm,
                                           &firmware_len))) {
    RSAPublicKeyFree(firmware_sign_key);
    debug("Couldn't verify Firmware preamble.\n");
    return error_code;  /* AKA jump to recovery. */
  }
  /* Only continue if firmware data verification succeeds. */
  firmware_ptr = (preamble_ptr +
                  (FIELD_LEN(firmware_version) +  /* Skip the preamble. */
                   FIELD_LEN(firmware_len) +
                   FIELD_LEN(preamble)) +
                  signature_len);

  if ((error_code = VerifyFirmwareData(firmware_sign_key, preamble_ptr,
                                       firmware_ptr,
                                       firmware_len,
                                       algorithm))) {
    RSAPublicKeyFree(firmware_sign_key);
    debug("Couldn't verify Firmware data.\n");
    return error_code;  /* AKA jump to recovery. */
  }

  RSAPublicKeyFree(firmware_sign_key);
  return 0;  /* Success! */
}

uint32_t GetLogicalFirmwareVersion(uint8_t* firmware_blob) {
  uint16_t firmware_key_version;
  uint16_t firmware_version;
  uint16_t firmware_sign_algorithm;
  int firmware_sign_key_len;
  Memcpy(&firmware_sign_algorithm,
         firmware_blob + (FIELD_LEN(magic) +  /* Offset to field. */
                          FIELD_LEN(header_len)),
         sizeof(firmware_sign_algorithm));
  Memcpy(&firmware_key_version,
         firmware_blob + (FIELD_LEN(magic) +  /* Offset to field. */
                          FIELD_LEN(header_len) +
                          FIELD_LEN(firmware_sign_algorithm)),
         sizeof(firmware_key_version));
  if (firmware_sign_algorithm >= kNumAlgorithms)
    return 0;
  firmware_sign_key_len = RSAProcessedKeySize(firmware_sign_algorithm);
  Memcpy(&firmware_version,
         firmware_blob +  (FIELD_LEN(magic) +  /* Offset to field. */
                           FIELD_LEN(header_len) +
                           FIELD_LEN(firmware_key_version) +
                           firmware_sign_key_len +
                           FIELD_LEN(header_checksum) +
                           FIELD_LEN(firmware_key_signature)),
         sizeof(firmware_version));
  return CombineUint16Pair(firmware_key_version, firmware_version);
}

int VerifyFirmwareDriver_f(uint8_t* root_key_blob,
                           uint8_t* firmwareA,
                           uint8_t* firmwareB) {
  /* Contains the logical firmware version (32-bit) which is calculated as
   * (firmware_key_version << 16 | firmware_version) where
   * [firmware_key_version] [firmware_version] are both 16-bit.
   */
  uint32_t firmwareA_lversion, firmwareB_lversion;
  uint8_t firmwareA_is_verified = 0;  /* Whether firmwareA verify succeeded. */
  uint32_t min_lversion;  /* Minimum of firmware A and firmware lversion. */
  uint32_t stored_lversion;  /* Stored logical version in the TPM. */

  /* Initialize the TPM since we'll be reading the rollback indices. */
  SetupTPM();

  /* We get the key versions by reading directly from the image blobs without
   * any additional (expensive) sanity checking on the blob since it's faster to
   * outright reject a firmware with an older firmware key version. A malformed
   * or corrupted firmware blob will still fail when VerifyFirmware() is called
   * on it.
   */
  firmwareA_lversion = GetLogicalFirmwareVersion(firmwareA);
  firmwareB_lversion = GetLogicalFirmwareVersion(firmwareB);
  min_lversion  = Min(firmwareA_lversion, firmwareB_lversion);
  stored_lversion = CombineUint16Pair(GetStoredVersion(FIRMWARE_KEY_VERSION),
                                      GetStoredVersion(FIRMWARE_VERSION));
  /* Always try FirmwareA first. */
  if (VERIFY_FIRMWARE_SUCCESS == VerifyFirmware(root_key_blob, firmwareA))
    firmwareA_is_verified = 1;
  if (firmwareA_is_verified && (stored_lversion < firmwareA_lversion)) {
    /* Stored version may need to be updated but only if FirmwareB
     * is successfully verified and has a logical version greater than
     * the stored logical version. */
    if (stored_lversion < firmwareB_lversion) {
      if (VERIFY_FIRMWARE_SUCCESS == VerifyFirmware(root_key_blob, firmwareB)) {
        WriteStoredVersion(FIRMWARE_KEY_VERSION,
                           (uint16_t) (min_lversion >> 16));
        WriteStoredVersion(FIRMWARE_VERSION,
                           (uint16_t) (min_lversion & 0x00FFFF));
        stored_lversion = min_lversion;  /* Update stored version as it's used
                                          * later. */
      }
    }
  }
  /* Lock Firmware TPM rollback indices from further writes. */
  /* TODO(gauravsh): Figure out if these can be combined into one
   * 32-bit location since we seem to always use them together. This can help
   * us minimize the number of NVRAM writes/locks (which are limited over flash
   * memory lifetimes.
   */
  LockStoredVersion(FIRMWARE_KEY_VERSION);
  LockStoredVersion(FIRMWARE_VERSION);

  /* Determine which firmware (if any) to jump to.
   *
   * We always attempt to jump to FirmwareA first. If verification of FirmwareA
   * fails, we try FirmwareB. In all cases, if the firmware successfully
   * verified but is a rollback, we jump to recovery.
   *
   * Note: This means that if FirmwareA verified successfully and is a
   * rollback, then no attempt is made to check FirmwareB. We still jump to
   * recovery. FirmwareB is only used as a backup in case FirmwareA gets
   * corrupted. Since newer firmware updates are always written to A,
   * the case where firmware A is verified but a rollback should not occur in
   * normal operation.
   */
  if (firmwareA_is_verified) {
    if (stored_lversion <= firmwareA_lversion)
      return BOOT_FIRMWARE_A_CONTINUE;
  } else {
    /* If FirmwareA was not valid, then we skipped over the
     * check to update the rollback indices and a Verify of FirmwareB wasn't
     * attempted.
     * If FirmwareB is not a rollback, then we attempt to do the verification.
     */
    if (stored_lversion <= firmwareB_lversion &&
        (VERIFY_FIRMWARE_SUCCESS == VerifyFirmware(root_key_blob, firmwareB)))
        return BOOT_FIRMWARE_B_CONTINUE;
  }
  /* D'oh: No bootable firmware. */
  return BOOT_FIRMWARE_RECOVERY_CONTINUE;
}