1/*
2 * Copyright (c) 2006 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Portions Copyright (c) 2010 Apple Inc. 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 the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include <config.h>
37
38#include <stdio.h>
39#include <stdlib.h>
40#include <dh.h>
41#include <roken.h>
42
43#ifdef HAVE_CDSA
44#define NEED_CDSA 1
45
46#include <rfc2459_asn1.h>
47
48#include "common.h"
49
50struct dh_cdsa {
51    CSSM_KEY priv_key;
52    CSSM_KEY pub_key;
53};
54
55/*
56 *
57 */
58
59static int
60dh_generate_key(DH *dh)
61{
62    CSSM_CSP_HANDLE cspHandle = _hc_get_cdsa_csphandle();
63    struct dh_cdsa *cdsa = DH_get_ex_data(dh, 0);
64    uint32_t pubAttr = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_DATA;
65    uint32_t privAttr = CSSM_KEYATTR_RETURN_REF;
66    DHParameter dp;
67    CSSM_CC_HANDLE handle;
68    CSSM_DATA param;
69    CSSM_RETURN ret;
70    size_t size;
71
72    if (dh->p == NULL || dh->g == NULL)
73	return 0;
74
75    CSSM_FreeKey(cspHandle, NULL, &cdsa->pub_key, CSSM_FALSE);
76    CSSM_FreeKey(cspHandle, NULL, &cdsa->priv_key, CSSM_FALSE);
77
78    memset(&dp, 0, sizeof(dp));
79
80    ret = _hc_BN_to_integer(dh->p, &dp.prime);
81    if (ret == 0)
82	ret = _hc_BN_to_integer(dh->g, &dp.base);
83    if (ret) {
84	free_DHParameter(&dp);
85	return 0;
86    }
87    dp.privateValueLength = NULL;
88
89    ASN1_MALLOC_ENCODE(DHParameter, param.Data, param.Length,
90		       &dp, &size, ret);
91    free_DHParameter(&dp);
92    if (ret)
93	return 0;
94    if (size != param.Length)
95	abort();
96
97    ret = CSSM_CSP_CreateKeyGenContext(cspHandle,
98				       CSSM_ALGID_DH,
99				       BN_num_bits(dh->p) - 1,
100				       NULL,
101				       NULL,
102				       NULL,
103				       NULL,
104				       &param,
105				       &handle);
106    free(param.Data);
107    if (ret)
108	return 0;
109
110    ret = CSSM_GenerateKeyPair(handle,
111			       /* pubkey */
112			       CSSM_KEYUSE_DERIVE,
113			       pubAttr,
114			       &_hc_labelData,
115			       &cdsa->pub_key,
116			       /* private key */
117			       CSSM_KEYUSE_DERIVE,
118			       privAttr,
119			       &_hc_labelData,
120			       NULL,
121			       &cdsa->priv_key);
122
123    CSSM_DeleteContext(handle);
124    if (ret)
125	return 0;
126
127    dh->pub_key = BN_bin2bn(cdsa->pub_key.KeyData.Data, cdsa->pub_key.KeyData.Length, NULL);
128    if (dh->pub_key == NULL)
129	return 0;
130
131    return 1;
132}
133
134static int
135dh_compute_key(unsigned char *shared, const BIGNUM * pub, DH *dh)
136{
137    CSSM_CSP_HANDLE cspHandle = _hc_get_cdsa_csphandle();
138    struct dh_cdsa *cdsa = DH_get_ex_data(dh, 0);
139    CSSM_ACCESS_CREDENTIALS creds;
140    CSSM_CC_HANDLE handle;
141    CSSM_KEY derivedKey;
142    CSSM_DATA param;
143    CSSM_RETURN ret;
144    int size;
145
146    memset(&creds, 0, sizeof(creds));
147    memset(&derivedKey, 0, sizeof(derivedKey));
148
149    ret = CSSM_CSP_CreateDeriveKeyContext(cspHandle,
150					  CSSM_ALGID_DH,
151					  CSSM_ALGID_RC5, /* will give us plenty of bits */
152					  DH_size(dh) * 8,
153					  &creds,
154					  &cdsa->priv_key,
155					  0,
156					  0,
157					  0,
158					  &handle);
159    if(ret)
160	return 0;
161
162    param.Length = BN_num_bytes(pub);
163    param.Data = malloc(param.Length);
164    if (param.Data == NULL) {
165	CSSM_DeleteContext(handle);
166	return 0;
167    }
168    BN_bn2bin(pub, param.Data);
169
170    ret = CSSM_DeriveKey(handle,
171			 &param,
172			 CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
173			 CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE,
174			 &_hc_labelData,
175			 NULL,
176			 &derivedKey);
177    free(param.Data);
178    if(ret)
179	return 0;
180
181    size = derivedKey.KeyData.Length;
182
183    if (size > DH_size(dh)) {
184	CSSM_FreeKey(cspHandle, NULL, &derivedKey, CSSM_FALSE);
185	CSSM_DeleteContext(handle);
186	return 0;
187    }
188
189    memcpy(shared, derivedKey.KeyData.Data, size);
190
191    CSSM_FreeKey(cspHandle, NULL, &derivedKey, CSSM_FALSE);
192    CSSM_DeleteContext(handle);
193
194    return size;
195}
196
197static int
198dh_generate_params(DH *dh, int a, int b, BN_GENCB *callback)
199{
200    /* groups should already be known, we don't care about this */
201    return 0;
202}
203
204static int
205dh_init(DH *dh)
206{
207    struct dh_cdsa *cdsa;
208
209    cdsa = calloc(1, sizeof(*cdsa));
210    if (cdsa == NULL)
211	return 0;
212
213    DH_set_ex_data(dh, 0, cdsa);
214
215    return 1;
216}
217
218static int
219dh_finish(DH *dh)
220{
221    struct dh_cdsa *cdsa = DH_get_ex_data(dh, 0);
222    if (cdsa) {
223	CSSM_CSP_HANDLE cspHandle = _hc_get_cdsa_csphandle();
224
225	CSSM_FreeKey(cspHandle, NULL, &cdsa->pub_key, CSSM_FALSE);
226	CSSM_FreeKey(cspHandle, NULL, &cdsa->priv_key, CSSM_FALSE);
227	free(cdsa);
228    }
229    return 1;
230}
231
232
233/*
234 *
235 */
236
237const DH_METHOD _hc_dh_cdsa_method = {
238    "hcrypto cdsa DH",
239    dh_generate_key,
240    dh_compute_key,
241    NULL,
242    dh_init,
243    dh_finish,
244    0,
245    NULL,
246    dh_generate_params
247};
248
249#endif /* HAVE_CDSA */
250
251/**
252 * DH implementation using cdsa.
253 *
254 * @return the DH_METHOD for the DH implementation using libcdsa.
255 *
256 * @ingroup hcrypto_dh
257 */
258
259const DH_METHOD *
260DH_cdsa_method(void)
261{
262#ifdef HAVE_CDSA
263    return &_hc_dh_cdsa_method;
264#else
265    return NULL;
266#endif /* HAVE_CDSA */
267}
268