summaryrefslogtreecommitdiff
path: root/board/cr50/dcrypto/p256_ec.c
blob: 6fae0cb52c2b8b8091160c60bfe993db1dc52591 (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
/* 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.
 */
#include "internal.h"

enum dcrypto_result DCRYPTO_p256_ecdsa_verify(const p256_int *key_x,
					      const p256_int *key_y,
					      const p256_int *message,
					      const p256_int *r,
					      const p256_int *s)
{
	if (!fips_crypto_allowed())
		return DCRYPTO_FAIL;

	return dcrypto_p256_ecdsa_verify(key_x, key_y, message, r, s);
}

/* return codes match dcrypto_p256_ecdsa_sign */
enum dcrypto_result DCRYPTO_p256_ecdsa_sign(const p256_int *key,
					    const p256_int *message,
					    p256_int *r, p256_int *s)
{
	if (!fips_drbg_init()) /* Also check for fips_crypto_allowed(). */
		return DCRYPTO_FAIL;

	return dcrypto_p256_fips_sign_internal(&fips_drbg, key, message, r, s);
}

/* p256_base_point_mul sets {out_x,out_y} = nG, where n is < the
 * order of the group. */
enum dcrypto_result DCRYPTO_p256_base_point_mul(p256_int *out_x,
		p256_int *out_y, const p256_int *n)
{
	if (!fips_crypto_allowed() || p256_is_zero(n)) {
		p256_clear(out_x);
		p256_clear(out_y);
		return DCRYPTO_FAIL;
	}

	return dcrypto_p256_base_point_mul(n, out_x, out_y);
}

enum dcrypto_result DCRYPTO_p256_is_valid_point(const p256_int *x,
						const p256_int *y)
{
	if (!fips_crypto_allowed())
		return DCRYPTO_FAIL;
	return dcrypto_p256_is_valid_point(x, y);
}

/* DCRYPTO_p256_point_mul sets {out_x,out_y} = n*{in_x,in_y}, where n is <
 * the order of the group. */
enum dcrypto_result 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)
{
	if (!fips_crypto_allowed() || p256_is_zero(n) ||
	    (dcrypto_p256_is_valid_point(in_x, in_y) != DCRYPTO_OK)) {
		p256_clear(out_x);
		p256_clear(out_y);
		return DCRYPTO_FAIL;
	}
	return dcrypto_p256_point_mul(n, in_x, in_y, out_x, out_y);
}

/**
 * This function serves as workaround for gcc 11.2 crash.
 */
static enum dcrypto_result fips_p256_hmac_drbg_generate(struct drbg_ctx *ctx,
							p256_int *rnd)
{
	return p256_hmac_drbg_generate(ctx, rnd);
}

enum dcrypto_result dcrypto_p256_fips_sign_internal(struct drbg_ctx *drbg,
						    const p256_int *key,
						    const p256_int *message,
						    p256_int *r, p256_int *s)
{
	enum dcrypto_result result;
	p256_int k;

	/* Pick uniform 0 < k < R */
	result = fips_p256_hmac_drbg_generate(drbg, &k);

	result |= dcrypto_p256_ecdsa_sign_raw(&k, key, message, r, s);

	/* Wipe temp k */
	p256_clear(&k);

	return dcrypto_ok_if_zero(result - DCRYPTO_OK);
}

enum dcrypto_result dcrypto_p256_key_pwct(struct drbg_ctx *drbg,
					  const p256_int *d, const p256_int *x,
					  const p256_int *y)
{
	p256_int message, r, s;
	enum dcrypto_result result;
#ifdef CRYPTO_TEST_SETUP
	p256_int d_altered;
#endif

	if (p256_is_zero(d))
		return DCRYPTO_FAIL;

	/* set some pseudo-random message. */
	p256_fast_random(&message);

#ifdef CRYPTO_TEST_SETUP
	if (fips_break_cmd == FIPS_BREAK_ECDSA_PWCT) {
		/* Modify key used for signing. */
		d_altered = *d;
		d_altered.a[1] ^= 1;
		d = &d_altered;
	}
#endif

	result = dcrypto_p256_fips_sign_internal(drbg, d, &message, &r, &s);
	if (result != DCRYPTO_OK) {
		fips_set_status(FIPS_FATAL_ECDSA_PWCT);
		return result;
	}

	result = dcrypto_p256_ecdsa_verify(x, y, &message, &r, &s);
	if (result != DCRYPTO_OK) {
		fips_set_status(FIPS_FATAL_ECDSA_PWCT);
		return result;
	}

	return result;
}

/**
 * Key selection based on FIPS-186-4, section B.4.2 (Key Pair
 * Generation by Testing Candidates).
 */
enum dcrypto_result DCRYPTO_p256_key_from_bytes(p256_int *x,
	p256_int *y, p256_int *d, const uint8_t key_bytes[P256_NBYTES])
{
	p256_int key;
	p256_int tx, ty;

	if (!fips_crypto_allowed())
		return DCRYPTO_FAIL;

	p256_from_bin(key_bytes, &key);

	/**
	 * We need key to be in the range  0 < key < SECP256r1 - 1.
	 * To achieve that, first check key < SECP256r1 - 2, and
	 * then add 1 to key. Since key is unsigned number this will
	 * bring key in proper range.
	 */
	if (p256_lt_blinded(&key, &SECP256r1_nMin2) >= 0)
		return DCRYPTO_RETRY;
	p256_add_d(&key, 1, d);
	always_memset(&key, 0, sizeof(key));

	/* We need public key anyway for pair-wise consistency test. */
	if (!x)
		x = &tx;
	if (!y)
		y = &ty;

	/* Compute public key (x,y) = d * G */
	if (dcrypto_p256_base_point_mul(d, x, y) != DCRYPTO_OK)
		return DCRYPTO_FAIL;

	return dcrypto_p256_key_pwct(&fips_drbg, d, x, y);
}