/src/nss-nspr/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 | 44 | { |
22 | 44 | SECStatus res = SECSuccess; |
23 | 44 | if (!pt || !pt->data) { |
24 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
25 | 0 | res = SECFailure; |
26 | 0 | return res; |
27 | 0 | } |
28 | | |
29 | 44 | if (pt->len != 133) { |
30 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
31 | 0 | res = SECFailure; |
32 | 0 | return res; |
33 | 0 | } |
34 | | |
35 | 44 | 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 | 44 | bool b = Hacl_P521_validate_public_key(pt->data + 1); |
42 | | |
43 | 44 | if (!b) { |
44 | 8 | PORT_SetError(SEC_ERROR_BAD_KEY); |
45 | 8 | res = SECFailure; |
46 | 8 | } |
47 | 44 | return res; |
48 | 44 | } |
49 | | |
50 | | /* |
51 | | * Scalar Validation for P-521. |
52 | | */ |
53 | | |
54 | | SECStatus |
55 | | ec_secp521r1_scalar_validate(const SECItem *scalar) |
56 | 1 | { |
57 | 1 | SECStatus res = SECSuccess; |
58 | 1 | if (!scalar || !scalar->data) { |
59 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
60 | 0 | res = SECFailure; |
61 | 0 | return res; |
62 | 0 | } |
63 | | |
64 | 1 | if (scalar->len != 66) { |
65 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
66 | 0 | res = SECFailure; |
67 | 0 | return res; |
68 | 0 | } |
69 | | |
70 | 1 | bool b = Hacl_P521_validate_private_key(scalar->data); |
71 | | |
72 | 1 | if (!b) { |
73 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
74 | 0 | res = SECFailure; |
75 | 0 | } |
76 | 1 | return res; |
77 | 1 | } |
78 | | |
79 | | /* |
80 | | * Scalar multiplication for P-521. |
81 | | * If P == NULL, the base point is used. |
82 | | * Returns X = k*P |
83 | | */ |
84 | | |
85 | | SECStatus |
86 | | ec_secp521r1_pt_mul(SECItem *X, SECItem *k, SECItem *P) |
87 | 67 | { |
88 | 67 | SECStatus res = SECSuccess; |
89 | 67 | if (!P) { |
90 | 67 | uint8_t derived[132] = { 0 }; |
91 | | |
92 | 67 | if (!X || !k || !X->data || !k->data || |
93 | 67 | X->len < 133 || k->len != 66) { |
94 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
95 | 0 | res = SECFailure; |
96 | 0 | return res; |
97 | 0 | } |
98 | | |
99 | 67 | bool b = Hacl_P521_dh_initiator(derived, k->data); |
100 | | |
101 | 67 | if (!b) { |
102 | 8 | PORT_SetError(SEC_ERROR_BAD_KEY); |
103 | 8 | res = SECFailure; |
104 | 8 | return res; |
105 | 8 | } |
106 | | |
107 | 59 | X->len = 133; |
108 | 59 | X->data[0] = EC_POINT_FORM_UNCOMPRESSED; |
109 | 59 | memcpy(X->data + 1, derived, 132); |
110 | | |
111 | 59 | } else { |
112 | 0 | uint8_t full_key[66] = { 0 }; |
113 | 0 | uint8_t *key; |
114 | 0 | uint8_t derived[132] = { 0 }; |
115 | |
|
116 | 0 | if (!X || !k || !P || !X->data || !k->data || !P->data || |
117 | 0 | X->len < 66 || P->len != 133 || |
118 | 0 | P->data[0] != EC_POINT_FORM_UNCOMPRESSED) { |
119 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
120 | 0 | res = SECFailure; |
121 | 0 | return res; |
122 | 0 | } |
123 | | |
124 | | /* We consider keys of up to size 66, or of size 67 with a single leading 0 */ |
125 | 0 | if (k->len < 66) { |
126 | 0 | memcpy(full_key + 66 - k->len, k->data, k->len); |
127 | 0 | key = full_key; |
128 | 0 | } else if (k->len == 66) { |
129 | 0 | key = k->data; |
130 | 0 | } else if (k->len == 67 && k->data[0] == 0) { |
131 | 0 | key = k->data + 1; |
132 | 0 | } else { |
133 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
134 | 0 | res = SECFailure; |
135 | 0 | return res; |
136 | 0 | } |
137 | | |
138 | 0 | bool b = Hacl_P521_dh_responder(derived, P->data + 1, key); |
139 | |
|
140 | 0 | if (!b) { |
141 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
142 | 0 | res = SECFailure; |
143 | 0 | return res; |
144 | 0 | } |
145 | | |
146 | 0 | X->len = 66; |
147 | 0 | memcpy(X->data, derived, 66); |
148 | 0 | } |
149 | | |
150 | 59 | return res; |
151 | 67 | } |
152 | | |
153 | | /* |
154 | | * ECDSA Signature for P-521 |
155 | | */ |
156 | | |
157 | | SECStatus |
158 | | ec_secp521r1_sign_digest(ECPrivateKey *ecPrivKey, SECItem *signature, |
159 | | const SECItem *digest, const unsigned char *kb, |
160 | | const unsigned int kblen) |
161 | 34 | { |
162 | 34 | SECStatus res = SECSuccess; |
163 | | |
164 | 34 | if (!ecPrivKey || !signature || !digest || !kb || |
165 | 34 | !ecPrivKey->privateValue.data || |
166 | 34 | !signature->data || !digest->data || |
167 | 34 | ecPrivKey->ecParams.name != ECCurve_NIST_P521) { |
168 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
169 | 0 | return SECFailure; |
170 | 0 | } |
171 | | |
172 | 34 | if (kblen == 0 || digest->len == 0 || signature->len < 132) { |
173 | 0 | PORT_SetError(SEC_ERROR_INPUT_LEN); |
174 | 0 | return SECFailure; |
175 | 0 | } |
176 | | |
177 | | // Private keys should be 66 bytes, but some software trims leading zeros, |
178 | | // and some software produces 67 byte keys with a leading zero. We'll |
179 | | // accept these variants. |
180 | 34 | uint8_t padded_key_data[66] = { 0 }; |
181 | 34 | uint8_t *key; |
182 | 34 | SECItem *privKey = &ecPrivKey->privateValue; |
183 | 34 | if (privKey->len == 66) { |
184 | 34 | key = privKey->data; |
185 | 34 | } else if (privKey->len == 67 && privKey->data[0] == 0) { |
186 | 0 | key = privKey->data + 1; |
187 | 0 | } else if (privKey->len < 66) { |
188 | 0 | memcpy(padded_key_data + 66 - 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 | 34 | uint8_t hash[66] = { 0 }; |
196 | 34 | if (digest->len < 66) { |
197 | 34 | memcpy(hash + 66 - digest->len, digest->data, digest->len); |
198 | 34 | } else { |
199 | | // SEC 1 takes the most significant ceil(log(n)) bits of hash output when the hash output is longer than log(n). |
200 | 0 | hash[0] = digest->data[0] >> 7; |
201 | 0 | for (size_t i = 1; i < 66; i++) { |
202 | 0 | hash[i] = (digest->data[i - 1] << 1) | (digest->data[i] >> 7); |
203 | 0 | } |
204 | 0 | } |
205 | | |
206 | 34 | uint8_t nonce[66] = { 0 }; |
207 | 34 | if (kblen < 66) { |
208 | 33 | memcpy(nonce + 66 - kblen, kb, kblen); |
209 | 33 | } else { |
210 | 1 | memcpy(nonce, kb, 66); |
211 | 1 | } |
212 | | |
213 | 34 | bool b = Hacl_P521_ecdsa_sign_p521_without_hash( |
214 | 34 | signature->data, 66, hash, key, nonce); |
215 | 34 | if (!b) { |
216 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
217 | 0 | res = SECFailure; |
218 | 0 | return res; |
219 | 0 | } |
220 | | |
221 | 34 | signature->len = 132; |
222 | 34 | return res; |
223 | 34 | } |
224 | | |
225 | | /* |
226 | | * ECDSA Signature Verification for P-521 |
227 | | */ |
228 | | |
229 | | SECStatus |
230 | | ec_secp521r1_verify_digest(ECPublicKey *key, const SECItem *signature, |
231 | | const SECItem *digest) |
232 | 34 | { |
233 | 34 | SECStatus res = SECSuccess; |
234 | | |
235 | 34 | if (!key || !signature || !digest || |
236 | 34 | !key->publicValue.data || |
237 | 34 | !signature->data || !digest->data || |
238 | 34 | key->ecParams.name != ECCurve_NIST_P521) { |
239 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
240 | 0 | res = SECFailure; |
241 | 0 | return res; |
242 | 0 | } |
243 | | |
244 | 34 | if (signature->len == 0 || signature->len % 2 != 0 || |
245 | 34 | signature->len > 132 || digest->len == 0 || |
246 | 34 | key->publicValue.len != 133) { |
247 | 0 | PORT_SetError(SEC_ERROR_INPUT_LEN); |
248 | 0 | res = SECFailure; |
249 | 0 | return res; |
250 | 0 | } |
251 | | |
252 | 34 | 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 | | // Signatures should be 132 bytes, but some software produces short signatures. |
259 | | // Pad components with zeros if necessary. |
260 | 34 | uint8_t paddedSigData[132] = { 0 }; |
261 | 34 | uint8_t *sig; |
262 | 34 | if (signature->len != 132) { |
263 | 0 | size_t split = signature->len / 2; |
264 | |
|
265 | 0 | memcpy(paddedSigData + 66 - split, signature->data, split); |
266 | 0 | memcpy(paddedSigData + 132 - split, signature->data + split, split); |
267 | |
|
268 | 0 | sig = paddedSigData; |
269 | 34 | } else { |
270 | 34 | sig = signature->data; |
271 | 34 | } |
272 | | |
273 | 34 | uint8_t hash[66] = { 0 }; |
274 | 34 | if (digest->len < 66) { |
275 | 34 | memcpy(hash + 66 - digest->len, digest->data, digest->len); |
276 | 34 | } else { |
277 | | // SEC 1 takes the most significant ceil(log(n)) bits of hash output when the hash output is longer than log(n). |
278 | 0 | hash[0] = digest->data[0] >> 7; |
279 | 0 | for (size_t i = 1; i < 66; i++) { |
280 | 0 | hash[i] = (digest->data[i - 1] << 1) | (digest->data[i] >> 7); |
281 | 0 | } |
282 | 0 | } |
283 | | |
284 | 34 | bool b = Hacl_P521_ecdsa_verif_without_hash( |
285 | 34 | 66, hash, key->publicValue.data + 1, sig, sig + 66); |
286 | 34 | if (!b) { |
287 | 0 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
288 | 0 | res = SECFailure; |
289 | 0 | return res; |
290 | 0 | } |
291 | | |
292 | 34 | return res; |
293 | 34 | } |