-
Notifications
You must be signed in to change notification settings - Fork 17
/
verify.c
132 lines (111 loc) · 3.45 KB
/
verify.c
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
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-License-Identifier: GPL-3.0-only
//
/*
* (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard <coldcardwallet.com>
* and is covered by GPLv3 license found in COPYING.
*
* verify.c -- Check signatures on firmware images in flash.
*
*/
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "delay.h"
#include "firmware-keys.h"
#include "hash.h"
#include "se.h"
#include "se-config.h"
#include "sha256.h"
#include "uECC.h"
#include "utils.h"
#include "se-atecc608a.h"
#include "verify.h"
secresult verify_header(passport_firmware_header_t *hdr)
{
if (hdr->info.magic != FW_HEADER_MAGIC) goto fail;
if (hdr->info.timestamp == 0) goto fail;
if (hdr->info.fwversion[0] == 0x0) goto fail;
if (hdr->info.fwlength < FW_HEADER_SIZE) goto fail;
#ifdef USE_CRYPTO
// if (hdr->signature.pubkey1 == 0) goto fail;
if ((hdr->signature.pubkey1 != FW_USER_KEY) && (hdr->signature.pubkey1 > FW_MAX_PUB_KEYS)) goto fail;
if (hdr->signature.pubkey1 != FW_USER_KEY)
{
// if (hdr->signature.pubkey2 == 0) goto fail;
if (hdr->signature.pubkey2 > FW_MAX_PUB_KEYS) goto fail;
}
#endif /* USE_CRYPTO */
return SEC_TRUE;
fail:
return SEC_FALSE;
}
secresult verify_signature(
passport_firmware_header_t *hdr,
uint8_t *fw_hash,
uint32_t hashlen
)
{
#ifdef USE_CRYPTO
int rc;
if (hdr->signature.pubkey1 == FW_USER_KEY)
{
uint8_t user_public_key[72] = {0};
/*
* It looks like the user signed this firmware so, in order to
* validate, we need to get the public key from the SE.
*/
se_pair_unlock();
rc = se_read_data_slot(KEYNUM_user_fw_pubkey, user_public_key, sizeof(user_public_key));
if (rc < 0)
return SEC_FALSE;
rc = uECC_verify(user_public_key,
fw_hash, hashlen,
hdr->signature.signature1, uECC_secp256k1());
if (rc == 0)
return SEC_FALSE;
}
else
{
rc = uECC_verify(approved_pubkeys[hdr->signature.pubkey1],
fw_hash, hashlen,
hdr->signature.signature1, uECC_secp256k1());
if (rc == 0)
return SEC_FALSE;
rc = uECC_verify(approved_pubkeys[hdr->signature.pubkey2],
fw_hash, hashlen,
hdr->signature.signature2, uECC_secp256k1());
if (rc == 0)
return SEC_FALSE;
}
return SEC_TRUE;
#else
return SEC_TRUE;
#endif /* USE_CRYPTO */
}
secresult verify_current_firmware(
bool process_led
)
{
uint8_t fw_hash[HASH_LEN];
passport_firmware_header_t *fwhdr = (passport_firmware_header_t *)FW_HDR;
uint8_t *fwptr = (uint8_t *)fwhdr + FW_HEADER_SIZE;
if (!verify_header(fwhdr))
return ERR_INVALID_FIRMWARE_HEADER;
hash_fw(&fwhdr->info, fwptr, fwhdr->info.fwlength, fw_hash, sizeof(fw_hash));
if (verify_signature(fwhdr, fw_hash, sizeof(fw_hash)) == SEC_FALSE)
return ERR_INVALID_FIRMWARE_SIGNATURE;
#ifdef PRODUCTION_BUILD
if (process_led)
{
int rc;
uint8_t board_hash[HASH_LEN];
hash_board(fw_hash, sizeof(fw_hash), board_hash, sizeof(board_hash));
rc = se_set_gpio_secure(board_hash);
if (rc < 0)
return ERR_UNABLE_TO_UPDATE_FIRMWARE_HASH_IN_SE;
}
#endif /* PRODUCTION_BUILD */
return SEC_TRUE;
}
// EOF