1160814Ssimon/* crypto/ecdh/ech_lib.c */
2160814Ssimon/* ====================================================================
3160814Ssimon * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
4160814Ssimon *
5160814Ssimon * The Elliptic Curve Public-Key Crypto Library (ECC Code) included
6160814Ssimon * herein is developed by SUN MICROSYSTEMS, INC., and is contributed
7160814Ssimon * to the OpenSSL project.
8160814Ssimon *
9160814Ssimon * The ECC Code is licensed pursuant to the OpenSSL open source
10160814Ssimon * license provided below.
11160814Ssimon *
12160814Ssimon * The ECDH software is originally written by Douglas Stebila of
13160814Ssimon * Sun Microsystems Laboratories.
14160814Ssimon *
15160814Ssimon */
16160814Ssimon/* ====================================================================
17160814Ssimon * Copyright (c) 1998-2003 The OpenSSL Project.  All rights reserved.
18160814Ssimon *
19160814Ssimon * Redistribution and use in source and binary forms, with or without
20160814Ssimon * modification, are permitted provided that the following conditions
21160814Ssimon * are met:
22160814Ssimon *
23160814Ssimon * 1. Redistributions of source code must retain the above copyright
24160814Ssimon *    notice, this list of conditions and the following disclaimer.
25160814Ssimon *
26160814Ssimon * 2. Redistributions in binary form must reproduce the above copyright
27160814Ssimon *    notice, this list of conditions and the following disclaimer in
28160814Ssimon *    the documentation and/or other materials provided with the
29160814Ssimon *    distribution.
30160814Ssimon *
31160814Ssimon * 3. All advertising materials mentioning features or use of this
32160814Ssimon *    software must display the following acknowledgment:
33160814Ssimon *    "This product includes software developed by the OpenSSL Project
34160814Ssimon *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
35160814Ssimon *
36160814Ssimon * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
37160814Ssimon *    endorse or promote products derived from this software without
38160814Ssimon *    prior written permission. For written permission, please contact
39160814Ssimon *    openssl-core@OpenSSL.org.
40160814Ssimon *
41160814Ssimon * 5. Products derived from this software may not be called "OpenSSL"
42160814Ssimon *    nor may "OpenSSL" appear in their names without prior written
43160814Ssimon *    permission of the OpenSSL Project.
44160814Ssimon *
45160814Ssimon * 6. Redistributions of any form whatsoever must retain the following
46160814Ssimon *    acknowledgment:
47160814Ssimon *    "This product includes software developed by the OpenSSL Project
48160814Ssimon *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
49160814Ssimon *
50160814Ssimon * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
51160814Ssimon * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52160814Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53160814Ssimon * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
54160814Ssimon * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
55160814Ssimon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
56160814Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
57160814Ssimon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58160814Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
59160814Ssimon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
60160814Ssimon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
61160814Ssimon * OF THE POSSIBILITY OF SUCH DAMAGE.
62160814Ssimon * ====================================================================
63160814Ssimon *
64160814Ssimon * This product includes cryptographic software written by Eric Young
65160814Ssimon * (eay@cryptsoft.com).  This product includes software written by Tim
66160814Ssimon * Hudson (tjh@cryptsoft.com).
67160814Ssimon *
68160814Ssimon */
69160814Ssimon
70160814Ssimon#include "ech_locl.h"
71160814Ssimon#include <string.h>
72160814Ssimon#ifndef OPENSSL_NO_ENGINE
73160814Ssimon#include <openssl/engine.h>
74160814Ssimon#endif
75160814Ssimon#include <openssl/err.h>
76238405Sjkim#ifdef OPENSSL_FIPS
77238405Sjkim#include <openssl/fips.h>
78238405Sjkim#endif
79160814Ssimon
80167612Ssimonconst char ECDH_version[]="ECDH" OPENSSL_VERSION_PTEXT;
81160814Ssimon
82160814Ssimonstatic const ECDH_METHOD *default_ECDH_method = NULL;
83160814Ssimon
84160814Ssimonstatic void *ecdh_data_new(void);
85160814Ssimonstatic void *ecdh_data_dup(void *);
86160814Ssimonstatic void  ecdh_data_free(void *);
87160814Ssimon
88160814Ssimonvoid ECDH_set_default_method(const ECDH_METHOD *meth)
89160814Ssimon	{
90160814Ssimon	default_ECDH_method = meth;
91160814Ssimon	}
92160814Ssimon
93160814Ssimonconst ECDH_METHOD *ECDH_get_default_method(void)
94160814Ssimon	{
95160814Ssimon	if(!default_ECDH_method)
96238405Sjkim		{
97238405Sjkim#ifdef OPENSSL_FIPS
98238405Sjkim		if (FIPS_mode())
99238405Sjkim			return FIPS_ecdh_openssl();
100238405Sjkim		else
101238405Sjkim			return ECDH_OpenSSL();
102238405Sjkim#else
103160814Ssimon		default_ECDH_method = ECDH_OpenSSL();
104238405Sjkim#endif
105238405Sjkim		}
106160814Ssimon	return default_ECDH_method;
107160814Ssimon	}
108160814Ssimon
109160814Ssimonint ECDH_set_method(EC_KEY *eckey, const ECDH_METHOD *meth)
110160814Ssimon	{
111160814Ssimon	ECDH_DATA *ecdh;
112160814Ssimon
113160814Ssimon	ecdh = ecdh_check(eckey);
114160814Ssimon
115160814Ssimon	if (ecdh == NULL)
116160814Ssimon		return 0;
117160814Ssimon
118238405Sjkim#if 0
119238405Sjkim        mtmp = ecdh->meth;
120238405Sjkim        if (mtmp->finish)
121238405Sjkim		mtmp->finish(eckey);
122238405Sjkim#endif
123160814Ssimon#ifndef OPENSSL_NO_ENGINE
124160814Ssimon	if (ecdh->engine)
125160814Ssimon		{
126160814Ssimon		ENGINE_finish(ecdh->engine);
127160814Ssimon		ecdh->engine = NULL;
128160814Ssimon		}
129160814Ssimon#endif
130160814Ssimon        ecdh->meth = meth;
131160814Ssimon#if 0
132160814Ssimon        if (meth->init)
133160814Ssimon		meth->init(eckey);
134160814Ssimon#endif
135160814Ssimon        return 1;
136160814Ssimon	}
137160814Ssimon
138160814Ssimonstatic ECDH_DATA *ECDH_DATA_new_method(ENGINE *engine)
139160814Ssimon	{
140160814Ssimon	ECDH_DATA *ret;
141160814Ssimon
142160814Ssimon	ret=(ECDH_DATA *)OPENSSL_malloc(sizeof(ECDH_DATA));
143160814Ssimon	if (ret == NULL)
144160814Ssimon		{
145160814Ssimon		ECDHerr(ECDH_F_ECDH_DATA_NEW_METHOD, ERR_R_MALLOC_FAILURE);
146160814Ssimon		return(NULL);
147160814Ssimon		}
148160814Ssimon
149160814Ssimon	ret->init = NULL;
150160814Ssimon
151160814Ssimon	ret->meth = ECDH_get_default_method();
152160814Ssimon	ret->engine = engine;
153160814Ssimon#ifndef OPENSSL_NO_ENGINE
154160814Ssimon	if (!ret->engine)
155160814Ssimon		ret->engine = ENGINE_get_default_ECDH();
156160814Ssimon	if (ret->engine)
157160814Ssimon		{
158160814Ssimon		ret->meth = ENGINE_get_ECDH(ret->engine);
159160814Ssimon		if (!ret->meth)
160160814Ssimon			{
161160814Ssimon			ECDHerr(ECDH_F_ECDH_DATA_NEW_METHOD, ERR_R_ENGINE_LIB);
162160814Ssimon			ENGINE_finish(ret->engine);
163160814Ssimon			OPENSSL_free(ret);
164160814Ssimon			return NULL;
165160814Ssimon			}
166160814Ssimon		}
167160814Ssimon#endif
168160814Ssimon
169160814Ssimon	ret->flags = ret->meth->flags;
170160814Ssimon	CRYPTO_new_ex_data(CRYPTO_EX_INDEX_ECDH, ret, &ret->ex_data);
171160814Ssimon#if 0
172160814Ssimon	if ((ret->meth->init != NULL) && !ret->meth->init(ret))
173160814Ssimon		{
174160814Ssimon		CRYPTO_free_ex_data(CRYPTO_EX_INDEX_ECDH, ret, &ret->ex_data);
175160814Ssimon		OPENSSL_free(ret);
176160814Ssimon		ret=NULL;
177160814Ssimon		}
178160814Ssimon#endif
179160814Ssimon	return(ret);
180160814Ssimon	}
181160814Ssimon
182160814Ssimonstatic void *ecdh_data_new(void)
183160814Ssimon	{
184160814Ssimon	return (void *)ECDH_DATA_new_method(NULL);
185160814Ssimon	}
186160814Ssimon
187160814Ssimonstatic void *ecdh_data_dup(void *data)
188160814Ssimon{
189160814Ssimon	ECDH_DATA *r = (ECDH_DATA *)data;
190160814Ssimon
191160814Ssimon	/* XXX: dummy operation */
192160814Ssimon	if (r == NULL)
193160814Ssimon		return NULL;
194160814Ssimon
195160814Ssimon	return (void *)ecdh_data_new();
196160814Ssimon}
197160814Ssimon
198160814Ssimonvoid ecdh_data_free(void *data)
199160814Ssimon	{
200160814Ssimon	ECDH_DATA *r = (ECDH_DATA *)data;
201160814Ssimon
202160814Ssimon#ifndef OPENSSL_NO_ENGINE
203160814Ssimon	if (r->engine)
204160814Ssimon		ENGINE_finish(r->engine);
205160814Ssimon#endif
206160814Ssimon
207160814Ssimon	CRYPTO_free_ex_data(CRYPTO_EX_INDEX_ECDH, r, &r->ex_data);
208160814Ssimon
209160814Ssimon	OPENSSL_cleanse((void *)r, sizeof(ECDH_DATA));
210160814Ssimon
211160814Ssimon	OPENSSL_free(r);
212160814Ssimon	}
213160814Ssimon
214160814SsimonECDH_DATA *ecdh_check(EC_KEY *key)
215160814Ssimon	{
216160814Ssimon	ECDH_DATA *ecdh_data;
217160814Ssimon
218160814Ssimon	void *data = EC_KEY_get_key_method_data(key, ecdh_data_dup,
219160814Ssimon					ecdh_data_free, ecdh_data_free);
220160814Ssimon	if (data == NULL)
221160814Ssimon	{
222160814Ssimon		ecdh_data = (ECDH_DATA *)ecdh_data_new();
223160814Ssimon		if (ecdh_data == NULL)
224160814Ssimon			return NULL;
225246772Sjkim		data = EC_KEY_insert_key_method_data(key, (void *)ecdh_data,
226246772Sjkim			   ecdh_data_dup, ecdh_data_free, ecdh_data_free);
227246772Sjkim		if (data != NULL)
228246772Sjkim			{
229246772Sjkim			/* Another thread raced us to install the key_method
230246772Sjkim			 * data and won. */
231246772Sjkim			ecdh_data_free(ecdh_data);
232246772Sjkim			ecdh_data = (ECDH_DATA *)data;
233246772Sjkim			}
234160814Ssimon	}
235160814Ssimon	else
236160814Ssimon		ecdh_data = (ECDH_DATA *)data;
237238405Sjkim#ifdef OPENSSL_FIPS
238238405Sjkim	if (FIPS_mode() && !(ecdh_data->flags & ECDH_FLAG_FIPS_METHOD)
239238405Sjkim			&& !(EC_KEY_get_flags(key) & EC_FLAG_NON_FIPS_ALLOW))
240238405Sjkim		{
241238405Sjkim		ECDHerr(ECDH_F_ECDH_CHECK, ECDH_R_NON_FIPS_METHOD);
242238405Sjkim		return NULL;
243238405Sjkim		}
244238405Sjkim#endif
245160814Ssimon
246160814Ssimon
247160814Ssimon	return ecdh_data;
248160814Ssimon	}
249160814Ssimon
250160814Ssimonint ECDH_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
251160814Ssimon	     CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func)
252160814Ssimon	{
253160814Ssimon	return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_ECDH, argl, argp,
254160814Ssimon				new_func, dup_func, free_func);
255160814Ssimon	}
256160814Ssimon
257160814Ssimonint ECDH_set_ex_data(EC_KEY *d, int idx, void *arg)
258160814Ssimon	{
259160814Ssimon	ECDH_DATA *ecdh;
260160814Ssimon	ecdh = ecdh_check(d);
261160814Ssimon	if (ecdh == NULL)
262160814Ssimon		return 0;
263160814Ssimon	return(CRYPTO_set_ex_data(&ecdh->ex_data,idx,arg));
264160814Ssimon	}
265160814Ssimon
266160814Ssimonvoid *ECDH_get_ex_data(EC_KEY *d, int idx)
267160814Ssimon	{
268160814Ssimon	ECDH_DATA *ecdh;
269160814Ssimon	ecdh = ecdh_check(d);
270160814Ssimon	if (ecdh == NULL)
271160814Ssimon		return NULL;
272160814Ssimon	return(CRYPTO_get_ex_data(&ecdh->ex_data,idx));
273160814Ssimon	}
274