summaryrefslogtreecommitdiff
path: root/board/cr50/dcrypto/dcrypto.h
blob: 8cf1071090866248a46e03268a8a044bd4416577 (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
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
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
/* Copyright 2015 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/*
 * Crypto wrapper library for the g chip.
 */
#ifndef __EC_CHIP_G_DCRYPTO_DCRYPTO_H
#define __EC_CHIP_G_DCRYPTO_DCRYPTO_H

#ifdef __cplusplus
extern "C" {
#endif

#if defined(TEST_FUZZ) || !defined(TEST_BUILD)

#include "internal.h"

#include "crypto_api.h"

#include <stddef.h>

#include "cryptoc/hmac.h"

enum cipher_mode {
	CIPHER_MODE_ECB = 0, /* NIST SP 800-38A */
	CIPHER_MODE_CTR = 1, /* NIST SP 800-38A */
	CIPHER_MODE_CBC = 2, /* NIST SP 800-38A */
	CIPHER_MODE_GCM = 3  /* NIST SP 800-38D */
};

enum encrypt_mode {
	DECRYPT_MODE = 0,
	ENCRYPT_MODE = 1
};

enum hashing_mode {
	HASH_SHA1 = 0,
	HASH_SHA256 = 1,
	HASH_SHA384 = 2,  /* Only supported for PKCS#1 signing */
	HASH_SHA512 = 3,  /* Only supported for PKCS#1 signing */
	HASH_NULL = 4  /* Only supported for PKCS#1 signing */
};

/*
 * AES implementation, based on a hardware AES block.
 * FIPS Publication 197, The Advanced Encryption Standard (AES)
 */
#define AES256_BLOCK_CIPHER_KEY_SIZE       32

int DCRYPTO_aes_init(const uint8_t *key, uint32_t key_len, const uint8_t *iv,
		enum cipher_mode c_mode, enum encrypt_mode e_mode);
int DCRYPTO_aes_block(const uint8_t *in, uint8_t *out);

void DCRYPTO_aes_write_iv(const uint8_t *iv);
void DCRYPTO_aes_read_iv(uint8_t *iv);

/* AES-CTR-128/192/256
 * NIST Special Publication 800-38A
 */
int DCRYPTO_aes_ctr(uint8_t *out, const uint8_t *key, uint32_t key_bits,
		const uint8_t *iv, const uint8_t *in, size_t in_len);

/* AES-GCM-128/192/256
 * NIST Special Publication 800-38D, IV is provided externally
 * Caller should use IV length according to section 8.2 of SP 800-38D
 * And choose appropriate IV construction method, constrain number
 * of invocations according to section 8.3 of SP 800-38D
 */
struct GCM_CTX {
	union {
		uint32_t d[4];
		uint8_t c[16];
	} block, Ej0;

	uint64_t aad_len;
	uint64_t count;
	size_t remainder;
};

/* Initialize the GCM context structure. */
void DCRYPTO_gcm_init(struct GCM_CTX *ctx, uint32_t key_bits,
		const uint8_t *key, const uint8_t *iv, size_t iv_len);
/* Additional authentication data to include in the tag calculation. */
void DCRYPTO_gcm_aad(struct GCM_CTX *ctx, const uint8_t *aad_data, size_t len);
/* Encrypt & decrypt return the number of bytes written to out
 * (always an integral multiple of 16), or -1 on error.  These functions
 * may be called repeatedly with incremental data.
 *
 * NOTE: if in_len is not a integral multiple of 16, then out_len must
 * be atleast in_len - (in_len % 16) + 16 bytes.
 */
int DCRYPTO_gcm_encrypt(struct GCM_CTX *ctx, uint8_t *out, size_t out_len,
			const uint8_t *in, size_t in_len);
int DCRYPTO_gcm_decrypt(struct GCM_CTX *ctx, uint8_t *out, size_t out_len,
			const uint8_t *in, size_t in_len);
/* Encrypt & decrypt a partial final block, if any.  These functions
 * return the number of bytes written to out (<= 15), or -1 on error.
 */
int DCRYPTO_gcm_encrypt_final(struct GCM_CTX *ctx,
			uint8_t *out, size_t out_len);
int DCRYPTO_gcm_decrypt_final(struct GCM_CTX *ctx,
			uint8_t *out, size_t out_len);
/* Compute the tag over AAD + encrypt or decrypt data, and return the
 * number of bytes written to tag.  Returns -1 on error.
 */
int DCRYPTO_gcm_tag(struct GCM_CTX *ctx, uint8_t *tag, size_t tag_len);
/* Cleanup secrets. */
void DCRYPTO_gcm_finish(struct GCM_CTX *ctx);

/* AES-CMAC-128
 * NIST Special Publication 800-38B, RFC 4493
 * K: 128-bit key, M: message, len: number of bytes in M
 * Writes 128-bit tag to T; returns 0 if an error is encountered and 1
 * otherwise.
 */
int DCRYPTO_aes_cmac(const uint8_t *K, const uint8_t *M, const uint32_t len,
		uint32_t T[4]);
/* key: 128-bit key, M: message, len: number of bytes in M,
 *    T: tag to be verified
 * Returns 1 if the tag is correct and 0 otherwise.
 */
int DCRYPTO_aes_cmac_verify(const uint8_t *key, const uint8_t *M, const int len,
		const uint32_t T[4]);

/*
 * SHA implementation.  This abstraction is backed by either a
 * software or hardware implementation.
 *
 * There could be only a single hardware SHA context in progress. The init
 * functions will try using the HW context, if available, unless 'sw_required'
 * is TRUE, in which case there will be no attempt to use the hardware for
 * this particular hashing session.
 */
void DCRYPTO_SHA1_init(SHA_CTX *ctx, uint32_t sw_required);
/*  SHA256/384/512 FIPS 180-4
 */
void DCRYPTO_SHA256_init(LITE_SHA256_CTX *ctx, uint32_t sw_required);
void DCRYPTO_SHA384_init(LITE_SHA384_CTX *ctx);
void DCRYPTO_SHA512_init(LITE_SHA512_CTX *ctx);
const uint8_t *DCRYPTO_SHA1_hash(const void *data, uint32_t n,
				uint8_t *digest);
const uint8_t *DCRYPTO_SHA256_hash(const void *data, uint32_t n,
				   uint8_t *digest);
const uint8_t *DCRYPTO_SHA384_hash(const void *data, uint32_t n,
				   uint8_t *digest);
const uint8_t *DCRYPTO_SHA512_hash(const void *data, uint32_t n,
				   uint8_t *digest);
/*
 *  HMAC. FIPS 198-1
 */
void DCRYPTO_HMAC_SHA256_init(LITE_HMAC_CTX *ctx, const void *key,
			unsigned int len);
/* DCRYPTO HMAC-SHA256 final */
const uint8_t *DCRYPTO_HMAC_final(LITE_HMAC_CTX *ctx);

/*
 * BIGNUM utility methods.
 */
void DCRYPTO_bn_wrap(struct LITE_BIGNUM *b, void *buf, size_t len);

/*
 *  RSA.
 */

/* Largest supported key size for signing / encryption: 2048-bits.
 * Verification is a special case and supports 4096-bits (signing /
 * decryption could also support 4k-RSA, but is disabled since support
 * is not required, and enabling support would result in increased
 * stack usage for all key sizes.)
 */
#define RSA_BYTES_2K    256
#define RSA_BYTES_4K    512
#define RSA_WORDS_2K    (RSA_BYTES_2K / sizeof(uint32_t))
#define RSA_WORDS_4K    (RSA_BYTES_4K / sizeof(uint32_t))
#ifndef RSA_MAX_BYTES
#define RSA_MAX_BYTES   RSA_BYTES_2K
#endif
#define RSA_MAX_WORDS   (RSA_MAX_BYTES / sizeof(uint32_t))
#define RSA_F4          65537

struct RSA {
	uint32_t e;
	struct LITE_BIGNUM N;
	struct LITE_BIGNUM d;
};

enum padding_mode {
	PADDING_MODE_PKCS1 = 0,
	PADDING_MODE_OAEP  = 1,
	PADDING_MODE_PSS = 2,
	/* USE OF NULL PADDING IS NOT RECOMMENDED.
	 * SUPPORT EXISTS AS A REQUIREMENT FOR TPM2 OPERATION. */
	PADDING_MODE_NULL  = 3
};

/* RSA support, FIPS PUB 186-4 *
 * Calculate r = m ^ e mod N
 */
int DCRYPTO_rsa_encrypt(struct RSA *rsa, uint8_t *out, uint32_t *out_len,
			const uint8_t *in, uint32_t in_len,
			enum padding_mode padding, enum hashing_mode hashing,
			const char *label);

/* Calculate r = m ^ d mod N
 * return 0 if error
 */
int DCRYPTO_rsa_decrypt(struct RSA *rsa, uint8_t *out, uint32_t *out_len,
			const uint8_t *in, const uint32_t in_len,
			enum padding_mode padding, enum hashing_mode hashing,
			const char *label);

/* Calculate r = m ^ d mod N
 * return 0 if error
 */
int DCRYPTO_rsa_sign(struct RSA *rsa, uint8_t *out, uint32_t *out_len,
		const uint8_t *in, const uint32_t in_len,
		enum padding_mode padding, enum hashing_mode hashing);

/* Calculate r = m ^ e mod N
 * return 0 if error
 */
int DCRYPTO_rsa_verify(const struct RSA *rsa, const uint8_t *digest,
		uint32_t digest_len, const uint8_t *sig,
		const uint32_t sig_len,	enum padding_mode padding,
		enum hashing_mode hashing);

/* Calculate n = p * q, d = e ^ -1 mod phi. */
int DCRYPTO_rsa_key_compute(struct LITE_BIGNUM *N, struct LITE_BIGNUM *d,
			struct LITE_BIGNUM *p, struct LITE_BIGNUM *q,
			uint32_t e);

/*
 *  EC.
 */

/* DCRYPTO_p256_base_point_mul sets {out_x,out_y} = nG, where n is < the
 * order of the group.
 */
int DCRYPTO_p256_base_point_mul(p256_int *out_x, p256_int *out_y,
				const p256_int *n);

/* DCRYPTO_p256_point_mul sets {out_x,out_y} = n*{in_x,in_y}, where n is <
 * the order of the group.
 */
int DCRYPTO_p256_point_mul(p256_int *out_x, p256_int *out_y,
			const p256_int *n, const p256_int *in_x,
			const p256_int *in_y);
/*
 * Key selection based on FIPS-186-4, section B.4.2 (Key Pair
 * Generation by Testing Candidates).
 * Produce uniform private key from seed.
 * If x or y is NULL, the public key part is not computed.
 * Returns !0 on success.
 */
int DCRYPTO_p256_key_from_bytes(p256_int *x, p256_int *y, p256_int *d,
				const uint8_t bytes[P256_NBYTES]);


/* P256 based integration encryption (DH+AES128+SHA256).
 * Not FIPS 140-2 compliant, not used other than for tests
 * Authenticated data may be provided, where the first auth_data_len
 * bytes of in will be authenticated but not encrypted. *
 * Supports in-place encryption / decryption. *
 * The output format is:
 * 0x04 || PUBKEY || AUTH_DATA || AES128_CTR(PLAINTEXT) ||
 *         HMAC_SHA256(AUTH_DATA || CIPHERTEXT)
 */
size_t DCRYPTO_ecies_encrypt(
	void *out, size_t out_len, const void *in, size_t in_len,
	size_t auth_data_len, const uint8_t *iv,
	const p256_int *pub_x, const p256_int *pub_y,
	const uint8_t *salt, size_t salt_len,
	const uint8_t *info, size_t info_len);
size_t DCRYPTO_ecies_decrypt(
	void *out, size_t out_len, const void *in, size_t in_len,
	size_t auth_data_len, const uint8_t *iv,
	const p256_int *d,
	const uint8_t *salt, size_t salt_len,
	const uint8_t *info, size_t info_len);

/*
 * HKDF as per RFC 5869. Mentioned as conforming NIST SP 800-56C Rev.1
 * [RFC 5869] specifies a version of the above extraction-then-expansion
 * key-derivation procedure using HMAC for both the extraction and expansion
 * steps.
 */
int DCRYPTO_hkdf(uint8_t *OKM, size_t OKM_len,
		const uint8_t *salt, size_t salt_len,
		const uint8_t *IKM, size_t IKM_len,
		const uint8_t *info, size_t info_len);

/*
 *  BN.
 */

/* Apply Miller-Rabin test for prime candidate p.
 * Returns 1 if test passed, 0 otherwise
 */
int DCRYPTO_bn_generate_prime(struct LITE_BIGNUM *p);
void DCRYPTO_bn_wrap(struct LITE_BIGNUM *b, void *buf, size_t len);
void DCRYPTO_bn_mul(struct LITE_BIGNUM *c, const struct LITE_BIGNUM *a,
		const struct LITE_BIGNUM *b);
int DCRYPTO_bn_div(struct LITE_BIGNUM *quotient, struct LITE_BIGNUM *remainder,
		const struct LITE_BIGNUM *input,
		const struct LITE_BIGNUM *divisor);

/*
 * ASN.1 DER
 */
size_t DCRYPTO_asn1_sigp(uint8_t *buf, const p256_int *r, const p256_int *s);
size_t DCRYPTO_asn1_pubp(uint8_t *buf, const p256_int *x, const p256_int *y);

/*
 *  X509.
 */
/* DCRYPTO_x509_verify verifies that the provided X509 certificate was issued
 * by the specified certifcate authority.
 *
 * cert is a pointer to a DER encoded X509 certificate, as specified
 * in https://tools.ietf.org/html/rfc5280#section-4.1.  In ASN.1
 * notation, the certificate has the following structure:
 *
 *   Certificate  ::=  SEQUENCE  {
 *        tbsCertificate       TBSCertificate,
 *        signatureAlgorithm   AlgorithmIdentifier,
 *        signatureValue       BIT STRING  }
 *
 *   TBSCertificate  ::=  SEQUENCE  { }
 *   AlgorithmIdentifier  ::=  SEQUENCE  { }
 *
 * where signatureValue = SIGN(HASH(tbsCertificate)), with SIGN and
 * HASH specified by signatureAlgorithm.
 * Accepts only certs with OID: sha256WithRSAEncryption:
 * 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00
 */
int DCRYPTO_x509_verify(const uint8_t *cert, size_t len,
			const struct RSA *ca_pub_key);

/* Generate U2F Certificate and sign it
 * Use ECDSA with NIST P-256 curve, and SHA2-256 digest
 * @param d: key handle, used for NIST SP 800-90A HMAC DRBG
 * @param pk_x, pk_y: public key
 * @param serial: serial number for certificate
 * @param name: certificate issuer and subject
 * @param cert: output buffer for certificate
 * @param n: max size of cert
 */
int DCRYPTO_x509_gen_u2f_cert_name(const p256_int *d, const p256_int *pk_x,
				   const p256_int *pk_y, const p256_int *serial,
				   const char *name, uint8_t *cert,
				   const int n);

/* Generate U2F Certificate with DCRYPTO_x509_gen_u2f_cert_name
 * Providing certificate issuer as BOARD or U2F
 * @param d: key handle, used for NIST SP 800-90A HMAC DRBG
 * @param pk_x, pk_y: public key
 * @param serial: serial number for certificate
 * @param name: certificate issuer and subject
 * @param cert: output buffer for certificate
 * @param n: max size of cert
 */
int DCRYPTO_x509_gen_u2f_cert(const p256_int *d, const p256_int *pk_x,
			const p256_int *pk_y, const p256_int *serial,
			uint8_t *cert, const int n);

/*
 * Memory related functions.
 */
int DCRYPTO_equals(const void *a, const void *b, size_t len);

/*
 * Key-ladder and application key related functions.
 */
enum dcrypto_appid {
	RESERVED = 0,
	NVMEM = 1,
	U2F_ATTEST = 2,
	U2F_ORIGIN = 3,
	U2F_WRAP = 4,
	PERSO_AUTH = 5,
	PINWEAVER = 6,
	/* This enum value should not exceed 7. */
};

struct APPKEY_CTX {
#ifdef TEST_FUZZ
	uint8_t unused_for_cxx_compatibility;
#endif
};

int DCRYPTO_ladder_compute_frk2(size_t major_fw_version, uint8_t *frk2);
int DCRYPTO_ladder_random(void *output);
void DCRYPTO_ladder_revoke(void);

int DCRYPTO_appkey_init(enum dcrypto_appid id, struct APPKEY_CTX *ctx);
void DCRYPTO_appkey_finish(struct APPKEY_CTX *ctx);
int DCRYPTO_appkey_derive(enum dcrypto_appid appid, const uint32_t input[8],
			  uint32_t output[8]);

/* Number of bytes in the salt object. */
#define DCRYPTO_CIPHER_SALT_SIZE 16
BUILD_ASSERT(DCRYPTO_CIPHER_SALT_SIZE == CIPHER_SALT_SIZE);

/*
 * Encrypt/decrypt a flat blob.
 *
 * Encrypt or decrypt the input buffer, and write the correspondingly
 * ciphered output to out.  The number of bytes produced is equal to
 * the number of input bytes.  Note that the input and output pointers
 * MUST be word-aligned.
 *
 * This API is expected to be applied to a single contiguous region.

 * WARNING: A given salt/"in" pair MUST be unique, i.e. re-using a
 * salt with a logically different input buffer is catastrophic.  An
 * example of a suitable salt is one that is derived from "in", e.g. a
 * digest of the input data.
 *
 * @param appid the application-id of the calling context.
 * @param salt pointer to a unique value to be associated with this blob,
 *	       used for derivation of the proper IV, the size of the value
 *	       is as defined by DCRYPTO_CIPHER_SALT_SIZE above.
 * @param out Destination pointer where to write plaintext / ciphertext.
 * @param in  Source pointer where to read ciphertext / plaintext.
 * @param len Number of bytes to read from in / write to out.
 * @return non-zero on success, and zero otherwise.
 */
int DCRYPTO_app_cipher(enum dcrypto_appid appid, const void *salt,
		void *out, const void *in, size_t len);

#endif  /*  ^^^^^^^^^^^^^^^^^^^^^  !TEST_BUILD   */
/*
 * Query whether Key Ladder is enabled.
 *
 * @return 1 if Key Ladder is enabled, and 0 otherwise.
 */
int DCRYPTO_ladder_is_enabled(void);

#ifdef __cplusplus
}
#endif

#endif  /* ! __EC_CHIP_G_DCRYPTO_DCRYPTO_H */