]> git.saurik.com Git - apple/security.git/blob - sec/Security/SecDH.c
Security-55163.44.tar.gz
[apple/security.git] / sec / Security / SecDH.c
1 /*
2 * Copyright (c) 2007-2008,2010 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 <security_utilities/debugging.h>
36 #include <Security/SecInternal.h>
37 #include <Security/SecRandom.h>
38 #include <stdlib.h>
39 #include <MacErrors.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 noErr;
78 case DR_EndOfSequence: return errSecDecode;
79 case DR_UnexpectedTag: return errSecDecode;
80 case DR_DecodeError: return errSecDecode;
81 case DR_Unimplemented: return unimpErr;
82 case DR_IncompleteSeq: return errSecDecode;
83 case DR_ParamErr: return paramErr;
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 noErr;
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 memFullErr;
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 noErr;
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 noErr;
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 noErr;
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 }