/src/nss-nspr/nss/lib/freebl/ecl/ecp_secp256r1.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* P-256 from HACL* */ |
2 | | |
3 | | #ifdef FREEBL_NO_DEPEND |
4 | | #include "../stubs.h" |
5 | | #endif |
6 | | |
7 | | #include "ecl-priv.h" |
8 | | #include "secitem.h" |
9 | | #include "secerr.h" |
10 | | #include "secmpi.h" |
11 | | #include "../verified/Hacl_P256.h" |
12 | | |
13 | | /* |
14 | | * Point Validation for P-256. |
15 | | */ |
16 | | |
17 | | SECStatus |
18 | | ec_secp256r1_pt_validate(const SECItem *pt) |
19 | 28 | { |
20 | 28 | SECStatus res = SECSuccess; |
21 | 28 | if (!pt || !pt->data) { |
22 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
23 | 0 | res = SECFailure; |
24 | 0 | return res; |
25 | 0 | } |
26 | | |
27 | 28 | if (pt->len != 65) { |
28 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
29 | 0 | res = SECFailure; |
30 | 0 | return res; |
31 | 0 | } |
32 | | |
33 | 28 | if (pt->data[0] != EC_POINT_FORM_UNCOMPRESSED) { |
34 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM); |
35 | 0 | res = SECFailure; |
36 | 0 | return res; |
37 | 0 | } |
38 | | |
39 | 28 | bool b = Hacl_P256_validate_public_key(pt->data + 1); |
40 | | |
41 | 28 | if (!b) { |
42 | 10 | PORT_SetError(SEC_ERROR_BAD_KEY); |
43 | 10 | res = SECFailure; |
44 | 10 | } |
45 | 28 | return res; |
46 | 28 | } |
47 | | |
48 | | /* |
49 | | * Scalar Validation for P-256. |
50 | | */ |
51 | | |
52 | | SECStatus |
53 | | ec_secp256r1_scalar_validate(const SECItem *scalar) |
54 | 40 | { |
55 | 40 | SECStatus res = SECSuccess; |
56 | 40 | if (!scalar || !scalar->data) { |
57 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
58 | 0 | res = SECFailure; |
59 | 0 | return res; |
60 | 0 | } |
61 | | |
62 | 40 | if (scalar->len != 32) { |
63 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
64 | 0 | res = SECFailure; |
65 | 0 | return res; |
66 | 0 | } |
67 | | |
68 | 40 | bool b = Hacl_P256_validate_private_key(scalar->data); |
69 | | |
70 | 40 | if (!b) { |
71 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
72 | 0 | res = SECFailure; |
73 | 0 | } |
74 | 40 | return res; |
75 | 40 | } |
76 | | |
77 | | /* |
78 | | * Scalar multiplication for P-256. |
79 | | * If P == NULL, the base point is used. |
80 | | * Returns X = k*P |
81 | | */ |
82 | | |
83 | | SECStatus |
84 | | ec_secp256r1_pt_mul(SECItem *X, SECItem *k, SECItem *P) |
85 | 89 | { |
86 | 89 | SECStatus res = SECSuccess; |
87 | 89 | if (!P) { |
88 | 89 | uint8_t derived[64] = { 0 }; |
89 | | |
90 | 89 | if (!X || !k || !X->data || !k->data || |
91 | 89 | X->len < 65 || k->len != 32) { |
92 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
93 | 0 | res = SECFailure; |
94 | 0 | return res; |
95 | 0 | } |
96 | | |
97 | 89 | bool b = Hacl_P256_dh_initiator(derived, k->data); |
98 | | |
99 | 89 | if (!b) { |
100 | 4 | PORT_SetError(SEC_ERROR_BAD_KEY); |
101 | 4 | res = SECFailure; |
102 | 4 | return res; |
103 | 4 | } |
104 | | |
105 | 85 | X->len = 65; |
106 | 85 | X->data[0] = EC_POINT_FORM_UNCOMPRESSED; |
107 | 85 | memcpy(X->data + 1, derived, 64); |
108 | | |
109 | 85 | } else { |
110 | 0 | uint8_t full_key[32] = { 0 }; |
111 | 0 | uint8_t *key; |
112 | 0 | uint8_t derived[64] = { 0 }; |
113 | |
|
114 | 0 | if (!X || !k || !P || !X->data || !k->data || !P->data || |
115 | 0 | X->len < 32 || P->len != 65 || |
116 | 0 | P->data[0] != EC_POINT_FORM_UNCOMPRESSED) { |
117 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
118 | 0 | res = SECFailure; |
119 | 0 | return res; |
120 | 0 | } |
121 | | |
122 | | /* We consider keys of up to size 32, or of size 33 with a single leading 0 */ |
123 | 0 | if (k->len < 32) { |
124 | 0 | memcpy(full_key + 32 - k->len, k->data, k->len); |
125 | 0 | key = full_key; |
126 | 0 | } else if (k->len == 32) { |
127 | 0 | key = k->data; |
128 | 0 | } else if (k->len == 33 && k->data[0] == 0) { |
129 | 0 | key = k->data + 1; |
130 | 0 | } else { |
131 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
132 | 0 | res = SECFailure; |
133 | 0 | return res; |
134 | 0 | } |
135 | | |
136 | 0 | bool b = Hacl_P256_dh_responder(derived, P->data + 1, key); |
137 | |
|
138 | 0 | if (!b) { |
139 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
140 | 0 | res = SECFailure; |
141 | 0 | return res; |
142 | 0 | } |
143 | | |
144 | 0 | X->len = 32; |
145 | 0 | memcpy(X->data, derived, 32); |
146 | 0 | } |
147 | | |
148 | 85 | return res; |
149 | 89 | } |
150 | | |
151 | | /* |
152 | | * ECDSA Signature for P-256 |
153 | | */ |
154 | | |
155 | | SECStatus |
156 | | ec_secp256r1_sign_digest(ECPrivateKey *ecPrivKey, SECItem *signature, |
157 | | const SECItem *digest, const unsigned char *kb, |
158 | | const unsigned int kblen) |
159 | 16 | { |
160 | 16 | SECStatus res = SECSuccess; |
161 | | |
162 | 16 | if (!ecPrivKey || !signature || !digest || !kb || |
163 | 16 | !ecPrivKey->privateValue.data || |
164 | 16 | !signature->data || !digest->data || |
165 | 16 | ecPrivKey->ecParams.name != ECCurve_NIST_P256) { |
166 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
167 | 0 | res = SECFailure; |
168 | 0 | return res; |
169 | 0 | } |
170 | | |
171 | 16 | if (kblen == 0 || digest->len == 0 || signature->len < 64) { |
172 | 0 | PORT_SetError(SEC_ERROR_INPUT_LEN); |
173 | 0 | res = SECFailure; |
174 | 0 | return res; |
175 | 0 | } |
176 | | |
177 | | // Private keys should be 32 bytes, but some software trims leading zeros, |
178 | | // and some software produces 33 byte keys with a leading zero. We'll |
179 | | // accept these variants. |
180 | 16 | uint8_t padded_key_data[32] = { 0 }; |
181 | 16 | uint8_t *key; |
182 | 16 | SECItem *privKey = &ecPrivKey->privateValue; |
183 | 16 | if (privKey->len == 32) { |
184 | 16 | key = privKey->data; |
185 | 16 | } else if (privKey->len == 33 && privKey->data[0] == 0) { |
186 | 0 | key = privKey->data + 1; |
187 | 0 | } else if (privKey->len < 32) { |
188 | 0 | memcpy(padded_key_data + 32 - privKey->len, privKey->data, privKey->len); |
189 | 0 | key = padded_key_data; |
190 | 0 | } else { |
191 | 0 | PORT_SetError(SEC_ERROR_INPUT_LEN); |
192 | 0 | return SECFailure; |
193 | 0 | } |
194 | | |
195 | 16 | uint8_t hash[32] = { 0 }; |
196 | 16 | if (digest->len < 32) { |
197 | 16 | memcpy(hash + 32 - digest->len, digest->data, digest->len); |
198 | 16 | } else { |
199 | 0 | memcpy(hash, digest->data, 32); |
200 | 0 | } |
201 | | |
202 | 16 | uint8_t nonce[32] = { 0 }; |
203 | 16 | if (kblen < 32) { |
204 | 1 | memcpy(nonce + 32 - kblen, kb, kblen); |
205 | 15 | } else { |
206 | 15 | memcpy(nonce, kb, 32); |
207 | 15 | } |
208 | | |
209 | 16 | bool b = Hacl_P256_ecdsa_sign_p256_without_hash( |
210 | 16 | signature->data, 32, hash, key, nonce); |
211 | 16 | if (!b) { |
212 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
213 | 0 | res = SECFailure; |
214 | 0 | return res; |
215 | 0 | } |
216 | | |
217 | 16 | signature->len = 64; |
218 | 16 | return res; |
219 | 16 | } |
220 | | |
221 | | /* |
222 | | * ECDSA Signature Verification for P-256 |
223 | | */ |
224 | | |
225 | | SECStatus |
226 | | ec_secp256r1_verify_digest(ECPublicKey *key, const SECItem *signature, |
227 | | const SECItem *digest) |
228 | 17 | { |
229 | 17 | SECStatus res = SECSuccess; |
230 | | |
231 | 17 | unsigned char _padded_sig_data[64] = { 0 }; |
232 | 17 | unsigned char *sig_r, *sig_s; |
233 | | |
234 | 17 | if (!key || !signature || !digest || |
235 | 17 | !key->publicValue.data || |
236 | 17 | !signature->data || !digest->data || |
237 | 17 | key->ecParams.name != ECCurve_NIST_P256) { |
238 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
239 | 0 | res = SECFailure; |
240 | 0 | return res; |
241 | 0 | } |
242 | | |
243 | 17 | unsigned int olen = key->ecParams.order.len; |
244 | 17 | if (signature->len == 0 || signature->len % 2 != 0 || |
245 | 17 | signature->len > 2 * olen || |
246 | 17 | digest->len == 0 || key->publicValue.len != 65) { |
247 | 0 | PORT_SetError(SEC_ERROR_INPUT_LEN); |
248 | 0 | res = SECFailure; |
249 | 0 | return res; |
250 | 0 | } |
251 | | |
252 | 17 | if (key->publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED) { |
253 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM); |
254 | 0 | res = SECFailure; |
255 | 0 | return res; |
256 | 0 | } |
257 | | |
258 | | /* P-256 signature has to be 64 bytes long, pad it with 0s if it isn't */ |
259 | 17 | if (signature->len != 64) { |
260 | 0 | unsigned split = signature->len / 2; |
261 | 0 | unsigned pad = 32 - split; |
262 | |
|
263 | 0 | unsigned char *o_sig = signature->data; |
264 | 0 | unsigned char *p_sig = _padded_sig_data; |
265 | |
|
266 | 0 | memcpy(p_sig + pad, o_sig, split); |
267 | 0 | memcpy(p_sig + 32 + pad, o_sig + split, split); |
268 | |
|
269 | 0 | sig_r = p_sig; |
270 | 0 | sig_s = p_sig + 32; |
271 | 17 | } else { |
272 | 17 | sig_r = signature->data; |
273 | 17 | sig_s = signature->data + 32; |
274 | 17 | } |
275 | | |
276 | 17 | uint8_t hash[32] = { 0 }; |
277 | 17 | if (digest->len < 32) { |
278 | 17 | memcpy(hash + 32 - digest->len, digest->data, digest->len); |
279 | 17 | } else { |
280 | 0 | memcpy(hash, digest->data, 32); |
281 | 0 | } |
282 | | |
283 | 17 | bool b = Hacl_P256_ecdsa_verif_without_hash( |
284 | 17 | 32, hash, |
285 | 17 | key->publicValue.data + 1, |
286 | 17 | sig_r, sig_s); |
287 | 17 | if (!b) { |
288 | 1 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
289 | 1 | res = SECFailure; |
290 | 1 | return res; |
291 | 1 | } |
292 | | |
293 | 16 | return res; |
294 | 17 | } |