Line data Source code
1 : /**
2 : * The MIT License (MIT)
3 : *
4 : * Copyright (c) 2021 RSK Labs Ltd
5 : *
6 : * Permission is hereby granted, free of charge, to any person obtaining a copy
7 : * of this software and associated documentation files (the "Software"), to
8 : * deal in the Software without restriction, including without limitation the
9 : * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 : * sell copies of the Software, and to permit persons to whom the Software is
11 : * furnished to do so, subject to the following conditions:
12 : *
13 : * The above copyright notice and this permission notice shall be included in
14 : * all copies or substantial portions of the Software.
15 : *
16 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 : * IN THE SOFTWARE.
23 : */
24 :
25 : #include <stdio.h>
26 : #include <string.h>
27 : #include <stdint.h>
28 : #include <secp256k1.h>
29 : #include <openenclave/enclave.h>
30 :
31 : #include "hal/hash.h"
32 : #include "hal/seed.h"
33 : #include "hal/constants.h"
34 : #include "hal/log.h"
35 :
36 : #include "secret_store.h"
37 : #include "bip32.h"
38 : #include "random.h"
39 :
40 : #define SEST_SEED_KEY "seed"
41 :
42 : // Globals
43 : static bool G_seed_available;
44 : static uint8_t G_seed[SEED_LENGTH];
45 :
46 : static secp256k1_context* sp_ctx = NULL;
47 :
48 26 : bool seed_init() {
49 : // Init the secp256k1 context
50 26 : if (!sp_ctx)
51 1 : sp_ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
52 :
53 26 : memset(G_seed, 0, sizeof(G_seed));
54 26 : G_seed_available = false;
55 :
56 26 : if (!sest_exists(SEST_SEED_KEY)) {
57 : // Module is in a wiped state
58 11 : return true;
59 : }
60 :
61 : // Read seed
62 15 : uint8_t seed_length = 0;
63 15 : if (!(seed_length = sest_read(SEST_SEED_KEY, G_seed, sizeof(G_seed)))) {
64 : LOG("Could not load the current seed\n");
65 1 : return false;
66 : }
67 :
68 : // Make sure seed is sound
69 14 : if (seed_length != sizeof(G_seed)) {
70 : LOG("Detected invalid seed\n");
71 1 : return false;
72 : }
73 :
74 13 : G_seed_available = true;
75 : LOG("Seed loaded\n");
76 :
77 13 : return true;
78 : }
79 :
80 2 : bool seed_wipe() {
81 2 : bool success = sest_remove(SEST_SEED_KEY);
82 2 : memset(G_seed, 0, sizeof(G_seed));
83 2 : G_seed_available = false;
84 :
85 2 : return success;
86 : }
87 :
88 5 : bool seed_generate(uint8_t* client_seed, uint8_t client_seed_size) {
89 5 : if (G_seed_available) {
90 : LOG("Seed already exists\n");
91 1 : return false;
92 : }
93 :
94 4 : if (client_seed_size != SEED_LENGTH) {
95 : LOG("Invalid client seed size\n");
96 1 : return false;
97 : }
98 :
99 : uint8_t random_bytes[SEED_LENGTH];
100 3 : if (!random_getrandom(random_bytes, sizeof(random_bytes))) {
101 : LOG("Error generating random seed\n");
102 1 : return false;
103 : }
104 :
105 66 : for (size_t i = 0; i < SEED_LENGTH; i++) {
106 64 : G_seed[i] = random_bytes[i] ^ client_seed[i];
107 : }
108 :
109 2 : if (!sest_write(SEST_SEED_KEY, G_seed, SEED_LENGTH)) {
110 : LOG("Error persisting generated seed\n");
111 1 : memset(G_seed, 0, sizeof(G_seed));
112 1 : return false;
113 : }
114 :
115 1 : G_seed_available = true;
116 1 : printf("Seed generated\n");
117 1 : return true;
118 : }
119 :
120 6 : static bool derive_privkey(uint32_t* path,
121 : uint8_t path_length,
122 : uint8_t* privkey_out,
123 : size_t privkey_out_size) {
124 6 : if (!bip32_derive_private(privkey_out,
125 : privkey_out_size,
126 : G_seed,
127 : sizeof(G_seed),
128 : path,
129 : path_length)) {
130 2 : return false;
131 : }
132 :
133 4 : return true;
134 : }
135 :
136 38 : bool seed_available() {
137 38 : return G_seed_available;
138 : }
139 :
140 4 : bool seed_derive_pubkey(uint32_t* path,
141 : uint8_t path_length,
142 : uint8_t* pubkey_out,
143 : uint8_t* pubkey_out_length) {
144 : secp256k1_pubkey sp_pubkey;
145 : uint8_t derived_privkey[PRIVATE_KEY_LENGTH];
146 :
147 : LOG("Deriving public key for path...\n");
148 :
149 : // Derive the private key
150 4 : if (!derive_privkey(
151 : path, path_length, derived_privkey, sizeof(derived_privkey))) {
152 : LOG("Error deriving private key for public key gathering\n");
153 1 : return false;
154 : }
155 :
156 : // Derive the public key and serialize it uncompressed
157 3 : if (!secp256k1_ec_pubkey_create(sp_ctx, &sp_pubkey, derived_privkey)) {
158 : LOG("Error deriving public key\n");
159 1 : return false;
160 : }
161 :
162 2 : if (*pubkey_out_length < PUBKEY_UNCMP_LENGTH) {
163 : LOG("Overflow while deriving public key\n");
164 1 : return false;
165 : }
166 1 : size_t temp_length = *pubkey_out_length;
167 1 : secp256k1_ec_pubkey_serialize(sp_ctx,
168 : pubkey_out,
169 : &temp_length,
170 : &sp_pubkey,
171 : SECP256K1_EC_UNCOMPRESSED);
172 :
173 1 : if (temp_length != PUBKEY_UNCMP_LENGTH) {
174 : LOG("Unexpected error while deriving public key\n");
175 0 : return false;
176 : }
177 1 : *pubkey_out_length = (uint8_t)temp_length;
178 :
179 : LOG_HEX("Pubkey for path is:", pubkey_out, *pubkey_out_length);
180 :
181 1 : return true;
182 : }
183 :
184 3 : bool seed_sign(uint32_t* path,
185 : uint8_t path_length,
186 : uint8_t* hash32,
187 : uint8_t* sig_out,
188 : uint8_t* sig_out_length) {
189 : secp256k1_ecdsa_signature sp_sig;
190 : uint8_t derived_privkey[PRIVATE_KEY_LENGTH];
191 :
192 3 : if (*sig_out_length < MAX_SIGNATURE_LENGTH) {
193 : LOG("Overflow while signing\n");
194 1 : return false;
195 : }
196 :
197 : LOG_HEX("Signing hash:", hash32, HASH_LENGTH);
198 :
199 : // Derive the private key
200 2 : if (!derive_privkey(
201 : path, path_length, derived_privkey, sizeof(derived_privkey))) {
202 : LOG("Error deriving private key for signing\n");
203 1 : return false;
204 : }
205 :
206 : // Sign and serialize as DER
207 1 : secp256k1_ecdsa_sign(sp_ctx, &sp_sig, hash32, derived_privkey, NULL, NULL);
208 1 : size_t temp_length = *sig_out_length;
209 1 : secp256k1_ecdsa_signature_serialize_der(
210 : sp_ctx, sig_out, &temp_length, &sp_sig);
211 1 : if (temp_length > MAX_SIGNATURE_LENGTH) {
212 : LOG("Overflow while signing\n");
213 0 : return false;
214 : }
215 1 : *sig_out_length = (uint8_t)temp_length;
216 :
217 : LOG_HEX("Signature is: ", sig_out, *sig_out_length);
218 :
219 1 : return true;
220 : }
221 :
222 4 : bool seed_output_USE_FROM_EXPORT_ONLY(uint8_t* out, size_t* out_size) {
223 : // We need a seed
224 4 : if (!G_seed_available) {
225 : LOG("Seed: no seed available to output\n");
226 1 : return false;
227 : }
228 :
229 : // Output buffer validations
230 3 : if (*out_size < sizeof(G_seed)) {
231 : LOG("Seed: output buffer to small to write seed\n");
232 1 : return false;
233 : }
234 2 : if (!oe_is_within_enclave(out, *out_size)) {
235 : LOG("Seed: output buffer not strictly within the enclave\n");
236 1 : return false;
237 : }
238 :
239 : // Write seed
240 1 : memcpy(out, G_seed, sizeof(G_seed));
241 1 : *out_size = sizeof(G_seed);
242 1 : return true;
243 : }
244 :
245 5 : bool seed_set_USE_FROM_EXPORT_ONLY(uint8_t* in, size_t in_size) {
246 : // We need no seed
247 5 : if (G_seed_available) {
248 : LOG("Seed: already set\n");
249 1 : return false;
250 : }
251 :
252 : // Input buffer validations
253 4 : if (in_size < sizeof(G_seed)) {
254 : LOG("Seed: input buffer too small to set seed\n");
255 1 : return false;
256 : }
257 3 : if (!oe_is_within_enclave(in, in_size)) {
258 : LOG("Seed: input buffer not strictly within the enclave\n");
259 1 : return false;
260 : }
261 :
262 : // Set seed
263 2 : G_seed_available = false;
264 2 : memcpy(G_seed, in, sizeof(G_seed));
265 2 : if (!sest_write(SEST_SEED_KEY, G_seed, SEED_LENGTH)) {
266 : LOG("Seed: error persisting given seed\n");
267 1 : memset(G_seed, 0, sizeof(G_seed));
268 1 : return false;
269 : }
270 :
271 1 : G_seed_available = true;
272 : LOG("Seed set\n");
273 1 : return true;
274 : }
|