1238384Sjkim/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
2238384Sjkim * project 2006.
3238384Sjkim */
4238384Sjkim/* ====================================================================
5238384Sjkim * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
6238384Sjkim *
7238384Sjkim * Redistribution and use in source and binary forms, with or without
8238384Sjkim * modification, are permitted provided that the following conditions
9238384Sjkim * are met:
10238384Sjkim *
11238384Sjkim * 1. Redistributions of source code must retain the above copyright
12238384Sjkim *    notice, this list of conditions and the following disclaimer.
13238384Sjkim *
14238384Sjkim * 2. Redistributions in binary form must reproduce the above copyright
15238384Sjkim *    notice, this list of conditions and the following disclaimer in
16238384Sjkim *    the documentation and/or other materials provided with the
17238384Sjkim *    distribution.
18238384Sjkim *
19238384Sjkim * 3. All advertising materials mentioning features or use of this
20238384Sjkim *    software must display the following acknowledgment:
21238384Sjkim *    "This product includes software developed by the OpenSSL Project
22238384Sjkim *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
23238384Sjkim *
24238384Sjkim * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
25238384Sjkim *    endorse or promote products derived from this software without
26238384Sjkim *    prior written permission. For written permission, please contact
27238384Sjkim *    licensing@OpenSSL.org.
28238384Sjkim *
29238384Sjkim * 5. Products derived from this software may not be called "OpenSSL"
30238384Sjkim *    nor may "OpenSSL" appear in their names without prior written
31238384Sjkim *    permission of the OpenSSL Project.
32238384Sjkim *
33238384Sjkim * 6. Redistributions of any form whatsoever must retain the following
34238384Sjkim *    acknowledgment:
35238384Sjkim *    "This product includes software developed by the OpenSSL Project
36238384Sjkim *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
37238384Sjkim *
38238384Sjkim * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
39238384Sjkim * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40238384Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
41238384Sjkim * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
42238384Sjkim * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43238384Sjkim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44238384Sjkim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45238384Sjkim * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46238384Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
47238384Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48238384Sjkim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
49238384Sjkim * OF THE POSSIBILITY OF SUCH DAMAGE.
50238384Sjkim * ====================================================================
51238384Sjkim *
52238384Sjkim * This product includes cryptographic software written by Eric Young
53238384Sjkim * (eay@cryptsoft.com).  This product includes software written by Tim
54238384Sjkim * Hudson (tjh@cryptsoft.com).
55238384Sjkim *
56238384Sjkim */
57238384Sjkim
58238384Sjkim#include <stdio.h>
59238384Sjkim#include "cryptlib.h"
60238384Sjkim#include <openssl/asn1t.h>
61238384Sjkim#include <openssl/x509.h>
62238384Sjkim#include <openssl/ec.h>
63238384Sjkim#include <openssl/ecdsa.h>
64238384Sjkim#include <openssl/evp.h>
65238384Sjkim#include "evp_locl.h"
66238384Sjkim
67238384Sjkim/* EC pkey context structure */
68238384Sjkim
69238384Sjkimtypedef struct
70238384Sjkim	{
71238384Sjkim	/* Key and paramgen group */
72238384Sjkim	EC_GROUP *gen_group;
73238384Sjkim	/* message digest */
74238384Sjkim	const EVP_MD *md;
75238384Sjkim	} EC_PKEY_CTX;
76238384Sjkim
77238384Sjkimstatic int pkey_ec_init(EVP_PKEY_CTX *ctx)
78238384Sjkim	{
79238384Sjkim	EC_PKEY_CTX *dctx;
80238384Sjkim	dctx = OPENSSL_malloc(sizeof(EC_PKEY_CTX));
81238384Sjkim	if (!dctx)
82238384Sjkim		return 0;
83238384Sjkim	dctx->gen_group = NULL;
84238384Sjkim	dctx->md = NULL;
85238384Sjkim
86238384Sjkim	ctx->data = dctx;
87238384Sjkim
88238384Sjkim	return 1;
89238384Sjkim	}
90238384Sjkim
91238384Sjkimstatic int pkey_ec_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
92238384Sjkim	{
93238384Sjkim	EC_PKEY_CTX *dctx, *sctx;
94238384Sjkim	if (!pkey_ec_init(dst))
95238384Sjkim		return 0;
96238384Sjkim       	sctx = src->data;
97238384Sjkim	dctx = dst->data;
98238384Sjkim	if (sctx->gen_group)
99238384Sjkim		{
100238384Sjkim		dctx->gen_group = EC_GROUP_dup(sctx->gen_group);
101238384Sjkim		if (!dctx->gen_group)
102238384Sjkim			return 0;
103238384Sjkim		}
104238384Sjkim	dctx->md = sctx->md;
105238384Sjkim	return 1;
106238384Sjkim	}
107238384Sjkim
108238384Sjkimstatic void pkey_ec_cleanup(EVP_PKEY_CTX *ctx)
109238384Sjkim	{
110238384Sjkim	EC_PKEY_CTX *dctx = ctx->data;
111238384Sjkim	if (dctx)
112238384Sjkim		{
113238384Sjkim		if (dctx->gen_group)
114238384Sjkim			EC_GROUP_free(dctx->gen_group);
115238384Sjkim		OPENSSL_free(dctx);
116238384Sjkim		}
117238384Sjkim	}
118238384Sjkim
119238384Sjkimstatic int pkey_ec_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
120238384Sjkim					const unsigned char *tbs, size_t tbslen)
121238384Sjkim	{
122238384Sjkim	int ret, type;
123238384Sjkim	unsigned int sltmp;
124238384Sjkim	EC_PKEY_CTX *dctx = ctx->data;
125238384Sjkim	EC_KEY *ec = ctx->pkey->pkey.ec;
126238384Sjkim
127238384Sjkim	if (!sig)
128238384Sjkim		{
129238384Sjkim		*siglen = ECDSA_size(ec);
130238384Sjkim		return 1;
131238384Sjkim		}
132238384Sjkim	else if(*siglen < (size_t)ECDSA_size(ec))
133238384Sjkim		{
134238384Sjkim		ECerr(EC_F_PKEY_EC_SIGN, EC_R_BUFFER_TOO_SMALL);
135238384Sjkim		return 0;
136238384Sjkim		}
137238384Sjkim
138238384Sjkim	if (dctx->md)
139238384Sjkim		type = EVP_MD_type(dctx->md);
140238384Sjkim	else
141238384Sjkim		type = NID_sha1;
142238384Sjkim
143238384Sjkim
144238384Sjkim	ret = ECDSA_sign(type, tbs, tbslen, sig, &sltmp, ec);
145238384Sjkim
146238384Sjkim	if (ret <= 0)
147238384Sjkim		return ret;
148238384Sjkim	*siglen = (size_t)sltmp;
149238384Sjkim	return 1;
150238384Sjkim	}
151238384Sjkim
152238384Sjkimstatic int pkey_ec_verify(EVP_PKEY_CTX *ctx,
153238384Sjkim					const unsigned char *sig, size_t siglen,
154238384Sjkim					const unsigned char *tbs, size_t tbslen)
155238384Sjkim	{
156238384Sjkim	int ret, type;
157238384Sjkim	EC_PKEY_CTX *dctx = ctx->data;
158238384Sjkim	EC_KEY *ec = ctx->pkey->pkey.ec;
159238384Sjkim
160238384Sjkim	if (dctx->md)
161238384Sjkim		type = EVP_MD_type(dctx->md);
162238384Sjkim	else
163238384Sjkim		type = NID_sha1;
164238384Sjkim
165238384Sjkim	ret = ECDSA_verify(type, tbs, tbslen, sig, siglen, ec);
166238384Sjkim
167238384Sjkim	return ret;
168238384Sjkim	}
169238384Sjkim
170279264Sdelphij#ifndef OPENSSL_NO_ECDH
171238384Sjkimstatic int pkey_ec_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen)
172238384Sjkim	{
173238384Sjkim	int ret;
174238384Sjkim	size_t outlen;
175238384Sjkim	const EC_POINT *pubkey = NULL;
176238384Sjkim	if (!ctx->pkey || !ctx->peerkey)
177238384Sjkim		{
178238384Sjkim		ECerr(EC_F_PKEY_EC_DERIVE, EC_R_KEYS_NOT_SET);
179238384Sjkim		return 0;
180238384Sjkim		}
181238384Sjkim
182238384Sjkim	if (!key)
183238384Sjkim		{
184238384Sjkim		const EC_GROUP *group;
185238384Sjkim		group = EC_KEY_get0_group(ctx->pkey->pkey.ec);
186238384Sjkim		*keylen = (EC_GROUP_get_degree(group) + 7)/8;
187238384Sjkim		return 1;
188238384Sjkim		}
189238384Sjkim
190238384Sjkim	pubkey = EC_KEY_get0_public_key(ctx->peerkey->pkey.ec);
191238384Sjkim
192246772Sjkim	/* NB: unlike PKCS#3 DH, if *outlen is less than maximum size this is
193238384Sjkim	 * not an error, the result is truncated.
194238384Sjkim	 */
195238384Sjkim
196238384Sjkim	outlen = *keylen;
197238384Sjkim
198238384Sjkim	ret = ECDH_compute_key(key, outlen, pubkey, ctx->pkey->pkey.ec, 0);
199238384Sjkim	if (ret < 0)
200238384Sjkim		return ret;
201238384Sjkim	*keylen = ret;
202238384Sjkim	return 1;
203238384Sjkim	}
204279264Sdelphij#endif
205238384Sjkim
206238384Sjkimstatic int pkey_ec_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
207238384Sjkim	{
208238384Sjkim	EC_PKEY_CTX *dctx = ctx->data;
209238384Sjkim	EC_GROUP *group;
210238384Sjkim	switch (type)
211238384Sjkim		{
212238384Sjkim		case EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID:
213238384Sjkim		group = EC_GROUP_new_by_curve_name(p1);
214238384Sjkim		if (group == NULL)
215238384Sjkim			{
216238384Sjkim			ECerr(EC_F_PKEY_EC_CTRL, EC_R_INVALID_CURVE);
217238384Sjkim			return 0;
218238384Sjkim			}
219238384Sjkim		if (dctx->gen_group)
220238384Sjkim			EC_GROUP_free(dctx->gen_group);
221238384Sjkim		dctx->gen_group = group;
222238384Sjkim		return 1;
223238384Sjkim
224238384Sjkim		case EVP_PKEY_CTRL_MD:
225238384Sjkim		if (EVP_MD_type((const EVP_MD *)p2) != NID_sha1 &&
226238384Sjkim		    EVP_MD_type((const EVP_MD *)p2) != NID_ecdsa_with_SHA1 &&
227238384Sjkim		    EVP_MD_type((const EVP_MD *)p2) != NID_sha224 &&
228238384Sjkim		    EVP_MD_type((const EVP_MD *)p2) != NID_sha256 &&
229238384Sjkim		    EVP_MD_type((const EVP_MD *)p2) != NID_sha384 &&
230238384Sjkim		    EVP_MD_type((const EVP_MD *)p2) != NID_sha512)
231238384Sjkim			{
232238384Sjkim			ECerr(EC_F_PKEY_EC_CTRL, EC_R_INVALID_DIGEST_TYPE);
233238384Sjkim			return 0;
234238384Sjkim			}
235238384Sjkim		dctx->md = p2;
236238384Sjkim		return 1;
237238384Sjkim
238238384Sjkim		case EVP_PKEY_CTRL_PEER_KEY:
239238384Sjkim		/* Default behaviour is OK */
240238384Sjkim		case EVP_PKEY_CTRL_DIGESTINIT:
241238384Sjkim		case EVP_PKEY_CTRL_PKCS7_SIGN:
242238384Sjkim		case EVP_PKEY_CTRL_CMS_SIGN:
243238384Sjkim		return 1;
244238384Sjkim
245238384Sjkim		default:
246238384Sjkim		return -2;
247238384Sjkim
248238384Sjkim		}
249238384Sjkim	}
250238384Sjkim
251238384Sjkimstatic int pkey_ec_ctrl_str(EVP_PKEY_CTX *ctx,
252238384Sjkim			const char *type, const char *value)
253238384Sjkim	{
254238384Sjkim	if (!strcmp(type, "ec_paramgen_curve"))
255238384Sjkim		{
256238384Sjkim		int nid;
257238384Sjkim		nid = OBJ_sn2nid(value);
258238384Sjkim		if (nid == NID_undef)
259238384Sjkim			nid = OBJ_ln2nid(value);
260238384Sjkim		if (nid == NID_undef)
261238384Sjkim			{
262238384Sjkim			ECerr(EC_F_PKEY_EC_CTRL_STR, EC_R_INVALID_CURVE);
263238384Sjkim			return 0;
264238384Sjkim			}
265238384Sjkim		return EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid);
266238384Sjkim		}
267238384Sjkim	return -2;
268238384Sjkim	}
269238384Sjkim
270238384Sjkimstatic int pkey_ec_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
271238384Sjkim	{
272238384Sjkim	EC_KEY *ec = NULL;
273238384Sjkim	EC_PKEY_CTX *dctx = ctx->data;
274238384Sjkim	int ret = 0;
275238384Sjkim	if (dctx->gen_group == NULL)
276238384Sjkim		{
277238384Sjkim		ECerr(EC_F_PKEY_EC_PARAMGEN, EC_R_NO_PARAMETERS_SET);
278238384Sjkim		return 0;
279238384Sjkim		}
280238384Sjkim	ec = EC_KEY_new();
281238384Sjkim	if (!ec)
282238384Sjkim		return 0;
283238384Sjkim	ret = EC_KEY_set_group(ec, dctx->gen_group);
284238384Sjkim	if (ret)
285238384Sjkim		EVP_PKEY_assign_EC_KEY(pkey, ec);
286238384Sjkim	else
287238384Sjkim		EC_KEY_free(ec);
288238384Sjkim	return ret;
289238384Sjkim	}
290238384Sjkim
291238384Sjkimstatic int pkey_ec_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
292238384Sjkim	{
293238384Sjkim	EC_KEY *ec = NULL;
294238384Sjkim	if (ctx->pkey == NULL)
295238384Sjkim		{
296238384Sjkim		ECerr(EC_F_PKEY_EC_KEYGEN, EC_R_NO_PARAMETERS_SET);
297238384Sjkim		return 0;
298238384Sjkim		}
299238384Sjkim	ec = EC_KEY_new();
300238384Sjkim	if (!ec)
301238384Sjkim		return 0;
302238384Sjkim	EVP_PKEY_assign_EC_KEY(pkey, ec);
303238384Sjkim	/* Note: if error return, pkey is freed by parent routine */
304238384Sjkim	if (!EVP_PKEY_copy_parameters(pkey, ctx->pkey))
305238384Sjkim		return 0;
306238384Sjkim	return EC_KEY_generate_key(pkey->pkey.ec);
307238384Sjkim	}
308238384Sjkim
309238384Sjkimconst EVP_PKEY_METHOD ec_pkey_meth =
310238384Sjkim	{
311238384Sjkim	EVP_PKEY_EC,
312238384Sjkim	0,
313238384Sjkim	pkey_ec_init,
314238384Sjkim	pkey_ec_copy,
315238384Sjkim	pkey_ec_cleanup,
316238384Sjkim
317238384Sjkim	0,
318238384Sjkim	pkey_ec_paramgen,
319238384Sjkim
320238384Sjkim	0,
321238384Sjkim	pkey_ec_keygen,
322238384Sjkim
323238384Sjkim	0,
324238384Sjkim	pkey_ec_sign,
325238384Sjkim
326238384Sjkim	0,
327238384Sjkim	pkey_ec_verify,
328238384Sjkim
329238384Sjkim	0,0,
330238384Sjkim
331238384Sjkim	0,0,0,0,
332238384Sjkim
333238384Sjkim	0,0,
334238384Sjkim
335238384Sjkim	0,0,
336238384Sjkim
337238384Sjkim	0,
338279264Sdelphij#ifndef OPENSSL_NO_ECDH
339238384Sjkim	pkey_ec_derive,
340279264Sdelphij#else
341279264Sdelphij	0,
342279264Sdelphij#endif
343238384Sjkim
344238384Sjkim	pkey_ec_ctrl,
345238384Sjkim	pkey_ec_ctrl_str
346238384Sjkim
347238384Sjkim	};
348