2 * Copyright (c) 2007-2008,2010,2012-2013 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * SecDH.c - Implement the crypto required for a Diffie-Hellman key exchange.
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>
39 #include <Security/SecBase.h>
40 #include <Security/SecBasePriv.h>
46 static inline ccdh_gp_t
SecDH_gp(SecDHContext dh
)
49 ccdh_gp_t gp
= { .gp
= p
};
53 static inline ccdh_full_ctx_t
SecDH_priv(SecDHContext 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
)) };
62 static inline size_t SecDH_context_size(size_t p_len
)
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
);
70 /* Shared static functions. */
73 der2OSStatus(DERReturn derReturn
)
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
;
89 static int dhRngCallback(struct ccrng_state
*rng
, unsigned long outlen
, void *out
)
91 return SecRandomCopyBytes(kSecRandomDefault
, outlen
, out
);
94 static struct ccrng_state dhrng
= {
95 .generate
= dhRngCallback
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
)
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
);
112 if(ccn_read_uint(n
, CCDH_GP_PRIME(gp
), p_len
, p
))
115 if(ccn_read_uint(n
+1, CCDH_GP_RECIP(gp
), recip_len
, recip
))
117 gp
.zp
.zp
->mod_prime
= cczp_mod
;
121 ccn_seti(n
, CCDH_GP_G(gp
), g
);
123 *pdh
= (SecDHContext
) context
;
125 return errSecSuccess
;
128 SecDHDestroy(context
);
130 return errSecInternal
;
134 /* this used to be in libgDH */
136 * Support for encoding and decoding DH parameter blocks.
137 * Apple form encodes the reciprocal of the prime p.
139 /* PKCS3, Openssl compatible */
144 DERItem recip
; /* Only used in Apple Custom blocks. */
147 static const DERItemSpec DER_DHParamsItemSpecs
[] =
149 { DER_OFFSET(DER_DHParams
, p
),
151 DER_DEC_NO_OPTS
| DER_ENC_SIGNED_INT
},
152 { DER_OFFSET(DER_DHParams
, g
),
154 DER_DEC_NO_OPTS
| DER_ENC_SIGNED_INT
},
155 { DER_OFFSET(DER_DHParams
, l
),
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
162 { DER_OFFSET(DER_DHParams
, recip
),
163 ASN1_PRIVATE
| ASN1_PRIMITIVE
| 0,
164 DER_DEC_OPTIONAL
| DER_ENC_SIGNED_INT
},
166 static const DERSize DER_NumDHParamsItemSpecs
=
167 sizeof(DER_DHParamsItemSpecs
) / sizeof(DERItemSpec
);
170 OSStatus
SecDHCreateFromParameters(const uint8_t *params
,
171 size_t params_len
, SecDHContext
*pdh
)
174 DERItem paramItem
= {(DERByte
*)params
, params_len
};
175 DER_DHParams decodedParams
;
178 drtn
= DERParseSequence(¶mItem
,
179 DER_NumDHParamsItemSpecs
, DER_DHParamsItemSpecs
,
180 &decodedParams
, sizeof(decodedParams
));
184 drtn
= DERParseInteger(&decodedParams
.l
, &l
);
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
);
192 return errSecAllocate
;
194 bzero(context
, context_size
);
202 if(ccn_read_uint(n
, CCDH_GP_PRIME(gp
), decodedParams
.p
.length
, decodedParams
.p
.data
))
204 if(decodedParams
.recip
.length
) {
205 if(ccn_read_uint(n
+1, CCDH_GP_RECIP(gp
), decodedParams
.recip
.length
, decodedParams
.recip
.data
))
207 gp
.zp
.zp
->mod_prime
= cczp_mod
;
212 if(ccn_read_uint(n
, CCDH_GP_G(gp
), decodedParams
.g
.length
, decodedParams
.g
.data
))
215 *pdh
= (SecDHContext
) context
;
216 return errSecSuccess
;
219 SecDHDestroy(context
);
221 return errSecInvalidKey
;
224 OSStatus
SecDHCreateFromAlgorithmId(const uint8_t *alg
, size_t alg_len
,
226 DERAlgorithmId algorithmId
;
229 algId
.data
= (uint8_t *)alg
;
230 algId
.length
= alg_len
;
232 DERReturn drtn
= DERParseSequence(&algId
,
233 DERNumAlgorithmIdItemSpecs
, DERAlgorithmIdItemSpecs
,
234 &algorithmId
, sizeof(algorithmId
));
235 if (drtn
!= DR_Success
)
236 return der2OSStatus(drtn
);
238 return SecDHCreateFromParameters(algorithmId
.params
.data
,
239 algorithmId
.params
.length
, pdh
);
242 size_t SecDHGetMaxKeyLength(SecDHContext dh
) {
244 zp
.u
= (cc_unit
*)dh
;
246 return ccn_sizeof_n(cczp_n(zp
));
250 OSStatus
SecDHGenerateKeypair(SecDHContext dh
, uint8_t *pub_key
,
254 ccdh_gp_t gp
= SecDH_gp(dh
);
255 ccdh_full_ctx_t priv
= SecDH_priv(dh
);
257 if((result
= ccdh_generate_key(gp
, &dhrng
, priv
)))
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
);
267 return errSecSuccess
;
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
)
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
);
280 if(ccdh_import_pub(gp
, pub_key_len
, pub_key
, pub
))
281 return errSecInvalidKey
;
283 if(ccdh_compute_key(priv
, pub
, r
))
284 return errSecInvalidKey
;
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
;
291 return errSecSuccess
;
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
);
300 bzero(dh
, context_size
);
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 */
312 OSStatus
SecDHEncodeParams(CFDataRef g
, CFDataRef p
,
313 CFDataRef l
, CFDataRef recip
,
317 DER_DHParams derParams
=
320 .length
= CFDataGetLength(p
),
321 .data
= (DERByte
*)CFDataGetBytePtr(p
),
324 .length
= CFDataGetLength(g
),
325 .data
= (DERByte
*)CFDataGetBytePtr(g
),
328 .length
= l
?CFDataGetLength(l
):0,
329 .data
= (DERByte
*)(l
?CFDataGetBytePtr(l
):NULL
),
332 .length
= recip
?CFDataGetLength(recip
):0,
333 .data
= (DERByte
*)(recip
?CFDataGetBytePtr(recip
):NULL
),
337 DERSize ioLen
= DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE
,
339 DER_NumDHParamsItemSpecs
, DER_DHParamsItemSpecs
);
341 DERByte
*der
= malloc(ioLen
);
342 // FIXME: What if this fails - we should probably not have a malloc here ?
344 ortn
= (int)DEREncodeSequence(ASN1_CONSTR_SEQUENCE
,
346 DER_NumDHParamsItemSpecs
, DER_DHParamsItemSpecs
,
351 *params
=CFDataCreate(kCFAllocatorDefault
, der
, ioLen
);
353 // FIXME: we should just allocate the CFDataRef
360 OSStatus
SecDHDecodeParams(CFDataRef
*g
, CFDataRef
*p
,
361 CFDataRef
*l
, CFDataRef
*r
,
365 DERItem paramItem
= {(DERByte
*)CFDataGetBytePtr(params
), CFDataGetLength(params
)};
366 DER_DHParams decodedParams
;
368 drtn
= DERParseSequence(¶mItem
,
369 DER_NumDHParamsItemSpecs
, DER_DHParamsItemSpecs
,
370 &decodedParams
, sizeof(decodedParams
));
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
);
379 return errSecSuccess
;