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 ¶m, 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 ¶m, 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