blob: d389799fc059c1440fe61814a84e5cab6d9de052 [file] [log] [blame]
Adam Langley95c29f32014-06-20 12:00:00 -07001/* ====================================================================
2 * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 *
16 * 3. All advertising materials mentioning features or use of this
17 * software must display the following acknowledgment:
18 * "This product includes software developed by the OpenSSL Project
19 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
20 *
21 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
22 * endorse or promote products derived from this software without
23 * prior written permission. For written permission, please contact
24 * openssl-core@OpenSSL.org.
25 *
26 * 5. Products derived from this software may not be called "OpenSSL"
27 * nor may "OpenSSL" appear in their names without prior written
28 * permission of the OpenSSL Project.
29 *
30 * 6. Redistributions of any form whatsoever must retain the following
31 * acknowledgment:
32 * "This product includes software developed by the OpenSSL Project
33 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
34 *
35 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
36 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
44 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
46 * OF THE POSSIBILITY OF SUCH DAMAGE.
47 * ====================================================================
48 *
49 * This product includes cryptographic software written by Eric Young
50 * (eay@cryptsoft.com). This product includes software written by Tim
51 * Hudson (tjh@cryptsoft.com). */
52
53#include <openssl/ecdsa.h>
54
Adam Langley2b2d66d2015-01-30 17:08:37 -080055#include <string.h>
56
Adam Langley95c29f32014-06-20 12:00:00 -070057#include <openssl/bn.h>
58#include <openssl/err.h>
59#include <openssl/mem.h>
60#include <openssl/thread.h>
61
62#include "../ec/internal.h"
63
64
65int ECDSA_sign(int type, const uint8_t *digest, size_t digest_len, uint8_t *sig,
66 unsigned int *sig_len, EC_KEY *eckey) {
67 if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) {
68 return eckey->ecdsa_meth->sign(digest, digest_len, sig, sig_len, eckey);
69 }
70
71 return ECDSA_sign_ex(type, digest, digest_len, sig, sig_len, NULL, NULL,
72 eckey);
73}
74
75int ECDSA_verify(int type, const uint8_t *digest, size_t digest_len,
76 const uint8_t *sig, size_t sig_len, EC_KEY *eckey) {
77 ECDSA_SIG *s;
Adam Langley5129e2d2014-07-25 10:06:44 -070078 int ret = 0;
Adam Langleyca9a5382015-01-08 12:26:55 -080079 uint8_t *der = NULL;
Adam Langley95c29f32014-06-20 12:00:00 -070080
81 if (eckey->ecdsa_meth && eckey->ecdsa_meth->verify) {
82 return eckey->ecdsa_meth->verify(digest, digest_len, sig, sig_len, eckey);
83 }
84
85 s = ECDSA_SIG_new();
Adam Langleyca9a5382015-01-08 12:26:55 -080086 const uint8_t *sigp = sig;
87 if (s == NULL || d2i_ECDSA_SIG(&s, &sigp, sig_len) == NULL ||
88 sigp != sig + sig_len) {
Adam Langley95c29f32014-06-20 12:00:00 -070089 goto err;
90 }
Adam Langleyca9a5382015-01-08 12:26:55 -080091
92 /* Ensure that the signature uses DER and doesn't have trailing garbage. */
93 const int der_len = i2d_ECDSA_SIG(s, &der);
94 if (der_len < 0 || (size_t) der_len != sig_len || memcmp(sig, der, sig_len)) {
95 goto err;
96 }
97
Adam Langley95c29f32014-06-20 12:00:00 -070098 ret = ECDSA_do_verify(digest, digest_len, s, eckey);
99
100err:
Adam Langleyca9a5382015-01-08 12:26:55 -0800101 if (der != NULL) {
102 OPENSSL_free(der);
103 }
Adam Langley95c29f32014-06-20 12:00:00 -0700104 if (s != NULL) {
105 ECDSA_SIG_free(s);
106 }
107 return ret;
108}
109
110/* digest_to_bn interprets |digest_len| bytes from |digest| as a big-endian
111 * number and sets |out| to that value. It then truncates |out| so that it's,
112 * at most, as long as |order|. It returns one on success and zero otherwise. */
113static int digest_to_bn(BIGNUM *out, const uint8_t *digest, size_t digest_len,
114 const BIGNUM *order) {
115 size_t num_bits;
116
117 num_bits = BN_num_bits(order);
118 /* Need to truncate digest if it is too long: first truncate whole
119 * bytes. */
120 if (8 * digest_len > num_bits) {
121 digest_len = (num_bits + 7) / 8;
122 }
123 if (!BN_bin2bn(digest, digest_len, out)) {
124 OPENSSL_PUT_ERROR(ECDSA, digest_to_bn, ERR_R_BN_LIB);
125 return 0;
126 }
127
128 /* If still too long truncate remaining bits with a shift */
129 if ((8 * digest_len > num_bits) &&
130 !BN_rshift(out, out, 8 - (num_bits & 0x7))) {
131 OPENSSL_PUT_ERROR(ECDSA, digest_to_bn, ERR_R_BN_LIB);
132 return 0;
133 }
134
135 return 1;
136}
137
138ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, size_t digest_len,
139 EC_KEY *key) {
140 return ECDSA_do_sign_ex(digest, digest_len, NULL, NULL, key);
141}
142
143int ECDSA_do_verify(const uint8_t *digest, size_t digest_len,
144 const ECDSA_SIG *sig, EC_KEY *eckey) {
Adam Langley5129e2d2014-07-25 10:06:44 -0700145 int ret = 0;
Adam Langley95c29f32014-06-20 12:00:00 -0700146 BN_CTX *ctx;
147 BIGNUM *order, *u1, *u2, *m, *X;
148 EC_POINT *point = NULL;
149 const EC_GROUP *group;
150 const EC_POINT *pub_key;
151
152 if (eckey->ecdsa_meth && eckey->ecdsa_meth->verify) {
David Benjamine09170f2014-07-11 10:55:28 -0400153 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ECDSA_R_NOT_IMPLEMENTED);
Adam Langley5129e2d2014-07-25 10:06:44 -0700154 return 0;
Adam Langley95c29f32014-06-20 12:00:00 -0700155 }
156
157 /* check input values */
Adam Langleyb2cb0ec2014-09-02 14:28:49 -0700158 if ((group = EC_KEY_get0_group(eckey)) == NULL ||
159 (pub_key = EC_KEY_get0_public_key(eckey)) == NULL ||
160 sig == NULL) {
Adam Langley95c29f32014-06-20 12:00:00 -0700161 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ECDSA_R_MISSING_PARAMETERS);
Adam Langley5129e2d2014-07-25 10:06:44 -0700162 return 0;
Adam Langley95c29f32014-06-20 12:00:00 -0700163 }
164
165 ctx = BN_CTX_new();
166 if (!ctx) {
167 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ERR_R_MALLOC_FAILURE);
Adam Langley5129e2d2014-07-25 10:06:44 -0700168 return 0;
Adam Langley95c29f32014-06-20 12:00:00 -0700169 }
170 BN_CTX_start(ctx);
171 order = BN_CTX_get(ctx);
172 u1 = BN_CTX_get(ctx);
173 u2 = BN_CTX_get(ctx);
174 m = BN_CTX_get(ctx);
175 X = BN_CTX_get(ctx);
176 if (!X) {
177 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ERR_R_BN_LIB);
178 goto err;
179 }
180
181 if (!EC_GROUP_get_order(group, order, ctx)) {
182 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ERR_R_EC_LIB);
183 goto err;
184 }
185
186 if (BN_is_zero(sig->r) || BN_is_negative(sig->r) ||
187 BN_ucmp(sig->r, order) >= 0 || BN_is_zero(sig->s) ||
188 BN_is_negative(sig->s) || BN_ucmp(sig->s, order) >= 0) {
189 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ECDSA_R_BAD_SIGNATURE);
190 ret = 0; /* signature is invalid */
191 goto err;
192 }
193 /* calculate tmp1 = inv(S) mod order */
194 if (!BN_mod_inverse(u2, sig->s, order, ctx)) {
195 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ERR_R_BN_LIB);
196 goto err;
197 }
198 if (!digest_to_bn(m, digest, digest_len, order)) {
199 goto err;
200 }
201 /* u1 = m * tmp mod order */
202 if (!BN_mod_mul(u1, m, u2, order, ctx)) {
203 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ERR_R_BN_LIB);
204 goto err;
205 }
206 /* u2 = r * w mod q */
207 if (!BN_mod_mul(u2, sig->r, u2, order, ctx)) {
208 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ERR_R_BN_LIB);
209 goto err;
210 }
211
212 point = EC_POINT_new(group);
213 if (point == NULL) {
214 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ERR_R_MALLOC_FAILURE);
215 goto err;
216 }
217 if (!EC_POINT_mul(group, point, u1, pub_key, u2, ctx)) {
218 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ERR_R_EC_LIB);
219 goto err;
220 }
221 if (!EC_POINT_get_affine_coordinates_GFp(group, point, X, NULL, ctx)) {
222 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ERR_R_EC_LIB);
223 goto err;
224 }
225 if (!BN_nnmod(u1, X, order, ctx)) {
226 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ERR_R_BN_LIB);
227 goto err;
228 }
229 /* if the signature is correct u1 is equal to sig->r */
230 ret = (BN_ucmp(u1, sig->r) == 0);
231
232err:
233 BN_CTX_end(ctx);
234 BN_CTX_free(ctx);
235 if (point) {
236 EC_POINT_free(point);
237 }
238 return ret;
239}
240
Adam Langleyd4b4f082014-06-20 12:00:00 -0700241static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp,
242 BIGNUM **rp, const uint8_t *digest,
243 size_t digest_len) {
Adam Langley95c29f32014-06-20 12:00:00 -0700244 BN_CTX *ctx = NULL;
245 BIGNUM *k = NULL, *r = NULL, *order = NULL, *X = NULL;
246 EC_POINT *tmp_point = NULL;
247 const EC_GROUP *group;
248 int ret = 0;
249
250 if (eckey == NULL || (group = EC_KEY_get0_group(eckey)) == NULL) {
Adam Langleyd4b4f082014-06-20 12:00:00 -0700251 OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_PASSED_NULL_PARAMETER);
Adam Langley95c29f32014-06-20 12:00:00 -0700252 return 0;
253 }
254
255 if (ctx_in == NULL) {
256 if ((ctx = BN_CTX_new()) == NULL) {
Adam Langleyd4b4f082014-06-20 12:00:00 -0700257 OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_MALLOC_FAILURE);
Adam Langley95c29f32014-06-20 12:00:00 -0700258 return 0;
259 }
260 } else {
261 ctx = ctx_in;
262 }
263
264 k = BN_new(); /* this value is later returned in *kinvp */
265 r = BN_new(); /* this value is later returned in *rp */
266 order = BN_new();
267 X = BN_new();
268 if (!k || !r || !order || !X) {
Adam Langleyd4b4f082014-06-20 12:00:00 -0700269 OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_MALLOC_FAILURE);
Adam Langley95c29f32014-06-20 12:00:00 -0700270 goto err;
271 }
272 tmp_point = EC_POINT_new(group);
273 if (tmp_point == NULL) {
Adam Langleyd4b4f082014-06-20 12:00:00 -0700274 OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_EC_LIB);
Adam Langley95c29f32014-06-20 12:00:00 -0700275 goto err;
276 }
277 if (!EC_GROUP_get_order(group, order, ctx)) {
Adam Langleyd4b4f082014-06-20 12:00:00 -0700278 OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_EC_LIB);
Adam Langley95c29f32014-06-20 12:00:00 -0700279 goto err;
280 }
281
282 do {
Adam Langleyd4b4f082014-06-20 12:00:00 -0700283 /* If possible, we'll include the private key and message digest in the k
284 * generation. The |digest| argument is only empty if |ECDSA_sign_setup| is
285 * being used. */
Adam Langley95c29f32014-06-20 12:00:00 -0700286 do {
Adam Langleyd4b4f082014-06-20 12:00:00 -0700287 int ok;
288
289 if (digest_len > 0) {
290 ok = BN_generate_dsa_nonce(k, order, EC_KEY_get0_private_key(eckey),
291 digest, digest_len, ctx);
292 } else {
293 ok = BN_rand_range(k, order);
294 }
295 if (!ok) {
296 OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup,
Adam Langley95c29f32014-06-20 12:00:00 -0700297 ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED);
298 goto err;
299 }
300 } while (BN_is_zero(k));
301
302 /* We do not want timing information to leak the length of k,
303 * so we compute G*k using an equivalent scalar of fixed
304 * bit-length. */
305
306 if (!BN_add(k, k, order)) {
307 goto err;
308 }
309 if (BN_num_bits(k) <= BN_num_bits(order)) {
310 if (!BN_add(k, k, order)) {
311 goto err;
312 }
313 }
314
315 /* compute r the x-coordinate of generator * k */
316 if (!EC_POINT_mul(group, tmp_point, k, NULL, NULL, ctx)) {
Adam Langleyd4b4f082014-06-20 12:00:00 -0700317 OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_EC_LIB);
Adam Langley95c29f32014-06-20 12:00:00 -0700318 goto err;
319 }
320 if (!EC_POINT_get_affine_coordinates_GFp(group, tmp_point, X, NULL, ctx)) {
Adam Langleyd4b4f082014-06-20 12:00:00 -0700321 OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_EC_LIB);
Adam Langley95c29f32014-06-20 12:00:00 -0700322 goto err;
323 }
324
325 if (!BN_nnmod(r, X, order, ctx)) {
Adam Langleyd4b4f082014-06-20 12:00:00 -0700326 OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_BN_LIB);
Adam Langley95c29f32014-06-20 12:00:00 -0700327 goto err;
328 }
329 } while (BN_is_zero(r));
330
331 /* compute the inverse of k */
332 if (!BN_mod_inverse(k, k, order, ctx)) {
Adam Langleyd4b4f082014-06-20 12:00:00 -0700333 OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_BN_LIB);
Adam Langley95c29f32014-06-20 12:00:00 -0700334 goto err;
335 }
336 /* clear old values if necessary */
337 if (*rp != NULL) {
338 BN_clear_free(*rp);
339 }
340 if (*kinvp != NULL) {
341 BN_clear_free(*kinvp);
342 }
343
344 /* save the pre-computed values */
345 *rp = r;
346 *kinvp = k;
347 ret = 1;
348
349err:
350 if (!ret) {
351 if (k != NULL) {
352 BN_clear_free(k);
353 }
354 if (r != NULL) {
355 BN_clear_free(r);
356 }
357 }
358 if (ctx_in == NULL)
359 BN_CTX_free(ctx);
360 if (order != NULL)
361 BN_free(order);
362 if (tmp_point != NULL)
363 EC_POINT_free(tmp_point);
364 if (X)
365 BN_clear_free(X);
366 return ret;
367}
368
Adam Langleyd4b4f082014-06-20 12:00:00 -0700369int ECDSA_sign_setup(EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv, BIGNUM **rp) {
370 return ecdsa_sign_setup(eckey, ctx, kinv, rp, NULL, 0);
371}
372
Adam Langley95c29f32014-06-20 12:00:00 -0700373ECDSA_SIG *ECDSA_do_sign_ex(const uint8_t *digest, size_t digest_len,
374 const BIGNUM *in_kinv, const BIGNUM *in_r,
375 EC_KEY *eckey) {
376 int ok = 0;
377 BIGNUM *kinv = NULL, *s, *m = NULL, *tmp = NULL, *order = NULL;
378 const BIGNUM *ckinv;
379 BN_CTX *ctx = NULL;
380 const EC_GROUP *group;
381 ECDSA_SIG *ret;
382 const BIGNUM *priv_key;
383
384 if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) {
David Benjamine09170f2014-07-11 10:55:28 -0400385 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, ECDSA_R_NOT_IMPLEMENTED);
Adam Langley95c29f32014-06-20 12:00:00 -0700386 return NULL;
387 }
388
389 group = EC_KEY_get0_group(eckey);
390 priv_key = EC_KEY_get0_private_key(eckey);
391
392 if (group == NULL || priv_key == NULL) {
393 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, ERR_R_PASSED_NULL_PARAMETER);
394 return NULL;
395 }
396
397 ret = ECDSA_SIG_new();
398 if (!ret) {
399 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, ERR_R_MALLOC_FAILURE);
400 return NULL;
401 }
402 s = ret->s;
403
404 if ((ctx = BN_CTX_new()) == NULL || (order = BN_new()) == NULL ||
405 (tmp = BN_new()) == NULL || (m = BN_new()) == NULL) {
406 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, ERR_R_MALLOC_FAILURE);
407 goto err;
408 }
409
410 if (!EC_GROUP_get_order(group, order, ctx)) {
411 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, ERR_R_EC_LIB);
412 goto err;
413 }
414 if (!digest_to_bn(m, digest, digest_len, order)) {
415 goto err;
416 }
417 for (;;) {
418 if (in_kinv == NULL || in_r == NULL) {
Adam Langleyd4b4f082014-06-20 12:00:00 -0700419 if (!ecdsa_sign_setup(eckey, ctx, &kinv, &ret->r, digest, digest_len)) {
Adam Langley95c29f32014-06-20 12:00:00 -0700420 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, ERR_R_ECDSA_LIB);
421 goto err;
422 }
423 ckinv = kinv;
424 } else {
425 ckinv = in_kinv;
426 if (BN_copy(ret->r, in_r) == NULL) {
427 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, ERR_R_MALLOC_FAILURE);
428 goto err;
429 }
430 }
431
432 if (!BN_mod_mul(tmp, priv_key, ret->r, order, ctx)) {
433 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, ERR_R_BN_LIB);
434 goto err;
435 }
436 if (!BN_mod_add_quick(s, tmp, m, order)) {
437 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, ERR_R_BN_LIB);
438 goto err;
439 }
440 if (!BN_mod_mul(s, s, ckinv, order, ctx)) {
441 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, ERR_R_BN_LIB);
442 goto err;
443 }
444 if (BN_is_zero(s)) {
445 /* if kinv and r have been supplied by the caller
446 * don't to generate new kinv and r values */
447 if (in_kinv != NULL && in_r != NULL) {
448 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, ECDSA_R_NEED_NEW_SETUP_VALUES);
449 goto err;
450 }
451 } else {
452 /* s != 0 => we have a valid signature */
453 break;
454 }
455 }
456
457 ok = 1;
458
459err:
460 if (!ok) {
461 ECDSA_SIG_free(ret);
462 ret = NULL;
463 }
464 if (ctx)
465 BN_CTX_free(ctx);
466 if (m)
467 BN_clear_free(m);
468 if (tmp)
469 BN_clear_free(tmp);
470 if (order)
471 BN_free(order);
472 if (kinv)
473 BN_clear_free(kinv);
474 return ret;
475}
476
477int ECDSA_sign_ex(int type, const uint8_t *digest, size_t digest_len,
478 uint8_t *sig, unsigned int *sig_len, const BIGNUM *kinv,
479 const BIGNUM *r, EC_KEY *eckey) {
480 ECDSA_SIG *s = NULL;
481
482 if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) {
483 OPENSSL_PUT_ERROR(ECDSA, ECDSA_sign_ex, ECDSA_R_NOT_IMPLEMENTED);
484 *sig_len = 0;
485 return 0;
486 }
487
488 s = ECDSA_do_sign_ex(digest, digest_len, kinv, r, eckey);
489 if (s == NULL) {
490 *sig_len = 0;
491 return 0;
492 }
493 *sig_len = i2d_ECDSA_SIG(s, &sig);
494 ECDSA_SIG_free(s);
495 return 1;
496}