1 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
2  * project 2006.
3  */
4 /* ====================================================================
5  * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  *
19  * 3. All advertising materials mentioning features or use of this
20  *    software must display the following acknowledgment:
21  *    "This product includes software developed by the OpenSSL Project
22  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
23  *
24  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
25  *    endorse or promote products derived from this software without
26  *    prior written permission. For written permission, please contact
27  *    licensing@OpenSSL.org.
28  *
29  * 5. Products derived from this software may not be called "OpenSSL"
30  *    nor may "OpenSSL" appear in their names without prior written
31  *    permission of the OpenSSL Project.
32  *
33  * 6. Redistributions of any form whatsoever must retain the following
34  *    acknowledgment:
35  *    "This product includes software developed by the OpenSSL Project
36  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
37  *
38  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
39  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
41  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
42  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
47  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
49  * OF THE POSSIBILITY OF SUCH DAMAGE.
50  * ====================================================================
51  *
52  * This product includes cryptographic software written by Eric Young
53  * (eay@cryptsoft.com).  This product includes software written by Tim
54  * Hudson (tjh@cryptsoft.com).
55  *
56  */
57 
58 #include <stdio.h>
59 #include "cryptlib.h"
60 #include <openssl/asn1t.h>
61 #include <openssl/x509.h>
62 #include <openssl/evp.h>
63 #include <openssl/dh.h>
64 #include <openssl/bn.h>
65 #include "evp_locl.h"
66 
67 /* DH pkey context structure */
68 
69 typedef struct
70 	{
71 	/* Parameter gen parameters */
72 	int prime_len;
73 	int generator;
74 	int use_dsa;
75 	/* Keygen callback info */
76 	int gentmp[2];
77 	/* message digest */
78 	} DH_PKEY_CTX;
79 
80 static int pkey_dh_init(EVP_PKEY_CTX *ctx)
81 	{
82 	DH_PKEY_CTX *dctx;
83 	dctx = OPENSSL_malloc(sizeof(DH_PKEY_CTX));
84 	if (!dctx)
85 		return 0;
86 	dctx->prime_len = 1024;
87 	dctx->generator = 2;
88 	dctx->use_dsa = 0;
89 
90 	ctx->data = dctx;
91 	ctx->keygen_info = dctx->gentmp;
92 	ctx->keygen_info_count = 2;
93 
94 	return 1;
95 	}
96 
97 static int pkey_dh_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
98 	{
99 	DH_PKEY_CTX *dctx, *sctx;
100 	if (!pkey_dh_init(dst))
101 		return 0;
102        	sctx = src->data;
103 	dctx = dst->data;
104 	dctx->prime_len = sctx->prime_len;
105 	dctx->generator = sctx->generator;
106 	dctx->use_dsa = sctx->use_dsa;
107 	return 1;
108 	}
109 
110 static void pkey_dh_cleanup(EVP_PKEY_CTX *ctx)
111 	{
112 	DH_PKEY_CTX *dctx = ctx->data;
113 	if (dctx)
114 		OPENSSL_free(dctx);
115 	}
116 
117 static int pkey_dh_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
118 	{
119 	DH_PKEY_CTX *dctx = ctx->data;
120 	switch (type)
121 		{
122 		case EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN:
123 		if (p1 < 256)
124 			return -2;
125 		dctx->prime_len = p1;
126 		return 1;
127 
128 		case EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR:
129 		dctx->generator = p1;
130 		return 1;
131 
132 		case EVP_PKEY_CTRL_PEER_KEY:
133 		/* Default behaviour is OK */
134 		return 1;
135 
136 		default:
137 		return -2;
138 
139 		}
140 	}
141 
142 
143 static int pkey_dh_ctrl_str(EVP_PKEY_CTX *ctx,
144 			const char *type, const char *value)
145 	{
146 	if (!strcmp(type, "dh_paramgen_prime_len"))
147 		{
148 		int len;
149 		len = atoi(value);
150 		return EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx, len);
151 		}
152 	if (!strcmp(type, "dh_paramgen_generator"))
153 		{
154 		int len;
155 		len = atoi(value);
156 		return EVP_PKEY_CTX_set_dh_paramgen_generator(ctx, len);
157 		}
158 	return -2;
159 	}
160 
161 static int pkey_dh_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
162 	{
163 	DH *dh = NULL;
164 	DH_PKEY_CTX *dctx = ctx->data;
165 	BN_GENCB *pcb, cb;
166 	int ret;
167 	if (ctx->pkey_gencb)
168 		{
169 		pcb = &cb;
170 		evp_pkey_set_cb_translate(pcb, ctx);
171 		}
172 	else
173 		pcb = NULL;
174 	dh = DH_new();
175 	if (!dh)
176 		return 0;
177 	ret = DH_generate_parameters_ex(dh,
178 					dctx->prime_len, dctx->generator, pcb);
179 	if (ret)
180 		EVP_PKEY_assign_DH(pkey, dh);
181 	else
182 		DH_free(dh);
183 	return ret;
184 	}
185 
186 static int pkey_dh_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
187 	{
188 	DH *dh = NULL;
189 	if (ctx->pkey == NULL)
190 		{
191 		DHerr(DH_F_PKEY_DH_KEYGEN, DH_R_NO_PARAMETERS_SET);
192 		return 0;
193 		}
194 	dh = DH_new();
195 	if (!dh)
196 		return 0;
197 	EVP_PKEY_assign_DH(pkey, dh);
198 	/* Note: if error return, pkey is freed by parent routine */
199 	if (!EVP_PKEY_copy_parameters(pkey, ctx->pkey))
200 		return 0;
201 	return DH_generate_key(pkey->pkey.dh);
202 	}
203 
204 static int pkey_dh_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen)
205 	{
206 	int ret;
207 	if (!ctx->pkey || !ctx->peerkey)
208 		{
209 		DHerr(DH_F_PKEY_DH_DERIVE, DH_R_KEYS_NOT_SET);
210 		return 0;
211 		}
212 	ret = DH_compute_key(key, ctx->peerkey->pkey.dh->pub_key,
213 							ctx->pkey->pkey.dh);
214 	if (ret < 0)
215 		return ret;
216 	*keylen = ret;
217 	return 1;
218 	}
219 
220 const EVP_PKEY_METHOD dh_pkey_meth =
221 	{
222 	EVP_PKEY_DH,
223 	EVP_PKEY_FLAG_AUTOARGLEN,
224 	pkey_dh_init,
225 	pkey_dh_copy,
226 	pkey_dh_cleanup,
227 
228 	0,
229 	pkey_dh_paramgen,
230 
231 	0,
232 	pkey_dh_keygen,
233 
234 	0,
235 	0,
236 
237 	0,
238 	0,
239 
240 	0,0,
241 
242 	0,0,0,0,
243 
244 	0,0,
245 
246 	0,0,
247 
248 	0,
249 	pkey_dh_derive,
250 
251 	pkey_dh_ctrl,
252 	pkey_dh_ctrl_str
253 
254 	};
255