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