/src/nss/lib/freebl/ecl/ecp_secp521r1.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
2 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | | |
5 | | #ifdef FREEBL_NO_DEPEND |
6 | | #include "../stubs.h" |
7 | | #endif |
8 | | |
9 | | #include "ecl-priv.h" |
10 | | #include "secitem.h" |
11 | | #include "secerr.h" |
12 | | #include "secmpi.h" |
13 | | #include "../verified/Hacl_P521.h" |
14 | | |
15 | | /* |
16 | | * Point Validation for P-521. |
17 | | */ |
18 | | |
19 | | SECStatus |
20 | | ec_secp521r1_pt_validate(const SECItem *pt) |
21 | 0 | { |
22 | 0 | SECStatus res = SECSuccess; |
23 | 0 | if (!pt || !pt->data) { |
24 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
25 | 0 | res = SECFailure; |
26 | 0 | return res; |
27 | 0 | } |
28 | | |
29 | 0 | if (pt->len != 133) { |
30 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
31 | 0 | res = SECFailure; |
32 | 0 | return res; |
33 | 0 | } |
34 | | |
35 | 0 | if (pt->data[0] != EC_POINT_FORM_UNCOMPRESSED) { |
36 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM); |
37 | 0 | res = SECFailure; |
38 | 0 | return res; |
39 | 0 | } |
40 | | |
41 | 0 | #ifndef UNSAFE_FUZZER_MODE |
42 | 0 | bool b = Hacl_P521_validate_public_key(pt->data + 1); |
43 | | #else |
44 | | bool b = PR_TRUE; |
45 | | #endif |
46 | |
|
47 | 0 | if (!b) { |
48 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
49 | 0 | res = SECFailure; |
50 | 0 | } |
51 | 0 | return res; |
52 | 0 | } |
53 | | |
54 | | /* |
55 | | * Scalar Validation for P-521. |
56 | | */ |
57 | | |
58 | | SECStatus |
59 | | ec_secp521r1_scalar_validate(const SECItem *scalar) |
60 | 0 | { |
61 | 0 | SECStatus res = SECSuccess; |
62 | 0 | if (!scalar || !scalar->data) { |
63 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
64 | 0 | res = SECFailure; |
65 | 0 | return res; |
66 | 0 | } |
67 | | |
68 | 0 | if (scalar->len != 66) { |
69 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
70 | 0 | res = SECFailure; |
71 | 0 | return res; |
72 | 0 | } |
73 | | |
74 | 0 | #ifndef UNSAFE_FUZZER_MODE |
75 | 0 | bool b = Hacl_P521_validate_private_key(scalar->data); |
76 | | #else |
77 | | bool b = PR_TRUE; |
78 | | #endif |
79 | |
|
80 | 0 | if (!b) { |
81 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
82 | 0 | res = SECFailure; |
83 | 0 | } |
84 | 0 | return res; |
85 | 0 | } |
86 | | |
87 | | /* |
88 | | * Scalar multiplication for P-521. |
89 | | * If P == NULL, the base point is used. |
90 | | * Returns X = k*P |
91 | | */ |
92 | | |
93 | | SECStatus |
94 | | ec_secp521r1_pt_mul(SECItem *X, SECItem *k, SECItem *P) |
95 | 0 | { |
96 | 0 | SECStatus res = SECSuccess; |
97 | 0 | if (!P) { |
98 | 0 | uint8_t derived[132] = { 0 }; |
99 | |
|
100 | 0 | if (!X || !k || !X->data || !k->data || |
101 | 0 | X->len < 133 || k->len != 66) { |
102 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
103 | 0 | res = SECFailure; |
104 | 0 | return res; |
105 | 0 | } |
106 | | |
107 | 0 | #ifndef UNSAFE_FUZZER_MODE |
108 | 0 | bool b = Hacl_P521_dh_initiator(derived, k->data); |
109 | | #else |
110 | | bool b = PR_TRUE; |
111 | | #endif |
112 | |
|
113 | 0 | if (!b) { |
114 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
115 | 0 | res = SECFailure; |
116 | 0 | return res; |
117 | 0 | } |
118 | | |
119 | 0 | X->len = 133; |
120 | 0 | X->data[0] = EC_POINT_FORM_UNCOMPRESSED; |
121 | 0 | memcpy(X->data + 1, derived, 132); |
122 | |
|
123 | 0 | } else { |
124 | 0 | uint8_t full_key[66] = { 0 }; |
125 | 0 | uint8_t *key; |
126 | 0 | uint8_t derived[132] = { 0 }; |
127 | |
|
128 | 0 | if (!X || !k || !P || !X->data || !k->data || !P->data || |
129 | 0 | X->len < 66 || P->len != 133 || |
130 | 0 | P->data[0] != EC_POINT_FORM_UNCOMPRESSED) { |
131 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
132 | 0 | res = SECFailure; |
133 | 0 | return res; |
134 | 0 | } |
135 | | |
136 | | /* We consider keys of up to size 66, or of size 67 with a single leading 0 */ |
137 | 0 | if (k->len < 66) { |
138 | 0 | memcpy(full_key + 66 - k->len, k->data, k->len); |
139 | 0 | key = full_key; |
140 | 0 | } else if (k->len == 66) { |
141 | 0 | key = k->data; |
142 | 0 | } else if (k->len == 67 && k->data[0] == 0) { |
143 | 0 | key = k->data + 1; |
144 | 0 | } else { |
145 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
146 | 0 | res = SECFailure; |
147 | 0 | return res; |
148 | 0 | } |
149 | | |
150 | 0 | #ifndef UNSAFE_FUZZER_MODE |
151 | 0 | bool b = Hacl_P521_dh_responder(derived, P->data + 1, key); |
152 | | #else |
153 | | bool b = key != NULL; /* Avoiding unused variable warnings */ |
154 | | #endif |
155 | |
|
156 | 0 | if (!b) { |
157 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
158 | 0 | res = SECFailure; |
159 | 0 | return res; |
160 | 0 | } |
161 | | |
162 | 0 | X->len = 66; |
163 | 0 | memcpy(X->data, derived, 66); |
164 | 0 | } |
165 | | |
166 | 0 | return res; |
167 | 0 | } |
168 | | |
169 | | /* |
170 | | * ECDSA Signature for P-521 |
171 | | */ |
172 | | |
173 | | SECStatus |
174 | | ec_secp521r1_sign_digest(ECPrivateKey *ecPrivKey, SECItem *signature, |
175 | | const SECItem *digest, const unsigned char *kb, |
176 | | const unsigned int kblen) |
177 | 0 | { |
178 | 0 | SECStatus res = SECSuccess; |
179 | |
|
180 | 0 | if (!ecPrivKey || !signature || !digest || !kb || |
181 | 0 | !ecPrivKey->privateValue.data || |
182 | 0 | !signature->data || !digest->data || |
183 | 0 | ecPrivKey->ecParams.name != ECCurve_NIST_P521) { |
184 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
185 | 0 | return SECFailure; |
186 | 0 | } |
187 | | |
188 | 0 | if (kblen == 0 || digest->len == 0 || signature->len < 132) { |
189 | 0 | PORT_SetError(SEC_ERROR_INPUT_LEN); |
190 | 0 | return SECFailure; |
191 | 0 | } |
192 | | |
193 | | // Private keys should be 66 bytes, but some software trims leading zeros, |
194 | | // and some software produces 67 byte keys with a leading zero. We'll |
195 | | // accept these variants. |
196 | 0 | uint8_t padded_key_data[66] = { 0 }; |
197 | 0 | uint8_t *key; |
198 | 0 | SECItem *privKey = &ecPrivKey->privateValue; |
199 | 0 | if (privKey->len == 66) { |
200 | 0 | key = privKey->data; |
201 | 0 | } else if (privKey->len == 67 && privKey->data[0] == 0) { |
202 | 0 | key = privKey->data + 1; |
203 | 0 | } else if (privKey->len < 66) { |
204 | 0 | memcpy(padded_key_data + 66 - privKey->len, privKey->data, privKey->len); |
205 | 0 | key = padded_key_data; |
206 | 0 | } else { |
207 | 0 | PORT_SetError(SEC_ERROR_INPUT_LEN); |
208 | 0 | return SECFailure; |
209 | 0 | } |
210 | | |
211 | 0 | uint8_t hash[66] = { 0 }; |
212 | 0 | if (digest->len < 66) { |
213 | 0 | memcpy(hash + 66 - digest->len, digest->data, digest->len); |
214 | 0 | } else { |
215 | | // SEC 1 takes the most significant ceil(log(n)) bits of hash output when the hash output is longer than log(n). |
216 | 0 | hash[0] = digest->data[0] >> 7; |
217 | 0 | for (size_t i = 1; i < 66; i++) { |
218 | 0 | hash[i] = (digest->data[i - 1] << 1) | (digest->data[i] >> 7); |
219 | 0 | } |
220 | 0 | } |
221 | |
|
222 | 0 | uint8_t nonce[66] = { 0 }; |
223 | 0 | if (kblen < 66) { |
224 | 0 | memcpy(nonce + 66 - kblen, kb, kblen); |
225 | 0 | } else { |
226 | 0 | memcpy(nonce, kb, 66); |
227 | 0 | } |
228 | |
|
229 | 0 | #ifndef UNSAFE_FUZZER_MODE |
230 | 0 | bool b = Hacl_P521_ecdsa_sign_p521_without_hash( |
231 | 0 | signature->data, 66, hash, key, nonce); |
232 | | #else |
233 | | bool b = key != NULL; /* Avoiding unused variable warnings */ |
234 | | #endif |
235 | |
|
236 | 0 | if (!b) { |
237 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
238 | 0 | res = SECFailure; |
239 | 0 | return res; |
240 | 0 | } |
241 | | |
242 | 0 | signature->len = 132; |
243 | 0 | return res; |
244 | 0 | } |
245 | | |
246 | | /* |
247 | | * ECDSA Signature Verification for P-521 |
248 | | */ |
249 | | |
250 | | SECStatus |
251 | | ec_secp521r1_verify_digest(ECPublicKey *key, const SECItem *signature, |
252 | | const SECItem *digest) |
253 | 0 | { |
254 | 0 | SECStatus res = SECSuccess; |
255 | |
|
256 | 0 | if (!key || !signature || !digest || |
257 | 0 | !key->publicValue.data || |
258 | 0 | !signature->data || !digest->data || |
259 | 0 | key->ecParams.name != ECCurve_NIST_P521) { |
260 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
261 | 0 | res = SECFailure; |
262 | 0 | return res; |
263 | 0 | } |
264 | | |
265 | 0 | if (signature->len == 0 || signature->len % 2 != 0 || |
266 | 0 | signature->len > 132 || digest->len == 0 || |
267 | 0 | key->publicValue.len != 133) { |
268 | 0 | PORT_SetError(SEC_ERROR_INPUT_LEN); |
269 | 0 | res = SECFailure; |
270 | 0 | return res; |
271 | 0 | } |
272 | | |
273 | 0 | if (key->publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED) { |
274 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM); |
275 | 0 | res = SECFailure; |
276 | 0 | return res; |
277 | 0 | } |
278 | | |
279 | | // Signatures should be 132 bytes, but some software produces short signatures. |
280 | | // Pad components with zeros if necessary. |
281 | 0 | uint8_t paddedSigData[132] = { 0 }; |
282 | 0 | uint8_t *sig; |
283 | 0 | if (signature->len != 132) { |
284 | 0 | size_t split = signature->len / 2; |
285 | |
|
286 | 0 | memcpy(paddedSigData + 66 - split, signature->data, split); |
287 | 0 | memcpy(paddedSigData + 132 - split, signature->data + split, split); |
288 | |
|
289 | 0 | sig = paddedSigData; |
290 | 0 | } else { |
291 | 0 | sig = signature->data; |
292 | 0 | } |
293 | |
|
294 | 0 | uint8_t hash[66] = { 0 }; |
295 | 0 | if (digest->len < 66) { |
296 | 0 | memcpy(hash + 66 - digest->len, digest->data, digest->len); |
297 | 0 | } else { |
298 | | // SEC 1 takes the most significant ceil(log(n)) bits of hash output when the hash output is longer than log(n). |
299 | 0 | hash[0] = digest->data[0] >> 7; |
300 | 0 | for (size_t i = 1; i < 66; i++) { |
301 | 0 | hash[i] = (digest->data[i - 1] << 1) | (digest->data[i] >> 7); |
302 | 0 | } |
303 | 0 | } |
304 | |
|
305 | 0 | #ifndef UNSAFE_FUZZER_MODE |
306 | 0 | bool b = Hacl_P521_ecdsa_verif_without_hash( |
307 | 0 | 66, hash, key->publicValue.data + 1, sig, sig + 66); |
308 | | #else |
309 | | bool b = sig != NULL; /* Avoiding unused variable warnings */ |
310 | | #endif |
311 | |
|
312 | 0 | if (!b) { |
313 | 0 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
314 | 0 | res = SECFailure; |
315 | 0 | return res; |
316 | 0 | } |
317 | | |
318 | 0 | return res; |
319 | 0 | } |