]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecDH.c
Security-59306.11.20.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 /* SecDHContext memory layout
47 +-----------------+
48 | ccdh_gp |
49 +-----------------+
50 | ccdh_full_ctx |
51 +-----------------+
52 */
53
54 static inline ccdh_gp_t SecDH_gp(SecDHContext dh)
55 {
56 return (ccdh_gp_t)dh;
57 }
58
59 static inline ccdh_full_ctx_t SecDH_priv(SecDHContext dh)
60 {
61 ccdh_gp_t gp = SecDH_gp(dh);
62 cc_size s = ccn_sizeof_n(ccdh_gp_n(gp));
63 ccdh_full_ctx_t priv = (ccdh_full_ctx_t)((char *) dh + ccdh_gp_size(s));
64
65 return priv;
66 }
67
68 size_t SecDHGetMaxKeyLength(SecDHContext dh) {
69
70 ccdh_gp_t gp = SecDH_gp(dh);
71 cc_size s = ccn_sizeof_n(ccdh_gp_n(gp));
72
73 return s;
74 }
75
76
77 static inline size_t SecDH_context_size(size_t p_len)
78 {
79 cc_size n = ccn_nof_size(p_len);
80 cc_size real_p_len = ccn_sizeof_n(n);
81 size_t context_size = ccdh_gp_size(real_p_len)+ccdh_full_ctx_size(real_p_len);
82 return context_size;
83 }
84
85 /* Shared static functions. */
86
87 static OSStatus
88 der2OSStatus(DERReturn derReturn)
89 {
90 switch(derReturn)
91 {
92 case DR_Success: return errSecSuccess;
93 case DR_EndOfSequence: return errSecDecode;
94 case DR_UnexpectedTag: return errSecDecode;
95 case DR_DecodeError: return errSecDecode;
96 case DR_Unimplemented: return errSecUnimplemented;
97 case DR_IncompleteSeq: return errSecDecode;
98 case DR_ParamErr: return errSecParam;
99 case DR_BufOverflow: return errSecBufferTooSmall;
100 default: return errSecInternal;
101 }
102 }
103
104 static int dhRngCallback(struct ccrng_state *rng, unsigned long outlen, void *out)
105 {
106 return SecRandomCopyBytes(kSecRandomDefault, outlen, out);
107 }
108
109 static struct ccrng_state dhrng = {
110 .generate = dhRngCallback
111 };
112
113 OSStatus SecDHCreate(uint32_t g, const uint8_t *p, size_t p_len,
114 uint32_t l, const uint8_t *recip, size_t recip_len, SecDHContext *pdh)
115 {
116 cc_size n = ccn_nof_size(p_len);
117 size_t context_size = SecDH_context_size(p_len);
118 void *context = malloc(context_size);
119 cc_clear(context_size, context);
120
121 ccdh_gp_t gp;
122 gp = context;
123
124 CCDH_GP_N(gp) = n;
125 CCDH_GP_L(gp) = l;
126
127 if(ccn_read_uint(n, CCDH_GP_PRIME(gp), p_len, p))
128 goto errOut;
129 if(recip) {
130 if(ccn_read_uint(n+1, CCDH_GP_RECIP(gp), recip_len, recip))
131 goto errOut;
132 cczp_init_with_recip(CCDH_GP_ZP(gp), CCDH_GP_RECIP(gp));
133 } else if (cczp_init(CCDH_GP_ZP(gp))) {
134 goto errOut;
135 }
136 ccn_seti(n, CCDH_GP_G(gp), g);
137
138 *pdh = (SecDHContext) context;
139
140 return errSecSuccess;
141
142 errOut:
143 SecDHDestroy(context);
144 *pdh = NULL;
145 return errSecInternal;
146
147 }
148
149 /* this used to be in libgDH */
150 /*
151 * Support for encoding and decoding DH parameter blocks.
152 * Apple form encodes the reciprocal of the prime p.
153 */
154 /* PKCS3, Openssl compatible */
155 typedef struct {
156 DERItem p;
157 DERItem g;
158 DERItem l;
159 DERItem recip; /* Only used in Apple Custom blocks. */
160 } DER_DHParams;
161
162 static const DERItemSpec DER_DHParamsItemSpecs[] =
163 {
164 { DER_OFFSET(DER_DHParams, p),
165 ASN1_INTEGER,
166 DER_DEC_NO_OPTS | DER_ENC_SIGNED_INT },
167 { DER_OFFSET(DER_DHParams, g),
168 ASN1_INTEGER,
169 DER_DEC_NO_OPTS | DER_ENC_SIGNED_INT },
170 { DER_OFFSET(DER_DHParams, l),
171 ASN1_INTEGER,
172 DER_DEC_OPTIONAL | DER_ENC_SIGNED_INT },
173 /* Not part of PKCS3 per-se, but we add it on just for kicks. Since
174 it's optional we will automatically decode any apple specific
175 params, but we won't add this section unless the caller asks
176 us to. */
177 { DER_OFFSET(DER_DHParams, recip),
178 ASN1_PRIVATE | ASN1_PRIMITIVE | 0,
179 DER_DEC_OPTIONAL | DER_ENC_SIGNED_INT },
180 };
181 static const DERSize DER_NumDHParamsItemSpecs =
182 sizeof(DER_DHParamsItemSpecs) / sizeof(DERItemSpec);
183
184
185 OSStatus SecDHCreateFromParameters(const uint8_t *params,
186 size_t params_len, SecDHContext *pdh)
187 {
188 // We support DomainParameters as specified in PKCS#3
189 // (http://www.emc.com/emc-plus/rsa-labs/standards-initiatives/pkcs-3-diffie-hellman-key-agreement-standar.htm)
190 // DHParameter ::= SEQUENCE {
191 // prime INTEGER, -- p
192 // base INTEGER, -- g
193 // privateValueLength INTEGER OPTIONAL }
194
195 DERReturn drtn;
196 DERItem paramItem = {(DERByte *)params, params_len};
197 DER_DHParams decodedParams;
198 uint32_t l = 0;
199
200 drtn = DERParseSequence(&paramItem,
201 DER_NumDHParamsItemSpecs, DER_DHParamsItemSpecs,
202 &decodedParams, sizeof(decodedParams));
203 if(drtn)
204 return drtn;
205
206 if (decodedParams.l.length > 0) {
207 drtn = DERParseInteger(&decodedParams.l, &l);
208 if(drtn)
209 return drtn;
210 }
211 cc_size n = ccn_nof_size(decodedParams.p.length);
212 cc_size p_len = ccn_sizeof_n(n);
213 size_t context_size = ccdh_gp_size(p_len)+ccdh_full_ctx_size(p_len);
214 void *context = malloc(context_size);
215 if(context==NULL)
216 return errSecAllocate;
217
218 bzero(context, context_size);
219
220 ccdh_gp_t gp = context;
221
222 CCDH_GP_N(gp) = n;
223 CCDH_GP_L(gp) = l;
224
225 if(ccn_read_uint(n, CCDH_GP_PRIME(gp), decodedParams.p.length, decodedParams.p.data))
226 goto errOut;
227 if(decodedParams.recip.length) {
228 if(ccn_read_uint(n+1, CCDH_GP_RECIP(gp), decodedParams.recip.length, decodedParams.recip.data))
229 goto errOut;
230 cczp_init_with_recip(CCDH_GP_ZP(gp), CCDH_GP_RECIP(gp));
231 } else if (cczp_init(CCDH_GP_ZP(gp))) {
232 goto errOut;
233 }
234
235 if(ccn_read_uint(n, CCDH_GP_G(gp), decodedParams.g.length, decodedParams.g.data))
236 goto errOut;
237
238 *pdh = (SecDHContext) context;
239 return errSecSuccess;
240
241 errOut:
242 SecDHDestroy(context);
243 *pdh = NULL;
244 return errSecInvalidKey;
245 }
246
247 OSStatus SecDHCreateFromAlgorithmId(const uint8_t *alg, size_t alg_len,
248 SecDHContext *pdh) {
249 DERAlgorithmId algorithmId;
250 DERItem algId;
251
252 algId.data = (uint8_t *)alg;
253 algId.length = alg_len;
254
255 DERReturn drtn = DERParseSequence(&algId,
256 DERNumAlgorithmIdItemSpecs, DERAlgorithmIdItemSpecs,
257 &algorithmId, sizeof(algorithmId));
258 if (drtn != DR_Success)
259 return der2OSStatus(drtn);
260
261 return SecDHCreateFromParameters(algorithmId.params.data,
262 algorithmId.params.length, pdh);
263 }
264
265 OSStatus SecDHGenerateKeypair(SecDHContext dh, uint8_t *pub_key,
266 size_t *pub_key_len)
267 {
268 int result;
269 ccdh_gp_t gp = SecDH_gp(dh);
270 ccdh_full_ctx_t priv = SecDH_priv(dh);
271
272 if((result = ccdh_generate_key(gp, &dhrng, priv)))
273 return result;
274
275 /* output y as a big endian byte buffer */
276 size_t ylen = ccn_write_uint_size(ccdh_gp_n(gp), ccdh_ctx_y(priv));
277 if(*pub_key_len < ylen)
278 return errSecBufferTooSmall;
279 ccn_write_uint(ccdh_gp_n(gp),ccdh_ctx_y(priv), ylen, pub_key);
280 *pub_key_len = ylen;
281
282 return errSecSuccess;
283 }
284
285 OSStatus SecDHComputeKey(SecDHContext dh,
286 const uint8_t *pub_key, size_t pub_key_len,
287 uint8_t *computed_key, size_t *computed_key_len)
288 {
289 ccdh_gp_t gp = SecDH_gp(dh);
290 ccdh_full_ctx_t priv = SecDH_priv(dh);
291 ccdh_pub_ctx_decl_gp(gp, pub);
292 cc_size n = ccdh_gp_n(gp);
293 cc_unit r[n];
294
295 if(ccdh_import_pub(gp, pub_key_len, pub_key, pub))
296 return errSecInvalidKey;
297
298 //ccdh_compute_shared_secret() cannot be used directly, because it doesn't allow truncated output. Buffering is needed.
299 if(ccdh_compute_key(priv, pub, r))
300 return errSecInvalidKey;
301
302 ccn_write_uint(n, r, *computed_key_len, computed_key);
303 size_t out_size = ccn_write_uint_size(n, r);
304 if(out_size < *computed_key_len)
305 *computed_key_len=out_size;
306
307 return errSecSuccess;
308 }
309
310 void SecDHDestroy(SecDHContext dh) {
311 /* Zero out key material. */
312 ccdh_gp_t gp = SecDH_gp(dh);
313 cc_size p_len = ccn_sizeof_n(ccdh_gp_n(gp));
314 size_t context_size = SecDH_context_size(p_len);
315
316 cc_clear(context_size, dh);
317 free(dh);
318 }
319
320 /* Max encoded size for standard (PKCS3) parameters */
321 #define DH_ENCODED_PARAM_SIZE(primeSizeInBytes) \
322 DER_MAX_ENCODED_SIZE( \
323 DER_MAX_ENCODED_SIZE(primeSizeInBytes) + /* g */ \
324 DER_MAX_ENCODED_SIZE(primeSizeInBytes) + /* p */ \
325 DER_MAX_ENCODED_SIZE(4)) /* l */
326
327
328 OSStatus SecDHEncodeParams(CFDataRef g, CFDataRef p,
329 CFDataRef l, CFDataRef recip,
330 CFDataRef *params)
331 {
332 OSStatus ortn;
333 DER_DHParams derParams =
334 {
335 .p = {
336 .length = CFDataGetLength(p),
337 .data = (DERByte *)CFDataGetBytePtr(p),
338 },
339 .g = {
340 .length = CFDataGetLength(g),
341 .data = (DERByte *)CFDataGetBytePtr(g),
342 },
343 .l = {
344 .length = l?CFDataGetLength(l):0,
345 .data = (DERByte *)(l?CFDataGetBytePtr(l):NULL),
346 },
347 .recip = {
348 .length = recip?CFDataGetLength(recip):0,
349 .data = (DERByte *)(recip?CFDataGetBytePtr(recip):NULL),
350 },
351 };
352
353 DERSize ioLen = DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE,
354 &derParams,
355 DER_NumDHParamsItemSpecs, DER_DHParamsItemSpecs);
356
357 DERByte *der = malloc(ioLen);
358 // FIXME: What if this fails - we should probably not have a malloc here ?
359 assert(der);
360 ortn = (int)DEREncodeSequence(ASN1_CONSTR_SEQUENCE,
361 &derParams,
362 DER_NumDHParamsItemSpecs, DER_DHParamsItemSpecs,
363 der,
364 &ioLen);
365
366 if(!ortn && params)
367 *params=CFDataCreate(kCFAllocatorDefault, der, ioLen);
368
369 // FIXME: we should just allocate the CFDataRef
370
371 free(der);
372 return ortn;
373 }
374
375
376 OSStatus SecDHDecodeParams(CFDataRef *g, CFDataRef *p,
377 CFDataRef *l, CFDataRef *r,
378 CFDataRef params)
379 {
380 DERReturn drtn;
381 DERItem paramItem = {(DERByte *)CFDataGetBytePtr(params), CFDataGetLength(params)};
382 DER_DHParams decodedParams;
383
384 drtn = DERParseSequence(&paramItem,
385 DER_NumDHParamsItemSpecs, DER_DHParamsItemSpecs,
386 &decodedParams, sizeof(decodedParams));
387 if(drtn)
388 return drtn;
389
390 if(g) *g=CFDataCreate(kCFAllocatorDefault, decodedParams.g.data, decodedParams.g.length);
391 if(p) *p=CFDataCreate(kCFAllocatorDefault, decodedParams.p.data, decodedParams.p.length);
392 if(l) *l=CFDataCreate(kCFAllocatorDefault, decodedParams.l.data, decodedParams.l.length);
393 if(r) *r=CFDataCreate(kCFAllocatorDefault, decodedParams.recip.data, decodedParams.recip.length);
394
395 return errSecSuccess;
396 }