]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecDH.c
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / sec / Security / SecDH.c
1 /*
2 * Copyright (c) 2007-2008,2010,2012-2013 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * SecDH.c - Implement the crypto required for a Diffie-Hellman key exchange.
26 */
27
28 #include "SecDH.h"
29 #include <libDER/DER_Keys.h>
30 #include <corecrypto/ccdh.h>
31 #include <libDER/DER_Keys.h>
32 #include <libDER/DER_Encode.h>
33 #include <libDER/asn1Types.h>
34 #include <libkern/OSByteOrder.h>
35 #include "utilities/debugging.h"
36 #include <Security/SecInternal.h>
37 #include <Security/SecRandom.h>
38 #include <stdlib.h>
39 #include <Security/SecBase.h>
40 #include <Security/SecBasePriv.h>
41
42 #ifdef DEBUG
43 #define DH_DEBUG 1
44 #endif
45
46 static inline ccdh_gp_t SecDH_gp(SecDHContext dh)
47 {
48 void *p = dh;
49 ccdh_gp_t gp = { .gp = p };
50 return gp;
51 }
52
53 static inline ccdh_full_ctx_t SecDH_priv(SecDHContext dh)
54 {
55 void *p = dh;
56 cczp_t zp = { .u = p };
57 cc_size s = ccn_sizeof_n(cczp_n(zp));
58 ccdh_full_ctx_t priv = { .hdr = (struct ccdh_ctx_header *)(p+ccdh_gp_size(s)) };
59 return priv;
60 }
61
62 static inline size_t SecDH_context_size(size_t p_len)
63 {
64 cc_size n = ccn_nof_size(p_len);
65 cc_size real_p_len = ccn_sizeof_n(n);
66 size_t context_size = ccdh_gp_size(real_p_len)+ccdh_full_ctx_size(real_p_len);
67 return context_size;
68 }
69
70 /* Shared static functions. */
71
72 static OSStatus
73 der2OSStatus(DERReturn derReturn)
74 {
75 switch(derReturn)
76 {
77 case DR_Success: return errSecSuccess;
78 case DR_EndOfSequence: return errSecDecode;
79 case DR_UnexpectedTag: return errSecDecode;
80 case DR_DecodeError: return errSecDecode;
81 case DR_Unimplemented: return errSecUnimplemented;
82 case DR_IncompleteSeq: return errSecDecode;
83 case DR_ParamErr: return errSecParam;
84 case DR_BufOverflow: return errSecBufferTooSmall;
85 default: return errSecInternal;
86 }
87 }
88
89 static int dhRngCallback(struct ccrng_state *rng, unsigned long outlen, void *out)
90 {
91 return SecRandomCopyBytes(kSecRandomDefault, outlen, out);
92 }
93
94 static struct ccrng_state dhrng = {
95 .generate = dhRngCallback
96 };
97
98 OSStatus SecDHCreate(uint32_t g, const uint8_t *p, size_t p_len,
99 uint32_t l, const uint8_t *recip, size_t recip_len, SecDHContext *pdh)
100 {
101 cc_size n = ccn_nof_size(p_len);
102 size_t context_size = SecDH_context_size(p_len);
103 void *context = malloc(context_size);
104 bzero(context, context_size);
105
106 ccdh_gp_t gp;
107 gp.gp = context;
108
109 CCDH_GP_N(gp) = n;
110 CCDH_GP_L(gp) = l;
111
112 if(ccn_read_uint(n, CCDH_GP_PRIME(gp), p_len, p))
113 goto errOut;
114 if(recip) {
115 if(ccn_read_uint(n+1, CCDH_GP_RECIP(gp), recip_len, recip))
116 goto errOut;
117 gp.zp.zp->mod_prime = cczp_mod;
118 } else {
119 cczp_init(gp.zp);
120 };
121 ccn_seti(n, CCDH_GP_G(gp), g);
122
123 *pdh = (SecDHContext) context;
124
125 return errSecSuccess;
126
127 errOut:
128 SecDHDestroy(context);
129 *pdh = NULL;
130 return errSecInternal;
131
132 }
133
134 /* this used to be in libgDH */
135 /*
136 * Support for encoding and decoding DH parameter blocks.
137 * Apple form encodes the reciprocal of the prime p.
138 */
139 /* PKCS3, Openssl compatible */
140 typedef struct {
141 DERItem p;
142 DERItem g;
143 DERItem l;
144 DERItem recip; /* Only used in Apple Custom blocks. */
145 } DER_DHParams;
146
147 static const DERItemSpec DER_DHParamsItemSpecs[] =
148 {
149 { DER_OFFSET(DER_DHParams, p),
150 ASN1_INTEGER,
151 DER_DEC_NO_OPTS | DER_ENC_SIGNED_INT },
152 { DER_OFFSET(DER_DHParams, g),
153 ASN1_INTEGER,
154 DER_DEC_NO_OPTS | DER_ENC_SIGNED_INT },
155 { DER_OFFSET(DER_DHParams, l),
156 ASN1_INTEGER,
157 DER_DEC_OPTIONAL | DER_ENC_SIGNED_INT },
158 /* Not part of PKCS3 per-se, but we add it on just for kicks. Since
159 it's optional we will automatically decode any apple specific
160 params, but we won't add this section unless the caller asks
161 us to. */
162 { DER_OFFSET(DER_DHParams, recip),
163 ASN1_PRIVATE | ASN1_PRIMITIVE | 0,
164 DER_DEC_OPTIONAL | DER_ENC_SIGNED_INT },
165 };
166 static const DERSize DER_NumDHParamsItemSpecs =
167 sizeof(DER_DHParamsItemSpecs) / sizeof(DERItemSpec);
168
169
170 OSStatus SecDHCreateFromParameters(const uint8_t *params,
171 size_t params_len, SecDHContext *pdh)
172 {
173 DERReturn drtn;
174 DERItem paramItem = {(DERByte *)params, params_len};
175 DER_DHParams decodedParams;
176 uint32_t l;
177
178 drtn = DERParseSequence(&paramItem,
179 DER_NumDHParamsItemSpecs, DER_DHParamsItemSpecs,
180 &decodedParams, sizeof(decodedParams));
181 if(drtn)
182 return drtn;
183
184 drtn = DERParseInteger(&decodedParams.l, &l);
185 if(drtn)
186 return drtn;
187 cc_size n = ccn_nof_size(decodedParams.p.length);
188 cc_size p_len = ccn_sizeof_n(n);
189 size_t context_size = ccdh_gp_size(p_len)+ccdh_full_ctx_size(p_len);
190 void *context = malloc(context_size);
191 if(context==NULL)
192 return errSecAllocate;
193
194 bzero(context, context_size);
195
196 ccdh_gp_t gp;
197 gp.gp = context;
198
199 CCDH_GP_N(gp) = n;
200 CCDH_GP_L(gp) = l;
201
202 if(ccn_read_uint(n, CCDH_GP_PRIME(gp), decodedParams.p.length, decodedParams.p.data))
203 goto errOut;
204 if(decodedParams.recip.length) {
205 if(ccn_read_uint(n+1, CCDH_GP_RECIP(gp), decodedParams.recip.length, decodedParams.recip.data))
206 goto errOut;
207 gp.zp.zp->mod_prime = cczp_mod;
208 } else {
209 cczp_init(gp.zp);
210 };
211
212 if(ccn_read_uint(n, CCDH_GP_G(gp), decodedParams.g.length, decodedParams.g.data))
213 goto errOut;
214
215 *pdh = (SecDHContext) context;
216 return errSecSuccess;
217
218 errOut:
219 SecDHDestroy(context);
220 *pdh = NULL;
221 return errSecInvalidKey;
222 }
223
224 OSStatus SecDHCreateFromAlgorithmId(const uint8_t *alg, size_t alg_len,
225 SecDHContext *pdh) {
226 DERAlgorithmId algorithmId;
227 DERItem algId;
228
229 algId.data = (uint8_t *)alg;
230 algId.length = alg_len;
231
232 DERReturn drtn = DERParseSequence(&algId,
233 DERNumAlgorithmIdItemSpecs, DERAlgorithmIdItemSpecs,
234 &algorithmId, sizeof(algorithmId));
235 if (drtn != DR_Success)
236 return der2OSStatus(drtn);
237
238 return SecDHCreateFromParameters(algorithmId.params.data,
239 algorithmId.params.length, pdh);
240 }
241
242 size_t SecDHGetMaxKeyLength(SecDHContext dh) {
243 cczp_const_t zp;
244 zp.u = (cc_unit *)dh;
245
246 return ccn_sizeof_n(cczp_n(zp));
247 }
248
249
250 OSStatus SecDHGenerateKeypair(SecDHContext dh, uint8_t *pub_key,
251 size_t *pub_key_len)
252 {
253 int result;
254 ccdh_gp_t gp = SecDH_gp(dh);
255 ccdh_full_ctx_t priv = SecDH_priv(dh);
256
257 if((result = ccdh_generate_key(gp, &dhrng, priv)))
258 return result;
259
260 /* output y as a big endian byte buffer */
261 size_t ylen = ccn_write_uint_size(ccdh_gp_n(gp), ccdh_ctx_y(priv));
262 if(*pub_key_len < ylen)
263 return errSecBufferTooSmall;
264 ccn_write_uint(ccdh_gp_n(gp),ccdh_ctx_y(priv), ylen, pub_key);
265 *pub_key_len = ylen;
266
267 return errSecSuccess;
268 }
269
270 OSStatus SecDHComputeKey(SecDHContext dh,
271 const uint8_t *pub_key, size_t pub_key_len,
272 uint8_t *computed_key, size_t *computed_key_len)
273 {
274 ccdh_gp_t gp = SecDH_gp(dh);
275 ccdh_full_ctx_t priv = SecDH_priv(dh);
276 ccdh_pub_ctx_decl_gp(gp, pub);
277 cc_size n = ccdh_gp_n(gp);
278 cc_unit r[n];
279
280 if(ccdh_import_pub(gp, pub_key_len, pub_key, pub))
281 return errSecInvalidKey;
282
283 if(ccdh_compute_key(priv, pub, r))
284 return errSecInvalidKey;
285
286 ccn_write_uint(n, r, *computed_key_len, computed_key);
287 size_t out_size = ccn_write_uint_size(n, r);
288 if(out_size < *computed_key_len)
289 *computed_key_len=out_size;
290
291 return errSecSuccess;
292 }
293
294 void SecDHDestroy(SecDHContext dh) {
295 /* Zero out key material. */
296 ccdh_gp_t gp = SecDH_gp(dh);
297 cc_size p_len = ccn_sizeof_n(ccdh_gp_n(gp));
298 size_t context_size = SecDH_context_size(p_len);
299
300 bzero(dh, context_size);
301 free(dh);
302 }
303
304 /* Max encoded size for standard (PKCS3) parameters */
305 #define DH_ENCODED_PARAM_SIZE(primeSizeInBytes) \
306 DER_MAX_ENCODED_SIZE( \
307 DER_MAX_ENCODED_SIZE(primeSizeInBytes) + /* g */ \
308 DER_MAX_ENCODED_SIZE(primeSizeInBytes) + /* p */ \
309 DER_MAX_ENCODED_SIZE(4)) /* l */
310
311
312 OSStatus SecDHEncodeParams(CFDataRef g, CFDataRef p,
313 CFDataRef l, CFDataRef recip,
314 CFDataRef *params)
315 {
316 OSStatus ortn;
317 DER_DHParams derParams =
318 {
319 .p = {
320 .length = CFDataGetLength(p),
321 .data = (DERByte *)CFDataGetBytePtr(p),
322 },
323 .g = {
324 .length = CFDataGetLength(g),
325 .data = (DERByte *)CFDataGetBytePtr(g),
326 },
327 .l = {
328 .length = l?CFDataGetLength(l):0,
329 .data = (DERByte *)(l?CFDataGetBytePtr(l):NULL),
330 },
331 .recip = {
332 .length = recip?CFDataGetLength(recip):0,
333 .data = (DERByte *)(recip?CFDataGetBytePtr(recip):NULL),
334 },
335 };
336
337 DERSize ioLen = DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE,
338 &derParams,
339 DER_NumDHParamsItemSpecs, DER_DHParamsItemSpecs);
340
341 DERByte *der = malloc(ioLen);
342 // FIXME: What if this fails - we should probably not have a malloc here ?
343 assert(der);
344 ortn = (int)DEREncodeSequence(ASN1_CONSTR_SEQUENCE,
345 &derParams,
346 DER_NumDHParamsItemSpecs, DER_DHParamsItemSpecs,
347 der,
348 &ioLen);
349
350 if(!ortn && params)
351 *params=CFDataCreate(kCFAllocatorDefault, der, ioLen);
352
353 // FIXME: we should just allocate the CFDataRef
354
355 free(der);
356 return ortn;
357 }
358
359
360 OSStatus SecDHDecodeParams(CFDataRef *g, CFDataRef *p,
361 CFDataRef *l, CFDataRef *r,
362 CFDataRef params)
363 {
364 DERReturn drtn;
365 DERItem paramItem = {(DERByte *)CFDataGetBytePtr(params), CFDataGetLength(params)};
366 DER_DHParams decodedParams;
367
368 drtn = DERParseSequence(&paramItem,
369 DER_NumDHParamsItemSpecs, DER_DHParamsItemSpecs,
370 &decodedParams, sizeof(decodedParams));
371 if(drtn)
372 return drtn;
373
374 if(g) *g=CFDataCreate(kCFAllocatorDefault, decodedParams.g.data, decodedParams.g.length);
375 if(p) *p=CFDataCreate(kCFAllocatorDefault, decodedParams.p.data, decodedParams.p.length);
376 if(l) *l=CFDataCreate(kCFAllocatorDefault, decodedParams.l.data, decodedParams.l.length);
377 if(r) *r=CFDataCreate(kCFAllocatorDefault, decodedParams.recip.data, decodedParams.recip.length);
378
379 return errSecSuccess;
380 }