1160814Ssimon/* crypto/ecdsa/ecs_lib.c */
2160814Ssimon/* ====================================================================
3160814Ssimon * Copyright (c) 1998-2005 The OpenSSL Project.  All rights reserved.
4160814Ssimon *
5160814Ssimon * Redistribution and use in source and binary forms, with or without
6160814Ssimon * modification, are permitted provided that the following conditions
7160814Ssimon * are met:
8160814Ssimon *
9160814Ssimon * 1. Redistributions of source code must retain the above copyright
10280304Sjkim *    notice, this list of conditions and the following disclaimer.
11160814Ssimon *
12160814Ssimon * 2. Redistributions in binary form must reproduce the above copyright
13160814Ssimon *    notice, this list of conditions and the following disclaimer in
14160814Ssimon *    the documentation and/or other materials provided with the
15160814Ssimon *    distribution.
16160814Ssimon *
17160814Ssimon * 3. All advertising materials mentioning features or use of this
18160814Ssimon *    software must display the following acknowledgment:
19160814Ssimon *    "This product includes software developed by the OpenSSL Project
20160814Ssimon *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
21160814Ssimon *
22160814Ssimon * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23160814Ssimon *    endorse or promote products derived from this software without
24160814Ssimon *    prior written permission. For written permission, please contact
25160814Ssimon *    openssl-core@OpenSSL.org.
26160814Ssimon *
27160814Ssimon * 5. Products derived from this software may not be called "OpenSSL"
28160814Ssimon *    nor may "OpenSSL" appear in their names without prior written
29160814Ssimon *    permission of the OpenSSL Project.
30160814Ssimon *
31160814Ssimon * 6. Redistributions of any form whatsoever must retain the following
32160814Ssimon *    acknowledgment:
33160814Ssimon *    "This product includes software developed by the OpenSSL Project
34160814Ssimon *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
35160814Ssimon *
36160814Ssimon * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37160814Ssimon * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38160814Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39160814Ssimon * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
40160814Ssimon * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41160814Ssimon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42160814Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43160814Ssimon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44160814Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45160814Ssimon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46160814Ssimon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47160814Ssimon * OF THE POSSIBILITY OF SUCH DAMAGE.
48160814Ssimon * ====================================================================
49160814Ssimon *
50160814Ssimon * This product includes cryptographic software written by Eric Young
51160814Ssimon * (eay@cryptsoft.com).  This product includes software written by Tim
52160814Ssimon * Hudson (tjh@cryptsoft.com).
53160814Ssimon *
54160814Ssimon */
55160814Ssimon
56160814Ssimon#include <string.h>
57160814Ssimon#include "ecs_locl.h"
58160814Ssimon#ifndef OPENSSL_NO_ENGINE
59280304Sjkim# include <openssl/engine.h>
60160814Ssimon#endif
61160814Ssimon#include <openssl/err.h>
62160814Ssimon#include <openssl/bn.h>
63238405Sjkim#ifdef OPENSSL_FIPS
64280304Sjkim# include <openssl/fips.h>
65238405Sjkim#endif
66160814Ssimon
67280304Sjkimconst char ECDSA_version[] = "ECDSA" OPENSSL_VERSION_PTEXT;
68160814Ssimon
69160814Ssimonstatic const ECDSA_METHOD *default_ECDSA_method = NULL;
70160814Ssimon
71160814Ssimonstatic void *ecdsa_data_new(void);
72160814Ssimonstatic void *ecdsa_data_dup(void *);
73280304Sjkimstatic void ecdsa_data_free(void *);
74160814Ssimon
75160814Ssimonvoid ECDSA_set_default_method(const ECDSA_METHOD *meth)
76160814Ssimon{
77280304Sjkim    default_ECDSA_method = meth;
78160814Ssimon}
79160814Ssimon
80160814Ssimonconst ECDSA_METHOD *ECDSA_get_default_method(void)
81160814Ssimon{
82280304Sjkim    if (!default_ECDSA_method) {
83238405Sjkim#ifdef OPENSSL_FIPS
84280304Sjkim        if (FIPS_mode())
85280304Sjkim            return FIPS_ecdsa_openssl();
86280304Sjkim        else
87280304Sjkim            return ECDSA_OpenSSL();
88238405Sjkim#else
89280304Sjkim        default_ECDSA_method = ECDSA_OpenSSL();
90238405Sjkim#endif
91280304Sjkim    }
92280304Sjkim    return default_ECDSA_method;
93160814Ssimon}
94160814Ssimon
95160814Ssimonint ECDSA_set_method(EC_KEY *eckey, const ECDSA_METHOD *meth)
96160814Ssimon{
97280304Sjkim    ECDSA_DATA *ecdsa;
98160814Ssimon
99280304Sjkim    ecdsa = ecdsa_check(eckey);
100160814Ssimon
101280304Sjkim    if (ecdsa == NULL)
102280304Sjkim        return 0;
103160814Ssimon
104160814Ssimon#ifndef OPENSSL_NO_ENGINE
105280304Sjkim    if (ecdsa->engine) {
106280304Sjkim        ENGINE_finish(ecdsa->engine);
107280304Sjkim        ecdsa->engine = NULL;
108280304Sjkim    }
109160814Ssimon#endif
110280304Sjkim    ecdsa->meth = meth;
111160814Ssimon
112280304Sjkim    return 1;
113160814Ssimon}
114160814Ssimon
115160814Ssimonstatic ECDSA_DATA *ECDSA_DATA_new_method(ENGINE *engine)
116160814Ssimon{
117280304Sjkim    ECDSA_DATA *ret;
118160814Ssimon
119280304Sjkim    ret = (ECDSA_DATA *)OPENSSL_malloc(sizeof(ECDSA_DATA));
120280304Sjkim    if (ret == NULL) {
121280304Sjkim        ECDSAerr(ECDSA_F_ECDSA_DATA_NEW_METHOD, ERR_R_MALLOC_FAILURE);
122280304Sjkim        return (NULL);
123280304Sjkim    }
124160814Ssimon
125280304Sjkim    ret->init = NULL;
126160814Ssimon
127280304Sjkim    ret->meth = ECDSA_get_default_method();
128280304Sjkim    ret->engine = engine;
129160814Ssimon#ifndef OPENSSL_NO_ENGINE
130280304Sjkim    if (!ret->engine)
131280304Sjkim        ret->engine = ENGINE_get_default_ECDSA();
132280304Sjkim    if (ret->engine) {
133280304Sjkim        ret->meth = ENGINE_get_ECDSA(ret->engine);
134280304Sjkim        if (!ret->meth) {
135280304Sjkim            ECDSAerr(ECDSA_F_ECDSA_DATA_NEW_METHOD, ERR_R_ENGINE_LIB);
136280304Sjkim            ENGINE_finish(ret->engine);
137280304Sjkim            OPENSSL_free(ret);
138280304Sjkim            return NULL;
139280304Sjkim        }
140280304Sjkim    }
141160814Ssimon#endif
142160814Ssimon
143280304Sjkim    ret->flags = ret->meth->flags;
144280304Sjkim    CRYPTO_new_ex_data(CRYPTO_EX_INDEX_ECDSA, ret, &ret->ex_data);
145160814Ssimon#if 0
146280304Sjkim    if ((ret->meth->init != NULL) && !ret->meth->init(ret)) {
147280304Sjkim        CRYPTO_free_ex_data(CRYPTO_EX_INDEX_ECDSA, ret, &ret->ex_data);
148280304Sjkim        OPENSSL_free(ret);
149280304Sjkim        ret = NULL;
150280304Sjkim    }
151280304Sjkim#endif
152280304Sjkim    return (ret);
153160814Ssimon}
154160814Ssimon
155160814Ssimonstatic void *ecdsa_data_new(void)
156160814Ssimon{
157280304Sjkim    return (void *)ECDSA_DATA_new_method(NULL);
158160814Ssimon}
159160814Ssimon
160160814Ssimonstatic void *ecdsa_data_dup(void *data)
161160814Ssimon{
162280304Sjkim    ECDSA_DATA *r = (ECDSA_DATA *)data;
163160814Ssimon
164280304Sjkim    /* XXX: dummy operation */
165280304Sjkim    if (r == NULL)
166280304Sjkim        return NULL;
167160814Ssimon
168280304Sjkim    return ecdsa_data_new();
169160814Ssimon}
170160814Ssimon
171160814Ssimonstatic void ecdsa_data_free(void *data)
172160814Ssimon{
173280304Sjkim    ECDSA_DATA *r = (ECDSA_DATA *)data;
174160814Ssimon
175160814Ssimon#ifndef OPENSSL_NO_ENGINE
176280304Sjkim    if (r->engine)
177280304Sjkim        ENGINE_finish(r->engine);
178160814Ssimon#endif
179280304Sjkim    CRYPTO_free_ex_data(CRYPTO_EX_INDEX_ECDSA, r, &r->ex_data);
180160814Ssimon
181280304Sjkim    OPENSSL_cleanse((void *)r, sizeof(ECDSA_DATA));
182160814Ssimon
183280304Sjkim    OPENSSL_free(r);
184160814Ssimon}
185160814Ssimon
186160814SsimonECDSA_DATA *ecdsa_check(EC_KEY *key)
187160814Ssimon{
188280304Sjkim    ECDSA_DATA *ecdsa_data;
189280304Sjkim
190280304Sjkim    void *data = EC_KEY_get_key_method_data(key, ecdsa_data_dup,
191280304Sjkim                                            ecdsa_data_free, ecdsa_data_free);
192280304Sjkim    if (data == NULL) {
193280304Sjkim        ecdsa_data = (ECDSA_DATA *)ecdsa_data_new();
194280304Sjkim        if (ecdsa_data == NULL)
195280304Sjkim            return NULL;
196280304Sjkim        data = EC_KEY_insert_key_method_data(key, (void *)ecdsa_data,
197280304Sjkim                                             ecdsa_data_dup, ecdsa_data_free,
198280304Sjkim                                             ecdsa_data_free);
199280304Sjkim        if (data != NULL) {
200280304Sjkim            /*
201280304Sjkim             * Another thread raced us to install the key_method data and
202280304Sjkim             * won.
203280304Sjkim             */
204280304Sjkim            ecdsa_data_free(ecdsa_data);
205280304Sjkim            ecdsa_data = (ECDSA_DATA *)data;
206280304Sjkim        }
207280304Sjkim    } else
208280304Sjkim        ecdsa_data = (ECDSA_DATA *)data;
209238405Sjkim#ifdef OPENSSL_FIPS
210280304Sjkim    if (FIPS_mode() && !(ecdsa_data->flags & ECDSA_FLAG_FIPS_METHOD)
211280304Sjkim        && !(EC_KEY_get_flags(key) & EC_FLAG_NON_FIPS_ALLOW)) {
212280304Sjkim        ECDSAerr(ECDSA_F_ECDSA_CHECK, ECDSA_R_NON_FIPS_METHOD);
213280304Sjkim        return NULL;
214280304Sjkim    }
215238405Sjkim#endif
216160814Ssimon
217280304Sjkim    return ecdsa_data;
218160814Ssimon}
219160814Ssimon
220160814Ssimonint ECDSA_size(const EC_KEY *r)
221160814Ssimon{
222280304Sjkim    int ret, i;
223280304Sjkim    ASN1_INTEGER bs;
224280304Sjkim    BIGNUM *order = NULL;
225280304Sjkim    unsigned char buf[4];
226280304Sjkim    const EC_GROUP *group;
227160814Ssimon
228280304Sjkim    if (r == NULL)
229280304Sjkim        return 0;
230280304Sjkim    group = EC_KEY_get0_group(r);
231280304Sjkim    if (group == NULL)
232280304Sjkim        return 0;
233160814Ssimon
234280304Sjkim    if ((order = BN_new()) == NULL)
235280304Sjkim        return 0;
236280304Sjkim    if (!EC_GROUP_get_order(group, order, NULL)) {
237280304Sjkim        BN_clear_free(order);
238280304Sjkim        return 0;
239280304Sjkim    }
240280304Sjkim    i = BN_num_bits(order);
241280304Sjkim    bs.length = (i + 7) / 8;
242280304Sjkim    bs.data = buf;
243280304Sjkim    bs.type = V_ASN1_INTEGER;
244280304Sjkim    /* If the top bit is set the asn1 encoding is 1 larger. */
245280304Sjkim    buf[0] = 0xff;
246160814Ssimon
247280304Sjkim    i = i2d_ASN1_INTEGER(&bs, NULL);
248280304Sjkim    i += i;                     /* r and s */
249280304Sjkim    ret = ASN1_object_size(1, i, V_ASN1_SEQUENCE);
250280304Sjkim    BN_clear_free(order);
251280304Sjkim    return (ret);
252160814Ssimon}
253160814Ssimon
254160814Ssimonint ECDSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
255280304Sjkim                           CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func)
256160814Ssimon{
257280304Sjkim    return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_ECDSA, argl, argp,
258280304Sjkim                                   new_func, dup_func, free_func);
259160814Ssimon}
260160814Ssimon
261160814Ssimonint ECDSA_set_ex_data(EC_KEY *d, int idx, void *arg)
262160814Ssimon{
263280304Sjkim    ECDSA_DATA *ecdsa;
264280304Sjkim    ecdsa = ecdsa_check(d);
265280304Sjkim    if (ecdsa == NULL)
266280304Sjkim        return 0;
267280304Sjkim    return (CRYPTO_set_ex_data(&ecdsa->ex_data, idx, arg));
268160814Ssimon}
269160814Ssimon
270160814Ssimonvoid *ECDSA_get_ex_data(EC_KEY *d, int idx)
271160814Ssimon{
272280304Sjkim    ECDSA_DATA *ecdsa;
273280304Sjkim    ecdsa = ecdsa_check(d);
274280304Sjkim    if (ecdsa == NULL)
275280304Sjkim        return NULL;
276280304Sjkim    return (CRYPTO_get_ex_data(&ecdsa->ex_data, idx));
277160814Ssimon}
278