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/evp.h>
63238384Sjkim#include <openssl/dh.h>
64238384Sjkim#include <openssl/bn.h>
65238384Sjkim#include "evp_locl.h"
66238384Sjkim
67238384Sjkim/* DH pkey context structure */
68238384Sjkim
69238384Sjkimtypedef struct
70238384Sjkim	{
71238384Sjkim	/* Parameter gen parameters */
72238384Sjkim	int prime_len;
73238384Sjkim	int generator;
74238384Sjkim	int use_dsa;
75238384Sjkim	/* Keygen callback info */
76238384Sjkim	int gentmp[2];
77238384Sjkim	/* message digest */
78238384Sjkim	} DH_PKEY_CTX;
79238384Sjkim
80238384Sjkimstatic int pkey_dh_init(EVP_PKEY_CTX *ctx)
81238384Sjkim	{
82238384Sjkim	DH_PKEY_CTX *dctx;
83238384Sjkim	dctx = OPENSSL_malloc(sizeof(DH_PKEY_CTX));
84238384Sjkim	if (!dctx)
85238384Sjkim		return 0;
86238384Sjkim	dctx->prime_len = 1024;
87238384Sjkim	dctx->generator = 2;
88238384Sjkim	dctx->use_dsa = 0;
89238384Sjkim
90238384Sjkim	ctx->data = dctx;
91238384Sjkim	ctx->keygen_info = dctx->gentmp;
92238384Sjkim	ctx->keygen_info_count = 2;
93238384Sjkim
94238384Sjkim	return 1;
95238384Sjkim	}
96238384Sjkim
97238384Sjkimstatic int pkey_dh_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
98238384Sjkim	{
99238384Sjkim	DH_PKEY_CTX *dctx, *sctx;
100238384Sjkim	if (!pkey_dh_init(dst))
101238384Sjkim		return 0;
102238384Sjkim       	sctx = src->data;
103238384Sjkim	dctx = dst->data;
104238384Sjkim	dctx->prime_len = sctx->prime_len;
105238384Sjkim	dctx->generator = sctx->generator;
106238384Sjkim	dctx->use_dsa = sctx->use_dsa;
107238384Sjkim	return 1;
108238384Sjkim	}
109238384Sjkim
110238384Sjkimstatic void pkey_dh_cleanup(EVP_PKEY_CTX *ctx)
111238384Sjkim	{
112238384Sjkim	DH_PKEY_CTX *dctx = ctx->data;
113238384Sjkim	if (dctx)
114238384Sjkim		OPENSSL_free(dctx);
115238384Sjkim	}
116238384Sjkim
117238384Sjkimstatic int pkey_dh_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
118238384Sjkim	{
119238384Sjkim	DH_PKEY_CTX *dctx = ctx->data;
120238384Sjkim	switch (type)
121238384Sjkim		{
122238384Sjkim		case EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN:
123238384Sjkim		if (p1 < 256)
124238384Sjkim			return -2;
125238384Sjkim		dctx->prime_len = p1;
126238384Sjkim		return 1;
127238384Sjkim
128238384Sjkim		case EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR:
129238384Sjkim		dctx->generator = p1;
130238384Sjkim		return 1;
131238384Sjkim
132238384Sjkim		case EVP_PKEY_CTRL_PEER_KEY:
133238384Sjkim		/* Default behaviour is OK */
134238384Sjkim		return 1;
135238384Sjkim
136238384Sjkim		default:
137238384Sjkim		return -2;
138238384Sjkim
139238384Sjkim		}
140238384Sjkim	}
141238384Sjkim
142238384Sjkim
143238384Sjkimstatic int pkey_dh_ctrl_str(EVP_PKEY_CTX *ctx,
144238384Sjkim			const char *type, const char *value)
145238384Sjkim	{
146238384Sjkim	if (!strcmp(type, "dh_paramgen_prime_len"))
147238384Sjkim		{
148238384Sjkim		int len;
149238384Sjkim		len = atoi(value);
150238384Sjkim		return EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx, len);
151238384Sjkim		}
152238384Sjkim	if (!strcmp(type, "dh_paramgen_generator"))
153238384Sjkim		{
154238384Sjkim		int len;
155238384Sjkim		len = atoi(value);
156238384Sjkim		return EVP_PKEY_CTX_set_dh_paramgen_generator(ctx, len);
157238384Sjkim		}
158238384Sjkim	return -2;
159238384Sjkim	}
160238384Sjkim
161238384Sjkimstatic int pkey_dh_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
162238384Sjkim	{
163238384Sjkim	DH *dh = NULL;
164238384Sjkim	DH_PKEY_CTX *dctx = ctx->data;
165238384Sjkim	BN_GENCB *pcb, cb;
166238384Sjkim	int ret;
167238384Sjkim	if (ctx->pkey_gencb)
168238384Sjkim		{
169238384Sjkim		pcb = &cb;
170238384Sjkim		evp_pkey_set_cb_translate(pcb, ctx);
171238384Sjkim		}
172238384Sjkim	else
173238384Sjkim		pcb = NULL;
174238384Sjkim	dh = DH_new();
175238384Sjkim	if (!dh)
176238384Sjkim		return 0;
177238384Sjkim	ret = DH_generate_parameters_ex(dh,
178238384Sjkim					dctx->prime_len, dctx->generator, pcb);
179238384Sjkim	if (ret)
180238384Sjkim		EVP_PKEY_assign_DH(pkey, dh);
181238384Sjkim	else
182238384Sjkim		DH_free(dh);
183238384Sjkim	return ret;
184238384Sjkim	}
185238384Sjkim
186238384Sjkimstatic int pkey_dh_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
187238384Sjkim	{
188238384Sjkim	DH *dh = NULL;
189238384Sjkim	if (ctx->pkey == NULL)
190238384Sjkim		{
191238384Sjkim		DHerr(DH_F_PKEY_DH_KEYGEN, DH_R_NO_PARAMETERS_SET);
192238384Sjkim		return 0;
193238384Sjkim		}
194238384Sjkim	dh = DH_new();
195238384Sjkim	if (!dh)
196238384Sjkim		return 0;
197238384Sjkim	EVP_PKEY_assign_DH(pkey, dh);
198238384Sjkim	/* Note: if error return, pkey is freed by parent routine */
199238384Sjkim	if (!EVP_PKEY_copy_parameters(pkey, ctx->pkey))
200238384Sjkim		return 0;
201238384Sjkim	return DH_generate_key(pkey->pkey.dh);
202238384Sjkim	}
203238384Sjkim
204238384Sjkimstatic int pkey_dh_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen)
205238384Sjkim	{
206238384Sjkim	int ret;
207238384Sjkim	if (!ctx->pkey || !ctx->peerkey)
208238384Sjkim		{
209238384Sjkim		DHerr(DH_F_PKEY_DH_DERIVE, DH_R_KEYS_NOT_SET);
210238384Sjkim		return 0;
211238384Sjkim		}
212238384Sjkim	ret = DH_compute_key(key, ctx->peerkey->pkey.dh->pub_key,
213238384Sjkim							ctx->pkey->pkey.dh);
214238384Sjkim	if (ret < 0)
215238384Sjkim		return ret;
216238384Sjkim	*keylen = ret;
217238384Sjkim	return 1;
218238384Sjkim	}
219238384Sjkim
220238384Sjkimconst EVP_PKEY_METHOD dh_pkey_meth =
221238384Sjkim	{
222238384Sjkim	EVP_PKEY_DH,
223238384Sjkim	EVP_PKEY_FLAG_AUTOARGLEN,
224238384Sjkim	pkey_dh_init,
225238384Sjkim	pkey_dh_copy,
226238384Sjkim	pkey_dh_cleanup,
227238384Sjkim
228238384Sjkim	0,
229238384Sjkim	pkey_dh_paramgen,
230238384Sjkim
231238384Sjkim	0,
232238384Sjkim	pkey_dh_keygen,
233238384Sjkim
234238384Sjkim	0,
235238384Sjkim	0,
236238384Sjkim
237238384Sjkim	0,
238238384Sjkim	0,
239238384Sjkim
240238384Sjkim	0,0,
241238384Sjkim
242238384Sjkim	0,0,0,0,
243238384Sjkim
244238384Sjkim	0,0,
245238384Sjkim
246238384Sjkim	0,0,
247238384Sjkim
248238384Sjkim	0,
249238384Sjkim	pkey_dh_derive,
250238384Sjkim
251238384Sjkim	pkey_dh_ctrl,
252238384Sjkim	pkey_dh_ctrl_str
253238384Sjkim
254238384Sjkim	};
255