forked from Foundation-Devices/passport2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathse-atecc608a.c
235 lines (191 loc) · 5.83 KB
/
se-atecc608a.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
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
// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. <[email protected]>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// 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.
*
* SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. <[email protected]>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "stm32h7xx_hal.h"
#include "stm32h7xx_hal_uart.h"
#include "stm32h7xx_hal_uart_ex.h"
#include "pprng.h"
#include "se-config.h"
#include "se.h"
#include "secrets.h"
#include "sha256.h"
#include "utils.h"
#include "se-atecc608a.h"
// Selectable debug level; keep them as comments regardless
#if 0
// break on any error: not helpful since some are normal
#define ERR(msg) BREAKPOINT;
#define ERRV(val, msg) BREAKPOINT;
#else
#define ERR(msg)
#define ERRV(val, msg)
#endif
// keep this in place.
#define RET_IF_BAD(rv) \
do { \
if (rv) return rv; \
} while (0)
bool se_probe() {
int chk;
se_sleep();
se_wake();
// Expect 0x11
chk = se_read1();
if (chk != SE_AFTER_WAKE) return false;
se_sleep();
return true;
}
// Do Info(p1=2) command, and return result.
//
uint16_t se_get_info(void) {
int rc;
// not doing error checking here
se_write(OP_Info, 0x2, 0, NULL, 0);
// note: always returns 4 bytes, but most are garbage and unused.
uint8_t tmp[4];
rc = se_read(tmp, 4);
se_sleep();
if (rc < 0) return -1;
return (tmp[0] << 8) | tmp[1];
}
// Load Tempkey with a specific value. Resulting Tempkey cannot be
// used with many commands/keys, but is needed for signing.
//
int se_load_nonce(uint8_t* nonce) {
uint8_t rc;
// p1=3
se_write(OP_Nonce, 3, 0, nonce, 32); // 608a ok
rc = se_read1();
se_sleep();
if (rc != 0) return -1;
return 0;
}
// Sign a message (already digested)
//
int se_sign(uint8_t keynum, uint8_t msg_hash[32], uint8_t signature[64]) {
int rc;
rc = se_load_nonce(msg_hash);
if (rc < 0) return -1;
se_write(OP_Sign, 0x80, keynum, NULL, 0);
rc = se_read(signature, 64);
se_sleep();
if (rc < 0) return -1;
return 0;
}
// Use old SHA256 command from 508A, but with new flags.
//
int se_hmac32(uint8_t keynum, uint8_t msg[32], uint8_t digest[32]) {
int rc;
// Start SHA w/ HMAC setup
se_write(OP_SHA, 4, keynum, NULL, 0); // 4 = HMAC_Init
rc = se_read1();
if (rc != 0) return -1;
// send the contents to be hashed
se_write(OP_SHA, (3 << 6) | 2, 32, msg, 32); // 2 = Finalize, 3=Place output
rc = se_read(digest, 32);
se_sleep();
return rc;
}
// Return the serial number: it's 9 bytes, altho 3 are fixed.
//
int se_get_serial(uint8_t serial[6]) {
int rc;
uint8_t temp[32];
se_write(OP_Read, 0x80, 0x0, NULL, 0);
rc = se_read(temp, 32);
se_sleep();
if (rc < 0) return -1;
// reformat to 9 bytes.
uint8_t ts[9];
memcpy(ts, &temp[0], 4);
memcpy(&ts[4], &temp[8], 5);
// check the hard-coded values
if ((ts[0] != 0x01) || (ts[1] != 0x23) || (ts[8] != 0xEE)) return 1;
// save only the unique bits.
memcpy(serial, ts + 2, 6);
return 0;
}
int se_destroy_key(int keynum) {
int rc;
uint8_t numin[20];
// Load tempkey with a known (random) nonce value
rng_buffer(numin, sizeof(numin));
se_write(OP_Nonce, 0, 0, numin, 20);
// Nonce command returns the RNG result, not contents of TempKey,
// but since we are destroying, no need to calculate what it is.
uint8_t randout[32];
rc = se_read(randout, 32);
if (rc < 0) return -1;
// do a "DeriveKey" operation, based on that!
se_write(OP_DeriveKey, 0x00, keynum, NULL, 0);
rc = se_read1();
se_sleep();
if (rc != 0) return -1;
return 0;
}
// Do on-chip hashing, with lots of iterations.
//
// - using HMAC-SHA256 with keys that are known only to the 608a.
// - rate limiting factor here is communication time w/ 608a, not algos.
// - caution: result here is not confidential
// - cost of each iteration, approximately: 8ms
// - but our time to do each iteration is limited by software SHA256 in se_pair_unlock
//
int se_stretch_iter(const uint8_t* start, uint8_t* end, int iterations) {
if (start == end) {
return -1;
}
memcpy(end, start, 32);
for (int i = 0; i < iterations; i++) {
// must unlock again, because pin_stretch is an auth'd key
if (se_pair_unlock()) return -2;
int rv = se_hmac32(KEYNUM_pin_stretch, end, end);
if (rv < 0) return -1;
LV_REFRESH();
}
return 0;
}
// Apply HMAC using secret in chip as a HMAC key, then encrypt
// the result a little because read in clear over bus.
//
int se_mixin_key(uint8_t keynum, uint8_t* start, uint8_t* end) {
int rc;
if (start == end) {
return -1;
}
rc = se_pair_unlock();
if (rc < 0) return -1;
if (keynum != 0) {
rc = se_hmac32(keynum, start, end);
if (rc < 0) return -1;
} else {
memset(end, 0, 32);
}
// Final value was just read over bus w/o any protection, but
// we won't be using that, instead, mix in the pairing secret.
//
// Concern: what if mitm gave us some zeros or other known pattern here. We will
// use the value provided in cleartext[sic--it's not] write back shortly (to test it).
// Solution: one more SHA256, and to be safe, mixin lots of values!
SHA256_CTX ctx;
sha256_init(&ctx);
sha256_update(&ctx, rom_secrets->pairing_secret, 32);
sha256_update(&ctx, start, 32);
sha256_update(&ctx, &keynum, 1);
sha256_update(&ctx, end, 32);
sha256_final(&ctx, end);
return 0;
}