summaryrefslogtreecommitdiff
path: root/include/u2f.h
blob: 6e7c3e5d5e20db7062277d53cf71656280ee5e75 (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
322
323
324
325
326
327
328
329
330
331
332
// Common U2F raw message format header - Review Draft
// 2014-10-08
// Editor: Jakob Ehrensvard, Yubico, jakob@yubico.com

#ifndef __U2F_H_INCLUDED__
#define __U2F_H_INCLUDED__

/**
 * Note: This header file should be self-sufficient as it is shared
 * with other boards and with userland daemons (u2fd).
 *
 * chromeos-ec-headers package installs it in ChromeOS development environment.
 *
 */

#ifdef _MSC_VER /* Windows */
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long int uint64_t;
#else
#include <stdint.h>
#endif

#ifdef __cplusplus
extern "C" {
#endif

/* General constants */

#define U2F_EC_KEY_SIZE	      32 /* EC key size in bytes, NIST P-256 Curve */
#define U2F_EC_POINT_SIZE     ((U2F_EC_KEY_SIZE * 2) + 1) /* Size of EC point */
#define U2F_MAX_KH_SIZE	      128 /* Max size of key handle */
#define U2F_MAX_ATT_CERT_SIZE 2048 /* Max size of attestation certificate */
#define U2F_MAX_EC_SIG_SIZE   72 /* Max size of DER coded EC signature */
#define U2F_CTR_SIZE	      4 /* Size of counter field */
#define U2F_APPID_SIZE	      32 /* Size of application id */
#define U2F_CHAL_SIZE	      32 /* Size of challenge */
#define U2F_MAX_ATTEST_SIZE   256 /* Size of largest blob to sign */
#define U2F_P256_SIZE	      32
/* Origin seed is a random nonce generated during key handle creation. */
#define U2F_ORIGIN_SEED_SIZE 32
#define U2F_USER_SECRET_SIZE 32 /* Size of user secret */

#define U2F_AUTH_TIME_SECRET_SIZE 32

#define SHA256_DIGEST_SIZE	32
#define U2F_MESSAGE_DIGEST_SIZE SHA256_DIGEST_SIZE

#define CORP_CHAL_SIZE 16
#define CORP_SALT_SIZE 16

#define ENC_SIZE(x) ((x + 7) & 0xfff8)

/* EC (uncompressed) point */

#define U2F_POINT_UNCOMPRESSED 0x04 /* Uncompressed point format */

struct u2f_ec_point {
	uint8_t pointFormat; /* Point type */
	uint8_t x[U2F_EC_KEY_SIZE]; /* X-value */
	uint8_t y[U2F_EC_KEY_SIZE]; /* Y-value */
};

/* Request Flags. */

#define U2F_AUTH_ENFORCE    0x03 /* Enforce user presence and sign */
#define U2F_AUTH_CHECK_ONLY 0x07 /* Check only */
#define U2F_AUTH_FLAG_TUP   0x01 /* Test of user presence set */
/* The key handle can be used with fingerprint or PIN. */
#define U2F_UV_ENABLED_KH 0x08

/* Request v2 key handle. Should be used with U2F_UV_ENABLED_KH */
#define U2F_V2_KH      0x10
#define U2F_V2_KH_MASK (U2F_V2_KH | U2F_UV_ENABLED_KH)

#define U2F_KH_VERSION_1 0x01
#define U2F_KH_VERSION_2 0x02

#define U2F_AUTHORIZATION_SALT_SIZE 16
#define U2F_V0_KH_SIZE		    64

/**
 * Key handle version = 1 for WebAuthn, bound to device and user.
 */
#define U2F_V1_KH_SIZE 113

/* Header is composed of version || origin_seed || kh_hmac */
#define U2F_V1_KH_HEADER_SIZE (U2F_ORIGIN_SEED_SIZE + SHA256_DIGEST_SIZE + 1)

/**
 * Key handle version = 2 for WebAuthn, bound to device and user.
 */
#define U2F_V2_KH_SIZE 81

/* Header is composed of version || origin_seed */
#define U2F_V2_KH_HEADER_SIZE (U2F_ORIGIN_SEED_SIZE + 1)

struct u2f_signature {
	uint8_t sig_r[U2F_EC_KEY_SIZE]; /* Signature */
	uint8_t sig_s[U2F_EC_KEY_SIZE]; /* Signature */
};

struct u2f_key_handle {
	uint8_t origin_seed[U2F_ORIGIN_SEED_SIZE];
	uint8_t hmac[SHA256_DIGEST_SIZE];
};

struct u2f_versioned_key_handle_header {
	uint8_t version;
	uint8_t origin_seed[U2F_ORIGIN_SEED_SIZE];
	uint8_t kh_hmac[SHA256_DIGEST_SIZE];
};

struct u2f_versioned_key_handle {
	struct u2f_versioned_key_handle_header header;
	/* Optionally checked in u2f_sign. */
	uint8_t authorization_salt[U2F_AUTHORIZATION_SALT_SIZE];
	uint8_t authorization_hmac[SHA256_DIGEST_SIZE];
};

/**
 * Alternative definitions of key handles.
 *
 *  struct u2f_key_handle_v0 == struct u2f_key_handle
 *  struct u2f_key_handle_v1 == struct u2f_versioned_key_handle
 *
 */

/* Key handle version = 0, only bound to device. */
struct u2f_key_handle_v0 {
	uint8_t origin_seed[U2F_ORIGIN_SEED_SIZE];
	uint8_t hmac[SHA256_DIGEST_SIZE];
};

/* Key handle version = 1, bound to device and user. */
struct u2f_key_handle_v1 {
	uint8_t version;
	uint8_t origin_seed[U2F_ORIGIN_SEED_SIZE];
	/* HMAC(u2f_hmac_key, origin || user || origin seed || version) */
	uint8_t kh_hmac[SHA256_DIGEST_SIZE];
	/* Optionally checked in u2f_sign. */
	uint8_t authorization_salt[U2F_AUTHORIZATION_SALT_SIZE];
	/**
	 * HMAC(u2f_hmac_key,
	 *      auth_salt || version || origin_seed
	 *      || kh_hmac || authTimeSecretHash)
	 */
	uint8_t authorization_hmac[SHA256_DIGEST_SIZE];
};

/* Key handle version = 2, bound to device and user. */
struct u2f_key_handle_v2 {
	uint8_t version;
	uint8_t origin_seed[U2F_ORIGIN_SEED_SIZE];
	/* Always checked in u2f_sign. */
	uint8_t authorization_salt[U2F_AUTHORIZATION_SALT_SIZE];
	/**
	 * HMAC(u2f_hmac_key,
	 *      auth_salt || version || origin_seed || origin ||
	 *      user || authTimeSecretHash)
	 */
	uint8_t authorization_hmac[SHA256_DIGEST_SIZE];
};

union u2f_key_handle_variant {
	struct u2f_key_handle_v0 v0;
	struct u2f_key_handle_v1 v1;
	struct u2f_key_handle_v2 v2;
};

/* TODO(louiscollard): Add Descriptions. */

struct u2f_generate_req {
	uint8_t appId[U2F_APPID_SIZE]; /* Application id */
	uint8_t userSecret[U2F_USER_SECRET_SIZE];
	uint8_t flags;
	/*
	 * If generating versioned KH, derive an hmac from it and append to
	 * the key handle. Otherwise unused.
	 */
	uint8_t authTimeSecretHash[U2F_AUTH_TIME_SECRET_SIZE];
};

struct u2f_generate_resp {
	struct u2f_ec_point pubKey; /* Generated public key */
	struct u2f_key_handle keyHandle;
};

struct u2f_generate_versioned_resp {
	struct u2f_ec_point pubKey; /* Generated public key */
	struct u2f_versioned_key_handle keyHandle;
};

struct u2f_generate_versioned_resp_v2 {
	struct u2f_ec_point pubKey; /* Generated public key */
	struct u2f_key_handle_v2 keyHandle;
};

/**
 * Combined type for U2F_GENERATE response. Length of response size
 * should be used to determine which version of key handle is generated.
 * Caller may check that response matches request flags.
 */
union u2f_generate_response {
	struct u2f_generate_resp v0;
	struct u2f_generate_versioned_resp v1;
	struct u2f_generate_versioned_resp_v2 v2;
};

struct u2f_sign_req {
	uint8_t appId[U2F_APPID_SIZE]; /* Application id */
	uint8_t userSecret[U2F_USER_SECRET_SIZE];
	struct u2f_key_handle keyHandle;
	uint8_t hash[U2F_P256_SIZE];
	uint8_t flags;
};

struct u2f_sign_versioned_req {
	uint8_t appId[U2F_APPID_SIZE]; /* Application id */
	uint8_t userSecret[U2F_USER_SECRET_SIZE];
	uint8_t authTimeSecret[U2F_AUTH_TIME_SECRET_SIZE];
	uint8_t hash[U2F_P256_SIZE];
	uint8_t flags;
	struct u2f_versioned_key_handle keyHandle;
};

struct u2f_sign_versioned_req_v2 {
	uint8_t appId[U2F_APPID_SIZE]; /* Application id */
	uint8_t userSecret[U2F_USER_SECRET_SIZE];
	uint8_t authTimeSecret[U2F_AUTH_TIME_SECRET_SIZE];
	uint8_t hash[U2F_P256_SIZE];
	uint8_t flags;
	struct u2f_key_handle_v2 keyHandle;
};

/**
 * Combined type for U2F_SIGN request. Length of request size
 * is used to determine which version of key handle is provided.
 */
union u2f_sign_request {
	struct u2f_sign_req v0;
	struct u2f_sign_versioned_req v1;
	struct u2f_sign_versioned_req_v2 v2;
};

struct u2f_sign_resp {
	uint8_t sig_r[U2F_P256_SIZE]; /* Signature */
	uint8_t sig_s[U2F_P256_SIZE]; /* Signature */
};

struct u2f_attest_req {
	uint8_t userSecret[U2F_USER_SECRET_SIZE];
	uint8_t format;
	uint8_t dataLen;
	/* struct g2f_register_msg_vX or corp_register_msg_vX */
	uint8_t data[U2F_MAX_ATTEST_SIZE];
};

struct g2f_register_msg_v0 {
	uint8_t reserved;
	uint8_t app_id[U2F_APPID_SIZE];
	uint8_t challenge[U2F_CHAL_SIZE];
	struct u2f_key_handle_v0 key_handle;
	struct u2f_ec_point public_key;
};

struct corp_attest_data {
	uint8_t challenge[CORP_CHAL_SIZE];
	struct u2f_ec_point public_key;
	uint8_t salt[65];
};

struct corp_register_msg_v0 {
	struct corp_attest_data data;
	uint8_t app_id[U2F_APPID_SIZE];
	struct u2f_key_handle_v0 key_handle;
};

union u2f_attest_msg_variant {
	struct g2f_register_msg_v0 g2f;
	struct corp_register_msg_v0 corp;
};

struct u2f_attest_resp {
	uint8_t sig_r[U2F_P256_SIZE];
	uint8_t sig_s[U2F_P256_SIZE];
};

/* Command status responses */

#define U2F_SW_NO_ERROR	  0x9000 /* SW_NO_ERROR */
#define U2F_SW_WRONG_DATA 0x6A80 /* SW_WRONG_DATA */
#define U2F_SW_CONDITIONS_NOT_SATISFIED       \
	0x6985 /* SW_CONDITIONS_NOT_SATISFIED \
		*/
#define U2F_SW_COMMAND_NOT_ALLOWED 0x6986 /* SW_COMMAND_NOT_ALLOWED */
#define U2F_SW_INS_NOT_SUPPORTED   0x6D00 /* SW_INS_NOT_SUPPORTED */

/* Protocol extensions */

/* Non-standardized command status responses */
#define U2F_SW_CLA_NOT_SUPPORTED 0x6E00
#define U2F_SW_WRONG_LENGTH	 0x6700
#define U2F_SW_WTF		 0x6f00

/* Additional flags for P1 field */
#define G2F_ATTEST  0x80 /* Fixed attestation key */
#define G2F_CONSUME 0x02 /* Consume presence */

/*
 * The key handle format was changed when support for user secrets was added.
 * U2F_SIGN requests that specify this flag will first try to validate the key
 * handle as a new format key handle, and if that fails, will fall back to
 * treating it as a legacy key handle (without user secrets).
 */
#define SIGN_LEGACY_KH 0x40

/* U2F Attest format for U2F Register Response. */
#define U2F_ATTEST_FORMAT_REG_RESP 0

/* Corp Attest format for U2F Register Response. */
#define CORP_ATTEST_FORMAT_REG_RESP 1

/* Vendor command to enable/disable the extensions */
#define U2F_VENDOR_MODE U2F_VENDOR_LAST

#ifdef __cplusplus
}
#endif

#endif /* __U2F_H_INCLUDED__ */