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