1280304Sjkim/*
2280304Sjkim * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
3280304Sjkim * 2006.
4238384Sjkim */
5238384Sjkim/* ====================================================================
6238384Sjkim * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
7238384Sjkim *
8238384Sjkim * Redistribution and use in source and binary forms, with or without
9238384Sjkim * modification, are permitted provided that the following conditions
10238384Sjkim * are met:
11238384Sjkim *
12238384Sjkim * 1. Redistributions of source code must retain the above copyright
13280304Sjkim *    notice, this list of conditions and the following disclaimer.
14238384Sjkim *
15238384Sjkim * 2. Redistributions in binary form must reproduce the above copyright
16238384Sjkim *    notice, this list of conditions and the following disclaimer in
17238384Sjkim *    the documentation and/or other materials provided with the
18238384Sjkim *    distribution.
19238384Sjkim *
20238384Sjkim * 3. All advertising materials mentioning features or use of this
21238384Sjkim *    software must display the following acknowledgment:
22238384Sjkim *    "This product includes software developed by the OpenSSL Project
23238384Sjkim *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24238384Sjkim *
25238384Sjkim * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26238384Sjkim *    endorse or promote products derived from this software without
27238384Sjkim *    prior written permission. For written permission, please contact
28238384Sjkim *    licensing@OpenSSL.org.
29238384Sjkim *
30238384Sjkim * 5. Products derived from this software may not be called "OpenSSL"
31238384Sjkim *    nor may "OpenSSL" appear in their names without prior written
32238384Sjkim *    permission of the OpenSSL Project.
33238384Sjkim *
34238384Sjkim * 6. Redistributions of any form whatsoever must retain the following
35238384Sjkim *    acknowledgment:
36238384Sjkim *    "This product includes software developed by the OpenSSL Project
37238384Sjkim *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38238384Sjkim *
39238384Sjkim * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40238384Sjkim * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41238384Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42238384Sjkim * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43238384Sjkim * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44238384Sjkim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45238384Sjkim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46238384Sjkim * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47238384Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48238384Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49238384Sjkim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50238384Sjkim * OF THE POSSIBILITY OF SUCH DAMAGE.
51238384Sjkim * ====================================================================
52238384Sjkim *
53238384Sjkim * This product includes cryptographic software written by Eric Young
54238384Sjkim * (eay@cryptsoft.com).  This product includes software written by Tim
55238384Sjkim * Hudson (tjh@cryptsoft.com).
56238384Sjkim *
57238384Sjkim */
58238384Sjkim
59238384Sjkim#include <stdio.h>
60238384Sjkim#include "cryptlib.h"
61238384Sjkim#include <openssl/asn1t.h>
62238384Sjkim#include <openssl/x509.h>
63238384Sjkim#include <openssl/evp.h>
64238384Sjkim#include <openssl/dh.h>
65238384Sjkim#include <openssl/bn.h>
66238384Sjkim#include "evp_locl.h"
67238384Sjkim
68238384Sjkim/* DH pkey context structure */
69238384Sjkim
70280304Sjkimtypedef struct {
71280304Sjkim    /* Parameter gen parameters */
72280304Sjkim    int prime_len;
73280304Sjkim    int generator;
74280304Sjkim    int use_dsa;
75280304Sjkim    /* Keygen callback info */
76280304Sjkim    int gentmp[2];
77280304Sjkim    /* message digest */
78280304Sjkim} DH_PKEY_CTX;
79238384Sjkim
80238384Sjkimstatic int pkey_dh_init(EVP_PKEY_CTX *ctx)
81280304Sjkim{
82280304Sjkim    DH_PKEY_CTX *dctx;
83280304Sjkim    dctx = OPENSSL_malloc(sizeof(DH_PKEY_CTX));
84280304Sjkim    if (!dctx)
85280304Sjkim        return 0;
86280304Sjkim    dctx->prime_len = 1024;
87280304Sjkim    dctx->generator = 2;
88280304Sjkim    dctx->use_dsa = 0;
89238384Sjkim
90280304Sjkim    ctx->data = dctx;
91280304Sjkim    ctx->keygen_info = dctx->gentmp;
92280304Sjkim    ctx->keygen_info_count = 2;
93238384Sjkim
94280304Sjkim    return 1;
95280304Sjkim}
96280304Sjkim
97238384Sjkimstatic int pkey_dh_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
98280304Sjkim{
99280304Sjkim    DH_PKEY_CTX *dctx, *sctx;
100280304Sjkim    if (!pkey_dh_init(dst))
101280304Sjkim        return 0;
102280304Sjkim    sctx = src->data;
103280304Sjkim    dctx = dst->data;
104280304Sjkim    dctx->prime_len = sctx->prime_len;
105280304Sjkim    dctx->generator = sctx->generator;
106280304Sjkim    dctx->use_dsa = sctx->use_dsa;
107280304Sjkim    return 1;
108280304Sjkim}
109238384Sjkim
110238384Sjkimstatic void pkey_dh_cleanup(EVP_PKEY_CTX *ctx)
111280304Sjkim{
112280304Sjkim    DH_PKEY_CTX *dctx = ctx->data;
113280304Sjkim    if (dctx)
114280304Sjkim        OPENSSL_free(dctx);
115280304Sjkim}
116238384Sjkim
117238384Sjkimstatic int pkey_dh_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
118280304Sjkim{
119280304Sjkim    DH_PKEY_CTX *dctx = ctx->data;
120280304Sjkim    switch (type) {
121280304Sjkim    case EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN:
122280304Sjkim        if (p1 < 256)
123280304Sjkim            return -2;
124280304Sjkim        dctx->prime_len = p1;
125280304Sjkim        return 1;
126238384Sjkim
127280304Sjkim    case EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR:
128280304Sjkim        dctx->generator = p1;
129280304Sjkim        return 1;
130238384Sjkim
131280304Sjkim    case EVP_PKEY_CTRL_PEER_KEY:
132280304Sjkim        /* Default behaviour is OK */
133280304Sjkim        return 1;
134238384Sjkim
135280304Sjkim    default:
136280304Sjkim        return -2;
137238384Sjkim
138280304Sjkim    }
139280304Sjkim}
140238384Sjkim
141238384Sjkimstatic int pkey_dh_ctrl_str(EVP_PKEY_CTX *ctx,
142280304Sjkim                            const char *type, const char *value)
143280304Sjkim{
144280304Sjkim    if (!strcmp(type, "dh_paramgen_prime_len")) {
145280304Sjkim        int len;
146280304Sjkim        len = atoi(value);
147280304Sjkim        return EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx, len);
148280304Sjkim    }
149280304Sjkim    if (!strcmp(type, "dh_paramgen_generator")) {
150280304Sjkim        int len;
151280304Sjkim        len = atoi(value);
152280304Sjkim        return EVP_PKEY_CTX_set_dh_paramgen_generator(ctx, len);
153280304Sjkim    }
154280304Sjkim    return -2;
155280304Sjkim}
156238384Sjkim
157238384Sjkimstatic int pkey_dh_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
158280304Sjkim{
159280304Sjkim    DH *dh = NULL;
160280304Sjkim    DH_PKEY_CTX *dctx = ctx->data;
161280304Sjkim    BN_GENCB *pcb, cb;
162280304Sjkim    int ret;
163280304Sjkim    if (ctx->pkey_gencb) {
164280304Sjkim        pcb = &cb;
165280304Sjkim        evp_pkey_set_cb_translate(pcb, ctx);
166280304Sjkim    } else
167280304Sjkim        pcb = NULL;
168280304Sjkim    dh = DH_new();
169280304Sjkim    if (!dh)
170280304Sjkim        return 0;
171280304Sjkim    ret = DH_generate_parameters_ex(dh,
172280304Sjkim                                    dctx->prime_len, dctx->generator, pcb);
173280304Sjkim    if (ret)
174280304Sjkim        EVP_PKEY_assign_DH(pkey, dh);
175280304Sjkim    else
176280304Sjkim        DH_free(dh);
177280304Sjkim    return ret;
178280304Sjkim}
179238384Sjkim
180238384Sjkimstatic int pkey_dh_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
181280304Sjkim{
182280304Sjkim    DH *dh = NULL;
183280304Sjkim    if (ctx->pkey == NULL) {
184280304Sjkim        DHerr(DH_F_PKEY_DH_KEYGEN, DH_R_NO_PARAMETERS_SET);
185280304Sjkim        return 0;
186280304Sjkim    }
187280304Sjkim    dh = DH_new();
188280304Sjkim    if (!dh)
189280304Sjkim        return 0;
190280304Sjkim    EVP_PKEY_assign_DH(pkey, dh);
191280304Sjkim    /* Note: if error return, pkey is freed by parent routine */
192280304Sjkim    if (!EVP_PKEY_copy_parameters(pkey, ctx->pkey))
193280304Sjkim        return 0;
194280304Sjkim    return DH_generate_key(pkey->pkey.dh);
195280304Sjkim}
196238384Sjkim
197280304Sjkimstatic int pkey_dh_derive(EVP_PKEY_CTX *ctx, unsigned char *key,
198280304Sjkim                          size_t *keylen)
199280304Sjkim{
200280304Sjkim    int ret;
201280304Sjkim    if (!ctx->pkey || !ctx->peerkey) {
202280304Sjkim        DHerr(DH_F_PKEY_DH_DERIVE, DH_R_KEYS_NOT_SET);
203280304Sjkim        return 0;
204280304Sjkim    }
205280304Sjkim    ret = DH_compute_key(key, ctx->peerkey->pkey.dh->pub_key,
206280304Sjkim                         ctx->pkey->pkey.dh);
207280304Sjkim    if (ret < 0)
208280304Sjkim        return ret;
209280304Sjkim    *keylen = ret;
210280304Sjkim    return 1;
211280304Sjkim}
212238384Sjkim
213280304Sjkimconst EVP_PKEY_METHOD dh_pkey_meth = {
214280304Sjkim    EVP_PKEY_DH,
215280304Sjkim    EVP_PKEY_FLAG_AUTOARGLEN,
216280304Sjkim    pkey_dh_init,
217280304Sjkim    pkey_dh_copy,
218280304Sjkim    pkey_dh_cleanup,
219238384Sjkim
220280304Sjkim    0,
221280304Sjkim    pkey_dh_paramgen,
222238384Sjkim
223280304Sjkim    0,
224280304Sjkim    pkey_dh_keygen,
225238384Sjkim
226280304Sjkim    0,
227280304Sjkim    0,
228238384Sjkim
229280304Sjkim    0,
230280304Sjkim    0,
231238384Sjkim
232280304Sjkim    0, 0,
233238384Sjkim
234280304Sjkim    0, 0, 0, 0,
235238384Sjkim
236280304Sjkim    0, 0,
237238384Sjkim
238280304Sjkim    0, 0,
239238384Sjkim
240280304Sjkim    0,
241280304Sjkim    pkey_dh_derive,
242238384Sjkim
243280304Sjkim    pkey_dh_ctrl,
244280304Sjkim    pkey_dh_ctrl_str
245280304Sjkim};
246