Fix undefined behaviour in shifts.
[openssl.git] / crypto / dh / dh_pmeth.c
1 /*
2  * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
3  * 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 <stdio.h>
60 #include "cryptlib.h"
61 #include <openssl/asn1t.h>
62 #include <openssl/x509.h>
63 #include <openssl/evp.h>
64 #include <openssl/dh.h>
65 #include <openssl/bn.h>
66 #include "evp_locl.h"
67
68 /* DH pkey context structure */
69
70 typedef struct {
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     case EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN:
122         if (p1 < 256)
123             return -2;
124         dctx->prime_len = p1;
125         return 1;
126
127     case EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR:
128         dctx->generator = p1;
129         return 1;
130
131     case EVP_PKEY_CTRL_PEER_KEY:
132         /* Default behaviour is OK */
133         return 1;
134
135     default:
136         return -2;
137
138     }
139 }
140
141 static int pkey_dh_ctrl_str(EVP_PKEY_CTX *ctx,
142                             const char *type, const char *value)
143 {
144     if (!strcmp(type, "dh_paramgen_prime_len")) {
145         int len;
146         len = atoi(value);
147         return EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx, len);
148     }
149     if (!strcmp(type, "dh_paramgen_generator")) {
150         int len;
151         len = atoi(value);
152         return EVP_PKEY_CTX_set_dh_paramgen_generator(ctx, len);
153     }
154     return -2;
155 }
156
157 static int pkey_dh_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
158 {
159     DH *dh = NULL;
160     DH_PKEY_CTX *dctx = ctx->data;
161     BN_GENCB *pcb, cb;
162     int ret;
163     if (ctx->pkey_gencb) {
164         pcb = &cb;
165         evp_pkey_set_cb_translate(pcb, ctx);
166     } else
167         pcb = NULL;
168     dh = DH_new();
169     if (!dh)
170         return 0;
171     ret = DH_generate_parameters_ex(dh,
172                                     dctx->prime_len, dctx->generator, pcb);
173     if (ret)
174         EVP_PKEY_assign_DH(pkey, dh);
175     else
176         DH_free(dh);
177     return ret;
178 }
179
180 static int pkey_dh_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
181 {
182     DH *dh = NULL;
183     if (ctx->pkey == NULL) {
184         DHerr(DH_F_PKEY_DH_KEYGEN, DH_R_NO_PARAMETERS_SET);
185         return 0;
186     }
187     dh = DH_new();
188     if (!dh)
189         return 0;
190     EVP_PKEY_assign_DH(pkey, dh);
191     /* Note: if error return, pkey is freed by parent routine */
192     if (!EVP_PKEY_copy_parameters(pkey, ctx->pkey))
193         return 0;
194     return DH_generate_key(pkey->pkey.dh);
195 }
196
197 static int pkey_dh_derive(EVP_PKEY_CTX *ctx, unsigned char *key,
198                           size_t *keylen)
199 {
200     int ret;
201     if (!ctx->pkey || !ctx->peerkey) {
202         DHerr(DH_F_PKEY_DH_DERIVE, DH_R_KEYS_NOT_SET);
203         return 0;
204     }
205     ret = DH_compute_key(key, ctx->peerkey->pkey.dh->pub_key,
206                          ctx->pkey->pkey.dh);
207     if (ret < 0)
208         return ret;
209     *keylen = ret;
210     return 1;
211 }
212
213 const EVP_PKEY_METHOD dh_pkey_meth = {
214     EVP_PKEY_DH,
215     EVP_PKEY_FLAG_AUTOARGLEN,
216     pkey_dh_init,
217     pkey_dh_copy,
218     pkey_dh_cleanup,
219
220     0,
221     pkey_dh_paramgen,
222
223     0,
224     pkey_dh_keygen,
225
226     0,
227     0,
228
229     0,
230     0,
231
232     0, 0,
233
234     0, 0, 0, 0,
235
236     0, 0,
237
238     0, 0,
239
240     0,
241     pkey_dh_derive,
242
243     pkey_dh_ctrl,
244     pkey_dh_ctrl_str
245 };