-
Notifications
You must be signed in to change notification settings - Fork 27
/
ebox.h
365 lines (315 loc) · 13.2 KB
/
ebox.h
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
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright (c) 2018, Joyent Inc
* Author: Alex Wilson <[email protected]>
*/
#if !defined(_EBOX_H)
#define _EBOX_H
#include <stdint.h>
#include <assert.h>
#if defined(__APPLE__)
#include <PCSC/wintypes.h>
#include <PCSC/winscard.h>
#else
#include <wintypes.h>
#include <winscard.h>
#endif
#include <sys/types.h>
#include <sys/uio.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include "errf.h"
#include "piv.h"
#include "openssh/config.h"
#include "openssh/digest.h"
/*
* This file contains the API for dealing with ebox structures, as well as
* recovery challenge-response messages and ebox streams.
*
* For background on the ebox format and what it does, see the file
* docs/box-ebox-formats.adoc
*
* Eboxes protect some amount of key material, and give you multiple
* "configurations" which are alternative ways to obtain it. Configurations
* may either be PRIMARY (in which case unlocking a single piv_ecdh_box gives
* you the final key), or RECOVERY (in which case you have to unlock some N out
* of the M available).
*/
enum ebox_type {
EBOX_TEMPLATE = 0x01,
EBOX_KEY = 0x02,
EBOX_STREAM = 0x03
};
enum ebox_config_type {
EBOX_PRIMARY = 0x01,
EBOX_RECOVERY = 0x02
};
enum ebox_chaltype {
CHAL_RECOVERY = 1,
CHAL_VERIFY_AUDIT = 2,
};
struct ebox_tpl;
struct ebox_tpl_config;
struct ebox_tpl_part;
struct ebox;
struct ebox_config;
struct ebox_part;
struct ebox_challenge;
struct ebox_stream;
struct ebox_stream_chunk;
/*
* Ebox templates (ebox_tpl_*) store the metadata about possible configurations
* separately to an actual ebox, so that they can be kept and re-used for
* storing multiple keys.
*/
struct ebox_tpl *ebox_tpl_alloc(void);
void ebox_tpl_free(struct ebox_tpl *tpl);
uint ebox_tpl_version(const struct ebox_tpl *tpl);
/* Recursively clones the entire ebox_tpl, all configurations and parts. */
struct ebox_tpl *ebox_tpl_clone(const struct ebox_tpl *tpl);
void ebox_tpl_add_config(struct ebox_tpl *tpl, struct ebox_tpl_config *config);
void ebox_tpl_remove_config(struct ebox_tpl *tpl, struct ebox_tpl_config *config);
struct ebox_tpl_config *ebox_tpl_next_config(const struct ebox_tpl *tpl,
const struct ebox_tpl_config *prev);
struct ebox_tpl_config *ebox_tpl_config_alloc(enum ebox_config_type type);
void ebox_tpl_config_free(struct ebox_tpl_config *config);
uint ebox_tpl_config_n(const struct ebox_tpl_config *config);
enum ebox_config_type ebox_tpl_config_type(
const struct ebox_tpl_config *config);
errf_t *ebox_tpl_config_set_n(struct ebox_tpl_config *config, uint n);
void ebox_tpl_config_add_part(struct ebox_tpl_config *config,
struct ebox_tpl_part *part);
void ebox_tpl_config_remove_part(struct ebox_tpl_config *config,
struct ebox_tpl_part *part);
struct ebox_tpl_part *ebox_tpl_config_next_part(
const struct ebox_tpl_config *config, const struct ebox_tpl_part *prev);
struct ebox_tpl_part *ebox_tpl_part_alloc(const uint8_t *guid, size_t guidlen,
enum piv_slotid slot, struct sshkey *pubkey);
void ebox_tpl_part_free(struct ebox_tpl_part *part);
/* Read-only attributes of the part. */
const char *ebox_tpl_part_name(const struct ebox_tpl_part *part);
/*
* Note that these "struct sshkey *" pointers are owned by the ebox_tpl_part
* and should not be modified. They should be const but aren't because of
* some sshkey functions.
*/
struct sshkey *ebox_tpl_part_pubkey(const struct ebox_tpl_part *part);
struct sshkey *ebox_tpl_part_cak(const struct ebox_tpl_part *part);
const uint8_t *ebox_tpl_part_guid(const struct ebox_tpl_part *part);
enum piv_slotid ebox_tpl_part_slot(const struct ebox_tpl_part *part);
/* These both make a copy of their argument. */
void ebox_tpl_part_set_name(struct ebox_tpl_part *part, const char *name);
void ebox_tpl_part_set_cak(struct ebox_tpl_part *part, struct sshkey *cak);
/*
* These functions allow an opaque "private" data pointer to be stashed on
* a struct ebox_tpl_*, which can be freely used by client applications.
*/
void *ebox_tpl_private(const struct ebox_tpl *tpl);
void *ebox_tpl_alloc_private(struct ebox_tpl *tpl, size_t sz);
void ebox_tpl_config_free_private(struct ebox_tpl_config *config);
void *ebox_tpl_config_private(const struct ebox_tpl_config *config);
void *ebox_tpl_config_alloc_private(struct ebox_tpl_config *config, size_t sz);
void *ebox_tpl_part_private(const struct ebox_tpl_part *part);
void *ebox_tpl_part_alloc_private(struct ebox_tpl_part *part, size_t sz);
void ebox_tpl_part_free_private(struct ebox_tpl_part *part);
/* Serialise and de-serialise an ebox structure. */
MUST_CHECK
errf_t *sshbuf_get_ebox_tpl(struct sshbuf *buf, struct ebox_tpl **tpl);
MUST_CHECK
errf_t *sshbuf_put_ebox_tpl(struct sshbuf *buf, struct ebox_tpl *tpl);
/*
* Creates a new ebox based on a given template, sealing up the provided key
* and (optional) recovery token.
*/
MUST_CHECK
errf_t *ebox_create(const struct ebox_tpl *tpl, const uint8_t *key,
size_t keylen, const uint8_t *rtoken, size_t rtokenlen,
struct ebox **pebox);
void ebox_free(struct ebox *box);
uint ebox_version(const struct ebox *ebox);
enum ebox_type ebox_type(const struct ebox *ebox);
uint ebox_ephem_count(const struct ebox *ebox);
const struct sshkey *ebox_ephem_pubkey(const struct ebox *ebox, uint index);
size_t ebox_config_nonce_len(const struct ebox_config *config);
boolean_t ebox_is_unlocked(const struct ebox *box);
const char *ebox_cipher(const struct ebox *box);
const uint8_t *ebox_key(const struct ebox *box, size_t *len);
const uint8_t *ebox_recovery_token(const struct ebox *box, size_t *len);
/*
* Returns the template "shadow" of the ebox. This is an ebox_tpl that's
* owned by the struct ebox (so you must not free or modify it). It contains
* a complete copy of a template that would produce this ebox if given the
* same key (so it contains the same number of configs and parts and the
* parts have all the information on them that's in the ebox).
*
* The ebox_config_tpl and ebox_part_tpl() functions are conveniences that
* return the shadow of a particular ebox_config or ebox_part. For a lot of
* the information that you might want to know about an ebox_part, you will
* have to use the shadow template (e.g. the friendly name).
*/
struct ebox_tpl *ebox_tpl(const struct ebox *ebox);
struct ebox_tpl_config *ebox_config_tpl(const struct ebox_config *config);
struct ebox_tpl_part *ebox_part_tpl(const struct ebox_part *part);
struct ebox_config *ebox_next_config(const struct ebox *box,
const struct ebox_config *prev);
struct ebox_part *ebox_config_next_part(const struct ebox_config *config,
const struct ebox_part *prev);
/*
* Returns a pointer to the ebox part secret box.
*
* You can and should modify this box by unsealing it, but don't free it (it's
* part of the ebox_part). Functions like ebox_unlock() and ebox_recover()
* expect you to iterate over the parts in a config and use this method to
* retrieve the piv_ecdh_box and call piv_box_open().
*
* You don't need to call piv_box_take_data() though.
*/
struct piv_ecdh_box *ebox_part_box(const struct ebox_part *part);
/* Serialise/de-serialise an ebox */
MUST_CHECK
errf_t *sshbuf_get_ebox(struct sshbuf *buf, struct ebox **box);
MUST_CHECK
errf_t *sshbuf_put_ebox(struct sshbuf *buf, struct ebox *box);
/*
* Unlock an ebox using a primary config.
*
* One of the primary config's part boxes must have been already unsealed
* before calling this (see ebox_part_box() and piv_box_open()).
*
* Errors:
* - InsufficientParts: none of the part boxes were unsealed
*/
MUST_CHECK
errf_t *ebox_unlock(struct ebox *ebox, struct ebox_config *config);
/*
* Perform recovery on an ebox using a recovery config.
*
* N out of M of the parts on this config must have been processed with
* ebox_challenge_response() before calling this.
*
* Errors:
* - InsufficientParts: insufficient number of parts available on this config
* that are ready for recovery
* - AlreadyUnlocked: the ebox is already unlocked or recovered
* - RecoveryFailed: the recovery box data was invalid or corrupt
*/
MUST_CHECK
errf_t *ebox_recover(struct ebox *ebox, struct ebox_config *config);
/*
* These functions allow an opaque "private" data pointer to be stashed on
* a struct ebox_*, which can be freely used by client applications. This is
* particularly useful because of functions like ebox_challenge_response() which
* give you back a pointer to an ebox_part (so you can then transform that back
* into some application-specific information about the part).
*/
void *ebox_private(const struct ebox *ebox);
void *ebox_alloc_private(struct ebox *ebox, size_t sz);
void ebox_free_private(struct ebox *ebox);
void *ebox_config_private(const struct ebox_config *config);
void *ebox_config_alloc_private(struct ebox_config *config, size_t sz);
void ebox_config_free_private(struct ebox_config *config);
void *ebox_part_private(const struct ebox_part *part);
void *ebox_part_alloc_private(struct ebox_part *part, size_t sz);
void ebox_part_free_private(struct ebox_part *part);
/*
* Generate a challenge for a given recovery config + part.
*
* The challenge can then be serialised using sshbuf_put_ebox_challenge() and
* sent to the remote side. The "descfmt", ... arguments are given to vsnprintf
* to create the "description" field for the challenge (displayed on the
* remote end).
*
* Errors:
* - LengthError: description was too long for available space
*/
MUST_CHECK
errf_t *ebox_gen_challenge(struct ebox_config *config, struct ebox_part *part,
const char *descfmt, ...);
const struct ebox_challenge *ebox_part_challenge(const struct ebox_part *part);
void ebox_challenge_free(struct ebox_challenge *chal);
/*
* Serializes an ebox challenge inside a piv_ecdh_box as a one-step process.
*
* The data written in the buf is ready to be transported to a remote machine.
*/
MUST_CHECK
errf_t *sshbuf_put_ebox_challenge(struct sshbuf *buf,
const struct ebox_challenge *chal);
/*
* De-serializes an ebox challenge from inside a piv_ecdh_box. The piv_ecdh_box
* must be already unsealed.
*/
MUST_CHECK
errf_t *sshbuf_get_ebox_challenge(struct piv_ecdh_box *box,
struct ebox_challenge **chal);
enum ebox_chaltype ebox_challenge_type(const struct ebox_challenge *chal);
uint ebox_challenge_id(const struct ebox_challenge *chal);
const char *ebox_challenge_desc(const struct ebox_challenge *chal);
const char *ebox_challenge_hostname(const struct ebox_challenge *chal);
uint64_t ebox_challenge_ctime(const struct ebox_challenge *chal);
const uint8_t *ebox_challenge_words(const struct ebox_challenge *chal,
size_t *len);
struct sshkey *ebox_challenge_destkey(const struct ebox_challenge *chal);
/*
* Returns a pointer to the keybox within the ebox_challenge, in the same style
* as ebox_part_box().
*
* You'll need to call piv_box_open() on this before you can use
* sshbuf_put_ebox_challenge_response() to generate a response.
*/
struct piv_ecdh_box *ebox_challenge_box(const struct ebox_challenge *chal);
/*
* Generate and serialise a response to an ebox challenge inside a piv_ecdh_box
* as a one-step process. The keybox on chal must be already unsealed.
*
* The data written in the buf is ready to be transported to the original
* requesting machine.
*/
MUST_CHECK
errf_t *sshbuf_put_ebox_challenge_response(struct sshbuf *buf,
const struct ebox_challenge *chal);
/*
* Process an incoming response to a recovery challenge for the given config.
*
* *ppart is set to point at the part that this response was from. Takes
* ownership of respbox, and will free it.
*
* Errors:
* - EAGAIN: this challenge matched a part that is already unlocked
*/
MUST_CHECK
errf_t *ebox_challenge_response(struct ebox_config *config,
struct piv_ecdh_box *respbox, struct ebox_part **ppart);
MUST_CHECK
errf_t *sshbuf_get_ebox_stream(struct sshbuf *buf, struct ebox_stream **str);
MUST_CHECK
errf_t *sshbuf_put_ebox_stream(struct sshbuf *buf, struct ebox_stream *str);
MUST_CHECK
errf_t *sshbuf_get_ebox_stream_chunk(struct sshbuf *buf,
const struct ebox_stream *stream, struct ebox_stream_chunk **chunk);
MUST_CHECK
errf_t *sshbuf_put_ebox_stream_chunk(struct sshbuf *buf,
struct ebox_stream_chunk *chunk);
struct ebox *ebox_stream_ebox(const struct ebox_stream *str);
const char *ebox_stream_cipher(const struct ebox_stream *str);
const char *ebox_stream_mac(const struct ebox_stream *str);
size_t ebox_stream_chunk_size(const struct ebox_stream *str);
size_t ebox_stream_seek_offset(const struct ebox_stream *str, size_t offset);
MUST_CHECK
errf_t *ebox_stream_new(const struct ebox_tpl *tpl, struct ebox_stream **str);
MUST_CHECK
errf_t *ebox_stream_chunk_new(const struct ebox_stream *str, const void *data,
size_t size, size_t seqnr, struct ebox_stream_chunk **chunk);
MUST_CHECK
errf_t *ebox_stream_decrypt_chunk(struct ebox_stream_chunk *chunk);
MUST_CHECK
errf_t *ebox_stream_encrypt_chunk(struct ebox_stream_chunk *chunk);
const uint8_t *ebox_stream_chunk_data(const struct ebox_stream_chunk *chunk,
size_t *size);
struct sshbuf *ebox_stream_chunk_data_buf(const struct ebox_stream_chunk *chunk);
void ebox_stream_free(struct ebox_stream *str);
void ebox_stream_chunk_free(struct ebox_stream_chunk *chunk);
#endif