]>
Commit | Line | Data |
---|---|---|
4d94ae00 | 1 | /* crypto/ecdsa/ecs_ossl.c */ |
c6700d27 GT |
2 | /* |
3 | * Written by Nils Larsch for the OpenSSL project | |
4 | */ | |
4d94ae00 | 5 | /* ==================================================================== |
c6700d27 | 6 | * Copyright (c) 1998-2004 The OpenSSL Project. All rights reserved. |
4d94ae00 BM |
7 | * |
8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | |
11 | * | |
12 | * 1. Redistributions of source code must retain the above copyright | |
13 | * notice, this list of conditions and the following disclaimer. | |
14 | * | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in | |
17 | * the documentation and/or other materials provided with the | |
18 | * distribution. | |
19 | * | |
20 | * 3. All advertising materials mentioning features or use of this | |
21 | * software must display the following acknowledgment: | |
22 | * "This product includes software developed by the OpenSSL Project | |
23 | * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" | |
24 | * | |
25 | * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to | |
26 | * endorse or promote products derived from this software without | |
27 | * prior written permission. For written permission, please contact | |
28 | * openssl-core@OpenSSL.org. | |
29 | * | |
30 | * 5. Products derived from this software may not be called "OpenSSL" | |
31 | * nor may "OpenSSL" appear in their names without prior written | |
32 | * permission of the OpenSSL Project. | |
33 | * | |
34 | * 6. Redistributions of any form whatsoever must retain the following | |
35 | * acknowledgment: | |
36 | * "This product includes software developed by the OpenSSL Project | |
37 | * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" | |
38 | * | |
39 | * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY | |
40 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
41 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
42 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR | |
43 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
44 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
45 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
46 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
47 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
48 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
49 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
50 | * OF THE POSSIBILITY OF SUCH DAMAGE. | |
51 | * ==================================================================== | |
52 | * | |
53 | * This product includes cryptographic software written by Eric Young | |
54 | * (eay@cryptsoft.com). This product includes software written by Tim | |
55 | * Hudson (tjh@cryptsoft.com). | |
56 | * | |
57 | */ | |
0bee0e62 BM |
58 | |
59 | #include "ecdsa.h" | |
60 | #include <openssl/err.h> | |
14a7cfb3 | 61 | #include <openssl/obj_mac.h> |
4d94ae00 | 62 | |
14a7cfb3 BM |
63 | static ECDSA_SIG *ecdsa_do_sign(const unsigned char *dgst, int dlen, |
64 | EC_KEY *eckey); | |
65 | static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, | |
66 | BIGNUM **rp); | |
67 | static int ecdsa_do_verify(const unsigned char *dgst, int dgst_len, | |
68 | ECDSA_SIG *sig, EC_KEY *eckey); | |
4d94ae00 BM |
69 | |
70 | static ECDSA_METHOD openssl_ecdsa_meth = { | |
14a7cfb3 BM |
71 | "OpenSSL ECDSA method", |
72 | ecdsa_do_sign, | |
73 | ecdsa_sign_setup, | |
74 | ecdsa_do_verify, | |
75 | #if 0 | |
76 | NULL, /* init */ | |
77 | NULL, /* finish */ | |
78 | #endif | |
79 | 0, /* flags */ | |
80 | NULL /* app_data */ | |
4d94ae00 BM |
81 | }; |
82 | ||
83 | const ECDSA_METHOD *ECDSA_OpenSSL(void) | |
84 | { | |
85 | return &openssl_ecdsa_meth; | |
86 | } | |
87 | ||
14a7cfb3 BM |
88 | static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, |
89 | BIGNUM **rp) | |
4d94ae00 BM |
90 | { |
91 | BN_CTX *ctx = NULL; | |
c6700d27 | 92 | BIGNUM *k = NULL, *r = NULL, *order = NULL, *X = NULL; |
4d94ae00 | 93 | EC_POINT *tmp_point=NULL; |
c6700d27 | 94 | EC_GROUP *group; |
14a7cfb3 BM |
95 | int ret = 0; |
96 | if (!eckey || !eckey->group || !eckey->pub_key || !eckey->priv_key) | |
4d94ae00 | 97 | { |
14a7cfb3 | 98 | ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_PASSED_NULL_PARAMETER); |
4d94ae00 BM |
99 | return 0; |
100 | } | |
c6700d27 | 101 | group = eckey->group; |
a74333f9 | 102 | |
4d94ae00 BM |
103 | if (ctx_in == NULL) |
104 | { | |
c6700d27 | 105 | if ((ctx = BN_CTX_new()) == NULL) |
14a7cfb3 | 106 | { |
c6700d27 GT |
107 | ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP,ERR_R_MALLOC_FAILURE); |
108 | return 0; | |
14a7cfb3 | 109 | } |
4d94ae00 BM |
110 | } |
111 | else | |
c6700d27 | 112 | ctx = ctx_in; |
4d94ae00 | 113 | |
c6700d27 GT |
114 | k = BN_new(); /* this value is later returned in *kinvp */ |
115 | r = BN_new(); /* this value is later returned in *rp */ | |
116 | order = BN_new(); | |
117 | X = BN_new(); | |
118 | if (!k || !r || !order || !X) | |
4d94ae00 | 119 | { |
c6700d27 GT |
120 | ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_MALLOC_FAILURE); |
121 | goto err; | |
14a7cfb3 | 122 | } |
c6700d27 | 123 | if ((tmp_point = EC_POINT_new(group)) == NULL) |
14a7cfb3 BM |
124 | { |
125 | ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); | |
4d94ae00 BM |
126 | goto err; |
127 | } | |
c6700d27 | 128 | if (!EC_GROUP_get_order(group, order, ctx)) |
4d94ae00 | 129 | { |
14a7cfb3 | 130 | ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); |
4d94ae00 BM |
131 | goto err; |
132 | } | |
133 | ||
134 | do | |
135 | { | |
136 | /* get random k */ | |
4d94ae00 | 137 | do |
c6700d27 | 138 | if (!BN_rand_range(k, order)) |
4d94ae00 | 139 | { |
14a7cfb3 BM |
140 | ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, |
141 | ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED); | |
4d94ae00 BM |
142 | goto err; |
143 | } | |
c6700d27 | 144 | while (BN_is_zero(k)); |
4d94ae00 BM |
145 | |
146 | /* compute r the x-coordinate of generator * k */ | |
c6700d27 | 147 | if (!EC_POINT_mul(group, tmp_point, k, NULL, NULL, ctx)) |
14a7cfb3 BM |
148 | { |
149 | ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); | |
150 | goto err; | |
151 | } | |
c6700d27 | 152 | if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) == NID_X9_62_prime_field) |
14a7cfb3 | 153 | { |
c6700d27 | 154 | if (!EC_POINT_get_affine_coordinates_GFp(group, |
14a7cfb3 BM |
155 | tmp_point, X, NULL, ctx)) |
156 | { | |
c6700d27 | 157 | ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP,ERR_R_EC_LIB); |
14a7cfb3 BM |
158 | goto err; |
159 | } | |
160 | } | |
161 | else /* NID_X9_62_characteristic_two_field */ | |
162 | { | |
c6700d27 | 163 | if (!EC_POINT_get_affine_coordinates_GF2m(group, |
14a7cfb3 BM |
164 | tmp_point, X, NULL, ctx)) |
165 | { | |
c6700d27 | 166 | ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP,ERR_R_EC_LIB); |
14a7cfb3 BM |
167 | goto err; |
168 | } | |
169 | } | |
c6700d27 | 170 | if (!BN_nnmod(r, X, order, ctx)) |
4d94ae00 | 171 | { |
14a7cfb3 | 172 | ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); |
4d94ae00 BM |
173 | goto err; |
174 | } | |
4d94ae00 BM |
175 | } |
176 | while (BN_is_zero(r)); | |
177 | ||
178 | /* compute the inverse of k */ | |
c6700d27 | 179 | if (!BN_mod_inverse(k, k, order, ctx)) |
14a7cfb3 BM |
180 | { |
181 | ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); | |
182 | goto err; | |
183 | } | |
c6700d27 GT |
184 | /* clear old values if necessary */ |
185 | if (*rp != NULL) | |
4d94ae00 | 186 | BN_clear_free(*rp); |
c6700d27 | 187 | if (*kinvp != NULL) |
4d94ae00 | 188 | BN_clear_free(*kinvp); |
c6700d27 GT |
189 | /* save the pre-computed values */ |
190 | *rp = r; | |
191 | *kinvp = k; | |
4d94ae00 BM |
192 | ret = 1; |
193 | err: | |
194 | if (!ret) | |
195 | { | |
c6700d27 | 196 | if (k != NULL) BN_clear_free(k); |
4d94ae00 BM |
197 | if (r != NULL) BN_clear_free(r); |
198 | } | |
199 | if (ctx_in == NULL) | |
200 | BN_CTX_free(ctx); | |
4d94ae00 | 201 | if (order != NULL) |
c6700d27 | 202 | BN_free(order); |
4d94ae00 BM |
203 | if (tmp_point != NULL) |
204 | EC_POINT_free(tmp_point); | |
c6700d27 GT |
205 | if (X) |
206 | BN_clear_free(X); | |
4d94ae00 BM |
207 | return(ret); |
208 | } | |
209 | ||
210 | ||
14a7cfb3 BM |
211 | static ECDSA_SIG *ecdsa_do_sign(const unsigned char *dgst, int dgst_len, |
212 | EC_KEY *eckey) | |
4d94ae00 | 213 | { |
c6700d27 GT |
214 | int ok = 0; |
215 | BIGNUM *kinv=NULL, *r, *s, *m=NULL,*tmp=NULL,*order=NULL; | |
216 | BN_CTX *ctx = NULL; | |
217 | EC_GROUP *group; | |
218 | ECDSA_SIG *ret; | |
14a7cfb3 BM |
219 | ECDSA_DATA *ecdsa; |
220 | ||
221 | ecdsa = ecdsa_check(eckey); | |
4d94ae00 | 222 | |
c6700d27 | 223 | if (!eckey->group || !eckey->pub_key || !eckey->priv_key || !ecdsa) |
4d94ae00 | 224 | { |
14a7cfb3 | 225 | ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_PASSED_NULL_PARAMETER); |
c6700d27 | 226 | return NULL; |
4d94ae00 | 227 | } |
4d94ae00 | 228 | |
c6700d27 GT |
229 | group = eckey->group; |
230 | ret = ECDSA_SIG_new(); | |
231 | if (!ret) | |
232 | { | |
233 | ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_MALLOC_FAILURE); | |
234 | return NULL; | |
235 | } | |
236 | s = ret->s; | |
237 | ||
14a7cfb3 | 238 | if ((ctx = BN_CTX_new()) == NULL || (order = BN_new()) == NULL || |
c6700d27 | 239 | (tmp = BN_new()) == NULL || (m = BN_new()) == NULL) |
14a7cfb3 BM |
240 | { |
241 | ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_MALLOC_FAILURE); | |
242 | goto err; | |
243 | } | |
4d94ae00 | 244 | |
c6700d27 | 245 | if (!EC_GROUP_get_order(group, order, ctx)) |
4d94ae00 | 246 | { |
14a7cfb3 | 247 | ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_EC_LIB); |
4d94ae00 BM |
248 | goto err; |
249 | } | |
250 | if (dgst_len > BN_num_bytes(order)) | |
251 | { | |
14a7cfb3 BM |
252 | ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, |
253 | ECDSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE); | |
4d94ae00 BM |
254 | goto err; |
255 | } | |
256 | ||
c6700d27 | 257 | if (!BN_bin2bn(dgst, dgst_len, m)) |
14a7cfb3 BM |
258 | { |
259 | ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB); | |
260 | goto err; | |
261 | } | |
4d94ae00 BM |
262 | do |
263 | { | |
14a7cfb3 | 264 | if (ecdsa->kinv == NULL || ecdsa->r == NULL) |
4d94ae00 | 265 | { |
c6700d27 | 266 | if (!ECDSA_sign_setup(eckey, ctx, &kinv, &ret->r)) |
14a7cfb3 | 267 | { |
c6700d27 | 268 | ECDSAerr(ECDSA_F_ECDSA_DO_SIGN,ERR_R_ECDSA_LIB); |
14a7cfb3 BM |
269 | goto err; |
270 | } | |
c6700d27 | 271 | r = ret->r; |
4d94ae00 BM |
272 | } |
273 | else | |
274 | { | |
c6700d27 GT |
275 | BN_free(ret->r); |
276 | kinv = ecdsa->kinv; | |
277 | r = ecdsa->r; | |
278 | ret->r = r; | |
4d94ae00 | 279 | ecdsa->kinv = NULL; |
c6700d27 | 280 | ecdsa->r = NULL; |
4d94ae00 BM |
281 | } |
282 | ||
c6700d27 | 283 | if (!BN_mod_mul(tmp, eckey->priv_key, r, order, ctx)) |
14a7cfb3 BM |
284 | { |
285 | ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB); | |
286 | goto err; | |
287 | } | |
c6700d27 | 288 | if (!BN_mod_add_quick(s, tmp, m, order)) |
14a7cfb3 BM |
289 | { |
290 | ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB); | |
291 | goto err; | |
292 | } | |
c6700d27 | 293 | if (!BN_mod_mul(s, s, kinv, order, ctx)) |
14a7cfb3 BM |
294 | { |
295 | ECDSAerr(ECDSA_F_ECDSA_DO_SIGN, ERR_R_BN_LIB); | |
296 | goto err; | |
297 | } | |
4d94ae00 BM |
298 | } |
299 | while (BN_is_zero(s)); | |
300 | ||
c6700d27 GT |
301 | ok = 1; |
302 | err: | |
303 | if (!ok) | |
3613e6fc BM |
304 | { |
305 | ECDSA_SIG_free(ret); | |
306 | ret = NULL; | |
3613e6fc | 307 | } |
14a7cfb3 BM |
308 | if (ctx) |
309 | BN_CTX_free(ctx); | |
310 | if (m) | |
311 | BN_clear_free(m); | |
312 | if (tmp) | |
313 | BN_clear_free(tmp); | |
314 | if (order) | |
c6700d27 | 315 | BN_free(order); |
14a7cfb3 BM |
316 | if (kinv) |
317 | BN_clear_free(kinv); | |
c6700d27 | 318 | return ret; |
4d94ae00 BM |
319 | } |
320 | ||
14a7cfb3 BM |
321 | static int ecdsa_do_verify(const unsigned char *dgst, int dgst_len, |
322 | ECDSA_SIG *sig, EC_KEY *eckey) | |
4d94ae00 | 323 | { |
14a7cfb3 | 324 | int ret = -1; |
c6700d27 GT |
325 | BN_CTX *ctx; |
326 | BIGNUM *order, *u1, *u2, *m, *X; | |
327 | EC_POINT *point = NULL; | |
328 | EC_GROUP *group; | |
329 | /* check input values */ | |
14a7cfb3 | 330 | if (!eckey || !eckey->group || !eckey->pub_key || !sig) |
4d94ae00 | 331 | { |
14a7cfb3 | 332 | ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ECDSA_R_MISSING_PARAMETERS); |
4d94ae00 BM |
333 | return -1; |
334 | } | |
335 | ||
c6700d27 GT |
336 | group = eckey->group; |
337 | ||
338 | ctx = BN_CTX_new(); | |
339 | if (!ctx) | |
14a7cfb3 BM |
340 | { |
341 | ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_MALLOC_FAILURE); | |
c6700d27 | 342 | return -1; |
14a7cfb3 | 343 | } |
c6700d27 GT |
344 | BN_CTX_start(ctx); |
345 | order = BN_CTX_get(ctx); | |
346 | u1 = BN_CTX_get(ctx); | |
347 | u2 = BN_CTX_get(ctx); | |
348 | m = BN_CTX_get(ctx); | |
349 | X = BN_CTX_get(ctx); | |
350 | if (!X) | |
14a7cfb3 BM |
351 | { |
352 | ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_BN_LIB); | |
353 | goto err; | |
354 | } | |
c6700d27 GT |
355 | |
356 | if (!EC_GROUP_get_order(group, order, ctx)) | |
4d94ae00 | 357 | { |
c6700d27 | 358 | ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_EC_LIB); |
4d94ae00 BM |
359 | goto err; |
360 | } | |
c6700d27 GT |
361 | |
362 | if (BN_is_zero(sig->r) || BN_get_sign(sig->r) || | |
363 | BN_ucmp(sig->r, order) >= 0 || BN_is_zero(sig->s) || | |
364 | BN_get_sign(sig->s) || BN_ucmp(sig->s, order) >= 0) | |
4d94ae00 | 365 | { |
14a7cfb3 | 366 | ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ECDSA_R_BAD_SIGNATURE); |
c6700d27 | 367 | ret = 0; /* signature is invalid */ |
4d94ae00 BM |
368 | goto err; |
369 | } | |
4d94ae00 | 370 | /* calculate tmp1 = inv(S) mod order */ |
c6700d27 | 371 | if (!BN_mod_inverse(u2, sig->s, order, ctx)) |
14a7cfb3 BM |
372 | { |
373 | ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_BN_LIB); | |
374 | goto err; | |
375 | } | |
4d94ae00 | 376 | /* digest -> m */ |
c6700d27 | 377 | if (!BN_bin2bn(dgst, dgst_len, m)) |
14a7cfb3 BM |
378 | { |
379 | ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_BN_LIB); | |
380 | goto err; | |
381 | } | |
4d94ae00 | 382 | /* u1 = m * tmp mod order */ |
c6700d27 | 383 | if (!BN_mod_mul(u1, m, u2, order, ctx)) |
14a7cfb3 BM |
384 | { |
385 | ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_BN_LIB); | |
386 | goto err; | |
387 | } | |
4d94ae00 | 388 | /* u2 = r * w mod q */ |
c6700d27 | 389 | if (!BN_mod_mul(u2, sig->r, u2, order, ctx)) |
14a7cfb3 BM |
390 | { |
391 | ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_BN_LIB); | |
392 | goto err; | |
393 | } | |
4d94ae00 | 394 | |
c6700d27 | 395 | if ((point = EC_POINT_new(group)) == NULL) |
4d94ae00 | 396 | { |
14a7cfb3 | 397 | ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_MALLOC_FAILURE); |
4d94ae00 BM |
398 | goto err; |
399 | } | |
c6700d27 | 400 | if (!EC_POINT_mul(group, point, u1, eckey->pub_key, u2, ctx)) |
4d94ae00 | 401 | { |
14a7cfb3 BM |
402 | ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_EC_LIB); |
403 | goto err; | |
404 | } | |
c6700d27 | 405 | if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) == NID_X9_62_prime_field) |
14a7cfb3 | 406 | { |
c6700d27 | 407 | if (!EC_POINT_get_affine_coordinates_GFp(group, |
14a7cfb3 BM |
408 | point, X, NULL, ctx)) |
409 | { | |
410 | ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); | |
411 | goto err; | |
412 | } | |
413 | } | |
414 | else /* NID_X9_62_characteristic_two_field */ | |
415 | { | |
c6700d27 | 416 | if (!EC_POINT_get_affine_coordinates_GF2m(group, |
14a7cfb3 BM |
417 | point, X, NULL, ctx)) |
418 | { | |
419 | ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); | |
420 | goto err; | |
421 | } | |
422 | } | |
423 | ||
c6700d27 | 424 | if (!BN_nnmod(u1, X, order, ctx)) |
14a7cfb3 BM |
425 | { |
426 | ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ERR_R_BN_LIB); | |
4d94ae00 BM |
427 | goto err; |
428 | } | |
c6700d27 GT |
429 | /* if the signature is correct u1 is equal to sig->r */ |
430 | ret = (BN_ucmp(u1, sig->r) == 0); | |
431 | err: | |
432 | BN_CTX_end(ctx); | |
433 | BN_CTX_free(ctx); | |
14a7cfb3 BM |
434 | if (point) |
435 | EC_POINT_free(point); | |
c6700d27 | 436 | return ret; |
4d94ae00 | 437 | } |