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
10160814Ssimon *    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
59160814Ssimon#include <openssl/engine.h>
60160814Ssimon#endif
61160814Ssimon#include <openssl/err.h>
62160814Ssimon#include <openssl/bn.h>
63238405Sjkim#ifdef OPENSSL_FIPS
64238405Sjkim#include <openssl/fips.h>
65238405Sjkim#endif
66160814Ssimon
67167612Ssimonconst 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 *);
73160814Ssimonstatic void  ecdsa_data_free(void *);
74160814Ssimon
75160814Ssimonvoid ECDSA_set_default_method(const ECDSA_METHOD *meth)
76160814Ssimon{
77160814Ssimon	default_ECDSA_method = meth;
78160814Ssimon}
79160814Ssimon
80160814Ssimonconst ECDSA_METHOD *ECDSA_get_default_method(void)
81160814Ssimon{
82160814Ssimon	if(!default_ECDSA_method)
83238405Sjkim		{
84238405Sjkim#ifdef OPENSSL_FIPS
85238405Sjkim		if (FIPS_mode())
86238405Sjkim			return FIPS_ecdsa_openssl();
87238405Sjkim		else
88238405Sjkim			return ECDSA_OpenSSL();
89238405Sjkim#else
90160814Ssimon		default_ECDSA_method = ECDSA_OpenSSL();
91238405Sjkim#endif
92238405Sjkim		}
93160814Ssimon	return default_ECDSA_method;
94160814Ssimon}
95160814Ssimon
96160814Ssimonint ECDSA_set_method(EC_KEY *eckey, const ECDSA_METHOD *meth)
97160814Ssimon{
98160814Ssimon	ECDSA_DATA *ecdsa;
99160814Ssimon
100160814Ssimon	ecdsa = ecdsa_check(eckey);
101160814Ssimon
102160814Ssimon	if (ecdsa == NULL)
103160814Ssimon		return 0;
104160814Ssimon
105160814Ssimon#ifndef OPENSSL_NO_ENGINE
106160814Ssimon	if (ecdsa->engine)
107160814Ssimon	{
108160814Ssimon		ENGINE_finish(ecdsa->engine);
109160814Ssimon		ecdsa->engine = NULL;
110160814Ssimon	}
111160814Ssimon#endif
112160814Ssimon        ecdsa->meth = meth;
113160814Ssimon
114160814Ssimon        return 1;
115160814Ssimon}
116160814Ssimon
117160814Ssimonstatic ECDSA_DATA *ECDSA_DATA_new_method(ENGINE *engine)
118160814Ssimon{
119160814Ssimon	ECDSA_DATA *ret;
120160814Ssimon
121160814Ssimon	ret=(ECDSA_DATA *)OPENSSL_malloc(sizeof(ECDSA_DATA));
122160814Ssimon	if (ret == NULL)
123160814Ssimon	{
124160814Ssimon		ECDSAerr(ECDSA_F_ECDSA_DATA_NEW_METHOD, ERR_R_MALLOC_FAILURE);
125160814Ssimon		return(NULL);
126160814Ssimon	}
127160814Ssimon
128160814Ssimon	ret->init = NULL;
129160814Ssimon
130160814Ssimon	ret->meth = ECDSA_get_default_method();
131160814Ssimon	ret->engine = engine;
132160814Ssimon#ifndef OPENSSL_NO_ENGINE
133160814Ssimon	if (!ret->engine)
134160814Ssimon		ret->engine = ENGINE_get_default_ECDSA();
135160814Ssimon	if (ret->engine)
136160814Ssimon	{
137160814Ssimon		ret->meth = ENGINE_get_ECDSA(ret->engine);
138160814Ssimon		if (!ret->meth)
139160814Ssimon		{
140160814Ssimon			ECDSAerr(ECDSA_F_ECDSA_DATA_NEW_METHOD, ERR_R_ENGINE_LIB);
141160814Ssimon			ENGINE_finish(ret->engine);
142160814Ssimon			OPENSSL_free(ret);
143160814Ssimon			return NULL;
144160814Ssimon		}
145160814Ssimon	}
146160814Ssimon#endif
147160814Ssimon
148160814Ssimon	ret->flags = ret->meth->flags;
149160814Ssimon	CRYPTO_new_ex_data(CRYPTO_EX_INDEX_ECDSA, ret, &ret->ex_data);
150160814Ssimon#if 0
151160814Ssimon	if ((ret->meth->init != NULL) && !ret->meth->init(ret))
152160814Ssimon	{
153160814Ssimon		CRYPTO_free_ex_data(CRYPTO_EX_INDEX_ECDSA, ret, &ret->ex_data);
154160814Ssimon		OPENSSL_free(ret);
155160814Ssimon		ret=NULL;
156160814Ssimon	}
157160814Ssimon#endif
158160814Ssimon	return(ret);
159160814Ssimon}
160160814Ssimon
161160814Ssimonstatic void *ecdsa_data_new(void)
162160814Ssimon{
163160814Ssimon	return (void *)ECDSA_DATA_new_method(NULL);
164160814Ssimon}
165160814Ssimon
166160814Ssimonstatic void *ecdsa_data_dup(void *data)
167160814Ssimon{
168160814Ssimon	ECDSA_DATA *r = (ECDSA_DATA *)data;
169160814Ssimon
170160814Ssimon	/* XXX: dummy operation */
171160814Ssimon	if (r == NULL)
172160814Ssimon		return NULL;
173160814Ssimon
174160814Ssimon	return ecdsa_data_new();
175160814Ssimon}
176160814Ssimon
177160814Ssimonstatic void ecdsa_data_free(void *data)
178160814Ssimon{
179160814Ssimon	ECDSA_DATA *r = (ECDSA_DATA *)data;
180160814Ssimon
181160814Ssimon#ifndef OPENSSL_NO_ENGINE
182160814Ssimon	if (r->engine)
183160814Ssimon		ENGINE_finish(r->engine);
184160814Ssimon#endif
185160814Ssimon	CRYPTO_free_ex_data(CRYPTO_EX_INDEX_ECDSA, r, &r->ex_data);
186160814Ssimon
187160814Ssimon	OPENSSL_cleanse((void *)r, sizeof(ECDSA_DATA));
188160814Ssimon
189160814Ssimon	OPENSSL_free(r);
190160814Ssimon}
191160814Ssimon
192160814SsimonECDSA_DATA *ecdsa_check(EC_KEY *key)
193160814Ssimon{
194160814Ssimon	ECDSA_DATA *ecdsa_data;
195160814Ssimon
196160814Ssimon	void *data = EC_KEY_get_key_method_data(key, ecdsa_data_dup,
197160814Ssimon					ecdsa_data_free, ecdsa_data_free);
198160814Ssimon	if (data == NULL)
199160814Ssimon	{
200160814Ssimon		ecdsa_data = (ECDSA_DATA *)ecdsa_data_new();
201160814Ssimon		if (ecdsa_data == NULL)
202160814Ssimon			return NULL;
203246772Sjkim		data = EC_KEY_insert_key_method_data(key, (void *)ecdsa_data,
204246772Sjkim			   ecdsa_data_dup, ecdsa_data_free, ecdsa_data_free);
205246772Sjkim		if (data != NULL)
206246772Sjkim			{
207246772Sjkim			/* Another thread raced us to install the key_method
208246772Sjkim			 * data and won. */
209246772Sjkim			ecdsa_data_free(ecdsa_data);
210246772Sjkim			ecdsa_data = (ECDSA_DATA *)data;
211246772Sjkim			}
212160814Ssimon	}
213160814Ssimon	else
214160814Ssimon		ecdsa_data = (ECDSA_DATA *)data;
215238405Sjkim#ifdef OPENSSL_FIPS
216238405Sjkim	if (FIPS_mode() && !(ecdsa_data->flags & ECDSA_FLAG_FIPS_METHOD)
217238405Sjkim			&& !(EC_KEY_get_flags(key) & EC_FLAG_NON_FIPS_ALLOW))
218238405Sjkim		{
219238405Sjkim		ECDSAerr(ECDSA_F_ECDSA_CHECK, ECDSA_R_NON_FIPS_METHOD);
220238405Sjkim		return NULL;
221238405Sjkim		}
222238405Sjkim#endif
223160814Ssimon
224160814Ssimon	return ecdsa_data;
225160814Ssimon}
226160814Ssimon
227160814Ssimonint ECDSA_size(const EC_KEY *r)
228160814Ssimon{
229160814Ssimon	int ret,i;
230160814Ssimon	ASN1_INTEGER bs;
231160814Ssimon	BIGNUM	*order=NULL;
232160814Ssimon	unsigned char buf[4];
233160814Ssimon	const EC_GROUP *group;
234160814Ssimon
235160814Ssimon	if (r == NULL)
236160814Ssimon		return 0;
237160814Ssimon	group = EC_KEY_get0_group(r);
238160814Ssimon	if (group == NULL)
239160814Ssimon		return 0;
240160814Ssimon
241160814Ssimon	if ((order = BN_new()) == NULL) return 0;
242160814Ssimon	if (!EC_GROUP_get_order(group,order,NULL))
243160814Ssimon	{
244160814Ssimon		BN_clear_free(order);
245160814Ssimon		return 0;
246160814Ssimon	}
247160814Ssimon	i=BN_num_bits(order);
248160814Ssimon	bs.length=(i+7)/8;
249160814Ssimon	bs.data=buf;
250160814Ssimon	bs.type=V_ASN1_INTEGER;
251160814Ssimon	/* If the top bit is set the asn1 encoding is 1 larger. */
252160814Ssimon	buf[0]=0xff;
253160814Ssimon
254160814Ssimon	i=i2d_ASN1_INTEGER(&bs,NULL);
255160814Ssimon	i+=i; /* r and s */
256160814Ssimon	ret=ASN1_object_size(1,i,V_ASN1_SEQUENCE);
257160814Ssimon	BN_clear_free(order);
258160814Ssimon	return(ret);
259160814Ssimon}
260160814Ssimon
261160814Ssimon
262160814Ssimonint ECDSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
263160814Ssimon	     CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func)
264160814Ssimon{
265160814Ssimon	return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_ECDSA, argl, argp,
266160814Ssimon				new_func, dup_func, free_func);
267160814Ssimon}
268160814Ssimon
269160814Ssimonint ECDSA_set_ex_data(EC_KEY *d, int idx, void *arg)
270160814Ssimon{
271160814Ssimon	ECDSA_DATA *ecdsa;
272160814Ssimon	ecdsa = ecdsa_check(d);
273160814Ssimon	if (ecdsa == NULL)
274160814Ssimon		return 0;
275160814Ssimon	return(CRYPTO_set_ex_data(&ecdsa->ex_data,idx,arg));
276160814Ssimon}
277160814Ssimon
278160814Ssimonvoid *ECDSA_get_ex_data(EC_KEY *d, int idx)
279160814Ssimon{
280160814Ssimon	ECDSA_DATA *ecdsa;
281160814Ssimon	ecdsa = ecdsa_check(d);
282160814Ssimon	if (ecdsa == NULL)
283160814Ssimon		return NULL;
284160814Ssimon	return(CRYPTO_get_ex_data(&ecdsa->ex_data,idx));
285160814Ssimon}
286