]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/CryptoSupport.c
mDNSResponder-379.27.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / CryptoSupport.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2011 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 // ***************************************************************************
19 // CryptoSupport.c
20 // Supporting routines for DNSSEC crypto
21 // ***************************************************************************
22
23 #include "mDNSEmbeddedAPI.h"
24 #include <CommonCrypto/CommonDigest.h> // For Hash algorithms SHA1 etc.
25 #include <dispatch/dispatch.h> // For Base32/Base64 encoding/decoding
26 #include <dispatch/private.h> // dispatch_data_create_with_transform
27 #include "CryptoAlg.h"
28 #include "CryptoSupport.h"
29 #include "dnssec.h"
30
31 #if TARGET_OS_IPHONE
32 #include "SecRSAKey.h" // For RSA_SHA1 etc. verification
33 #endif
34
35 typedef struct
36 {
37 #if DISPATCH_API_VERSION >= 20111008
38 dispatch_data_t encData;
39 dispatch_data_t encMap;
40 dispatch_data_t encNULL;
41 #endif
42 }encContext;
43
44 mDNSlocal mStatus enc_create(AlgContext *ctx)
45 {
46 encContext *ptr;
47
48 switch (ctx->alg)
49 {
50 case ENC_BASE32:
51 case ENC_BASE64:
52 ptr = (encContext *)mDNSPlatformMemAllocate(sizeof(encContext));
53 if (!ptr) return mStatus_NoMemoryErr;
54 break;
55 default:
56 LogMsg("enc_create: Unsupported algorithm %d", ctx->alg);
57 return mStatus_BadParamErr;
58 }
59 #if DISPATCH_API_VERSION >= 20111008
60 ptr->encData = NULL;
61 ptr->encMap = NULL;
62 // The encoded data is not NULL terminated. So, we concatenate a null byte later when we encode and map
63 // the real data.
64 ptr->encNULL = dispatch_data_create("", 1, dispatch_get_global_queue(0, 0), ^{});
65 if (!ptr->encNULL)
66 {
67 mDNSPlatformMemFree(ptr);
68 return mStatus_NoMemoryErr;
69 }
70 #endif
71 ctx->context = ptr;
72 return mStatus_NoError;
73 }
74
75 mDNSlocal mStatus enc_destroy(AlgContext *ctx)
76 {
77 encContext *ptr = (encContext *)ctx->context;
78 #if DISPATCH_API_VERSION >= 20111008
79 if (ptr->encData) dispatch_release(ptr->encData);
80 if (ptr->encMap) dispatch_release(ptr->encMap);
81 if (ptr->encNULL) dispatch_release(ptr->encNULL);
82 #endif
83 mDNSPlatformMemFree(ptr);
84 return mStatus_NoError;
85 }
86
87 mDNSlocal mStatus enc_add(AlgContext *ctx, void *data, mDNSu32 len)
88 {
89 switch (ctx->alg)
90 {
91 case ENC_BASE32:
92 case ENC_BASE64:
93 {
94 #if DISPATCH_API_VERSION >= 20111008
95 encContext *ptr = (encContext *)ctx->context;
96 dispatch_data_t src_data = dispatch_data_create(data, len, dispatch_get_global_queue(0, 0), ^{});
97 if (!src_data)
98 {
99 LogMsg("enc_add: dispatch_data_create src failed");
100 return mStatus_BadParamErr;
101 }
102 dispatch_data_t dest_data = dispatch_data_create_with_transform(src_data, DISPATCH_DATA_FORMAT_TYPE_NONE,
103 (ctx->alg == ENC_BASE32 ? DISPATCH_DATA_FORMAT_TYPE_BASE32 : DISPATCH_DATA_FORMAT_TYPE_BASE64));
104 dispatch_release(src_data);
105 if (!dest_data)
106 {
107 LogMsg("enc_add: dispatch_data_create dst failed");
108 return mStatus_BadParamErr;
109 }
110 ptr->encData = dest_data;
111 #else
112 (void)data;
113 (void)len;
114 #endif
115 return mStatus_NoError;
116 }
117 default:
118 LogMsg("enc_add: Unsupported algorithm %d", ctx->alg);
119 return mStatus_BadParamErr;
120 }
121 }
122
123 mDNSlocal mDNSu8* enc_encode(AlgContext *ctx)
124 {
125 const void *result = NULL;
126
127 switch (ctx->alg)
128 {
129 case ENC_BASE32:
130 case ENC_BASE64:
131 {
132 #if DISPATCH_API_VERSION >= 20111008
133 encContext *ptr = (encContext *)ctx->context;
134 size_t size;
135 dispatch_data_t dest_data = ptr->encData;
136 dispatch_data_t data = dispatch_data_create_concat(dest_data, ptr->encNULL);
137
138 if (!data)
139 {
140 LogMsg("enc_encode: cannot concatenate");
141 return NULL;
142 }
143
144 dispatch_data_t map = dispatch_data_create_map(data, &result, &size);
145 if (!map)
146 {
147 LogMsg("enc_encode: cannot create map %d", ctx->alg);
148 return NULL;
149 }
150 dispatch_release(dest_data);
151 ptr->encData = data;
152 ptr->encMap = map;
153 #endif
154 return (mDNSu8 *)result;
155 }
156 default:
157 LogMsg("enc_encode: Unsupported algorithm %d", ctx->alg);
158 return mDNSNULL;
159 }
160 }
161
162 mDNSlocal mStatus sha_create(AlgContext *ctx)
163 {
164 mDNSu8 *ptr;
165 switch (ctx->alg)
166 {
167 case SHA1_DIGEST_TYPE:
168 ptr = mDNSPlatformMemAllocate(sizeof(CC_SHA1_CTX));
169 if (!ptr) return mStatus_NoMemoryErr;
170 CC_SHA1_Init((CC_SHA1_CTX *)ptr);
171 break;
172 case SHA256_DIGEST_TYPE:
173 ptr = mDNSPlatformMemAllocate(sizeof(CC_SHA256_CTX));
174 if (!ptr) return mStatus_NoMemoryErr;
175 CC_SHA256_Init((CC_SHA256_CTX *)ptr);
176 break;
177 default:
178 LogMsg("sha_create: Unsupported algorithm %d", ctx->alg);
179 return mStatus_BadParamErr;
180 }
181 ctx->context = ptr;
182 return mStatus_NoError;
183 }
184
185 mDNSlocal mStatus sha_destroy(AlgContext *ctx)
186 {
187 mDNSPlatformMemFree(ctx->context);
188 return mStatus_NoError;
189 }
190
191 mDNSlocal mDNSu32 sha_len(AlgContext *ctx)
192 {
193 switch (ctx->alg)
194 {
195 case SHA1_DIGEST_TYPE:
196 return CC_SHA1_DIGEST_LENGTH;
197 case SHA256_DIGEST_TYPE:
198 return CC_SHA256_DIGEST_LENGTH;
199 default:
200 LogMsg("sha_len: Unsupported algorithm %d", ctx->alg);
201 return mStatus_BadParamErr;
202 }
203 }
204
205 mDNSlocal mStatus sha_add(AlgContext *ctx, void *data, mDNSu32 len)
206 {
207 switch (ctx->alg)
208 {
209 case SHA1_DIGEST_TYPE:
210 CC_SHA1_Update((CC_SHA1_CTX *)ctx->context, data, len);
211 break;
212 case SHA256_DIGEST_TYPE:
213 CC_SHA256_Update((CC_SHA256_CTX *)ctx->context, data, len);
214 break;
215 default:
216 LogMsg("sha_add: Unsupported algorithm %d", ctx->alg);
217 return mStatus_BadParamErr;
218 }
219 return mStatus_NoError;
220 }
221
222 mDNSlocal mStatus sha_verify(AlgContext *ctx, mDNSu8 *key, mDNSu32 keylen, mDNSu8 *digestIn, mDNSu32 dlen)
223 {
224 mDNSu8 digest[CC_SHA512_DIGEST_LENGTH];
225 mDNSu32 digestLen;
226
227 (void) key; //unused
228 (void)keylen; //unused
229 switch (ctx->alg)
230 {
231 case SHA1_DIGEST_TYPE:
232 digestLen = CC_SHA1_DIGEST_LENGTH;
233 CC_SHA1_Final(digest, (CC_SHA1_CTX *)ctx->context);
234 break;
235 case SHA256_DIGEST_TYPE:
236 digestLen = CC_SHA256_DIGEST_LENGTH;
237 CC_SHA256_Final(digest, (CC_SHA256_CTX *)ctx->context);
238 break;
239 default:
240 LogMsg("sha_verify: Unsupported algorithm %d", ctx->alg);
241 return mStatus_BadParamErr;
242 }
243 if (dlen != digestLen)
244 {
245 LogMsg("sha_verify(Alg %d): digest len mismatch len %u, expected %u", ctx->alg, (unsigned int)dlen, (unsigned int)digestLen);
246 return mStatus_BadParamErr;
247 }
248 if (!memcmp(digest, digestIn, digestLen))
249 return mStatus_NoError;
250 else
251 return mStatus_NoAuth;
252 }
253
254 mDNSlocal mStatus rsa_sha_create(AlgContext *ctx)
255 {
256 mDNSu8 *ptr;
257 switch (ctx->alg)
258 {
259 case CRYPTO_RSA_NSEC3_SHA1:
260 case CRYPTO_RSA_SHA1:
261 ptr = mDNSPlatformMemAllocate(sizeof(CC_SHA1_CTX));
262 if (!ptr) return mStatus_NoMemoryErr;
263 CC_SHA1_Init((CC_SHA1_CTX *)ptr);
264 break;
265 case CRYPTO_RSA_SHA256:
266 ptr = mDNSPlatformMemAllocate(sizeof(CC_SHA256_CTX));
267 if (!ptr) return mStatus_NoMemoryErr;
268 CC_SHA256_Init((CC_SHA256_CTX *)ptr);
269 break;
270 case CRYPTO_RSA_SHA512:
271 ptr = mDNSPlatformMemAllocate(sizeof(CC_SHA512_CTX));
272 if (!ptr) return mStatus_NoMemoryErr;
273 CC_SHA512_Init((CC_SHA512_CTX *)ptr);
274 break;
275 default:
276 LogMsg("rsa_sha_create: Unsupported algorithm %d", ctx->alg);
277 return mStatus_BadParamErr;
278 }
279 ctx->context = ptr;
280 return mStatus_NoError;
281 }
282
283 mDNSlocal mStatus rsa_sha_destroy(AlgContext *ctx)
284 {
285 mDNSPlatformMemFree(ctx->context);
286 return mStatus_NoError;
287 }
288
289 mDNSlocal mDNSu32 rsa_sha_len(AlgContext *ctx)
290 {
291 switch (ctx->alg)
292 {
293 case CRYPTO_RSA_NSEC3_SHA1:
294 case CRYPTO_RSA_SHA1:
295 return CC_SHA1_DIGEST_LENGTH;
296 case CRYPTO_RSA_SHA256:
297 return CC_SHA256_DIGEST_LENGTH;
298 case CRYPTO_RSA_SHA512:
299 return CC_SHA512_DIGEST_LENGTH;
300 default:
301 LogMsg("rsa_sha_len: Unsupported algorithm %d", ctx->alg);
302 return mStatus_BadParamErr;
303 }
304 }
305
306 mDNSlocal mStatus rsa_sha_add(AlgContext *ctx, void *data, mDNSu32 len)
307 {
308 switch (ctx->alg)
309 {
310 case CRYPTO_RSA_NSEC3_SHA1:
311 case CRYPTO_RSA_SHA1:
312 CC_SHA1_Update((CC_SHA1_CTX *)ctx->context, data, len);
313 break;
314 case CRYPTO_RSA_SHA256:
315 CC_SHA256_Update((CC_SHA256_CTX *)ctx->context, data, len);
316 break;
317 case CRYPTO_RSA_SHA512:
318 CC_SHA512_Update((CC_SHA512_CTX *)ctx->context, data, len);
319 break;
320 default:
321 LogMsg("rsa_sha_add: Unsupported algorithm %d", ctx->alg);
322 return mStatus_BadParamErr;
323 }
324 return mStatus_NoError;
325 }
326
327 #if TARGET_OS_IPHONE
328 mDNSlocal SecKeyRef rfc3110_import(const mDNSu8 *data, const mDNSu32 len)
329 {
330 static const int max_key_bytes = 4096 / 8; // max DNSSEC supported modulus is 4096 bits
331 static const int max_exp_bytes = 3; // DNSSEC supports 1 or 3 bytes for exponent
332 static const int asn1_cmd_bytes = 3; // since there is an ASN1 SEQ and two INTs
333 //static const int asn1_max_len_bytes = asn1_cmd_bytes * 3; // capped at 3 due to max payload size
334 static const int asn1_max_len_bytes = 3 * 3; // capped at 3 due to max payload size
335 unsigned char asn1[max_key_bytes + 1 + max_exp_bytes + asn1_cmd_bytes + asn1_max_len_bytes]; // +1 is for leading 0 for non negative asn1 number
336 const mDNSu8 *modulus;
337 unsigned int modulus_length;
338 unsigned int exp_length;
339 mDNSu32 index = 0;
340 mDNSu32 asn1_length = 0;
341 unsigned int i;
342
343 // Validate Input
344 if (!data)
345 return NULL;
346
347 // we have to have at least 1 byte for the length
348 if (len < 1)
349 return NULL;
350
351 // Parse Modulus and Exponent
352 exp_length = data[0];
353
354 // we have to have at least len byte + size of exponent
355 if (len < 1+exp_length)
356 return NULL;
357
358 // -1 is for the exp_length byte
359 modulus_length = len - 1 - exp_length;
360
361 // rfc3110 limits modulus to 4096 bits
362 if (modulus_length > 512)
363 return NULL;
364
365 if (modulus_length < 1)
366 return NULL;
367
368 // add 1 to modulus length for pre-ceding 0 t make ASN1 value non-negative
369 ++modulus_length;
370
371 // 1 is to skip exp_length byte
372 modulus = &data[1+exp_length];
373
374 // 2 bytes for commands since first doesn't count
375 // 2 bytes for min 1 byte length field
376 asn1_length = modulus_length + exp_length + 2 + 2;
377
378 // account for modulus length causing INT length field to grow
379 if (modulus_length > 0xFF)
380 asn1_length += 2;
381 else if (modulus_length >= 128)
382 ++asn1_length;
383
384 // Construct ASN1 formatted public key
385 // Write ASN1 SEQ byte
386 asn1[index++] = 0x30;
387
388 // Write ASN1 length for SEQ
389 if (asn1_length < 128)
390 {
391 asn1[index++] = asn1_length & 0xFF;
392 }
393 else
394 {
395 asn1[index++] = (0x80 | ((asn1_length & 0xFF00) ? 2 : 1));
396 if (asn1_length & 0xFF00)
397 asn1[index++] = (asn1_length & 0xFF00) >> 8;
398 asn1[index++] = asn1_length & 0xFF;
399 }
400
401 // Write ASN1 INT for modulus
402 asn1[index++] = 0x02;
403 // Write ASN1 length for INT
404 if (modulus_length < 128)
405 {
406 asn1[index++] = asn1_length & 0xFF;
407 }
408 else
409 {
410 asn1[index++] = 0x80 | ((modulus_length & 0xFF00) ? 2 : 1);
411 if (modulus_length & 0xFF00)
412 asn1[index++] = (modulus_length & 0xFF00) >> 8;
413 asn1[index++] = modulus_length & 0xFF;
414 }
415
416 // Write preceding 0 so our integer isn't negative
417 asn1[index++] = 0x00;
418 // Write actual modulus (-1 for preceding 0)
419 memcpy(&asn1[index], (void *)modulus, modulus_length-1);
420 index += modulus_length-1;
421
422 // Write ASN1 INT for exponent
423 asn1[index++] = 0x02;
424 // Write ASN1 length for INT
425 asn1[index++] = exp_length & 0xFF;
426 // Write exponent bytes
427 for (i = 1; i <= exp_length; i++)
428 asn1[index++] = data[i];
429
430 // index contains bytes written, use it for length
431 return SecKeyCreateRSAPublicKey(NULL, asn1, index, kSecKeyEncodingPkcs1);
432 }
433
434 mDNSlocal mStatus rsa_sha_verify(AlgContext *ctx, mDNSu8 *key, mDNSu32 keylen, mDNSu8 *signature, mDNSu32 siglen)
435 {
436 SecKeyRef keyref;
437 OSStatus result;
438 mDNSu8 digest[CC_SHA512_DIGEST_LENGTH];
439 int digestlen;
440
441 switch (ctx->alg)
442 {
443 case CRYPTO_RSA_NSEC3_SHA1:
444 case CRYPTO_RSA_SHA1:
445 digestlen = CC_SHA1_DIGEST_LENGTH;
446 CC_SHA1_Final(digest, (CC_SHA1_CTX *)ctx->context);
447 break;
448 case CRYPTO_RSA_SHA256:
449 digestlen = CC_SHA256_DIGEST_LENGTH;
450 CC_SHA256_Final(digest, (CC_SHA256_CTX *)ctx->context);
451 break;
452 case CRYPTO_RSA_SHA512:
453 digestlen = CC_SHA512_DIGEST_LENGTH;
454 CC_SHA512_Final(digest, (CC_SHA512_CTX *)ctx->context);
455 break;
456 default:
457 LogMsg("rsa_sha_verify: Unsupported algorithm %d", ctx->alg);
458 return mStatus_BadParamErr;
459 }
460
461 keyref = rfc3110_import(key, keylen);
462 if (!key)
463 {
464 LogMsg("rsa_sha_verify: Error decoding rfc3110 key data");
465 return mStatus_NoMemoryErr;
466 }
467 // TBD: Use the right algorithm when the support becomes available
468 result = SecKeyRawVerify(keyref, kSecPaddingPKCS1SHA1, digest, digestlen, signature, siglen);
469 LogMsg("rsa_sha_verify: result: %s (%ld)", result == noErr ? "PASS" : "FAIL", result);
470 if (result == noErr)
471 return mStatus_NoError;
472 else
473 return mStatus_BadParamErr;
474 }
475 #else
476 mDNSlocal mStatus rsa_sha_verify(AlgContext *ctx, mDNSu8 *key, mDNSu32 keylen, mDNSu8 *signature, mDNSu32 siglen)
477 {
478 (void)ctx;
479 (void)key;
480 (void)keylen;
481 (void)signature;
482 (void)siglen;
483 return mStatus_NoError;
484 }
485 #endif
486
487 AlgFuncs sha_funcs = {sha_create, sha_destroy, sha_len, sha_add, sha_verify, mDNSNULL};
488 AlgFuncs rsa_sha_funcs = {rsa_sha_create, rsa_sha_destroy, rsa_sha_len, rsa_sha_add, rsa_sha_verify, mDNSNULL};
489 AlgFuncs enc_funcs = {enc_create, enc_destroy, mDNSNULL, enc_add, mDNSNULL, enc_encode};
490
491 mDNSexport mStatus DNSSECCryptoInit(mDNS *const m)
492 {
493 mStatus result;
494
495 result = DigestAlgInit(SHA1_DIGEST_TYPE, &sha_funcs);
496 if (result != mStatus_NoError)
497 return result;
498 result = DigestAlgInit(SHA256_DIGEST_TYPE, &sha_funcs);
499 if (result != mStatus_NoError)
500 return result;
501 result = CryptoAlgInit(CRYPTO_RSA_SHA1, &rsa_sha_funcs);
502 if (result != mStatus_NoError)
503 return result;
504 result = CryptoAlgInit(CRYPTO_RSA_NSEC3_SHA1, &rsa_sha_funcs);
505 if (result != mStatus_NoError)
506 return result;
507 result = CryptoAlgInit(CRYPTO_RSA_SHA256, &rsa_sha_funcs);
508 if (result != mStatus_NoError)
509 return result;
510 result = CryptoAlgInit(CRYPTO_RSA_SHA512, &rsa_sha_funcs);
511 if (result != mStatus_NoError)
512 return result;
513 result = EncAlgInit(ENC_BASE32, &enc_funcs);
514 if (result != mStatus_NoError)
515 return result;
516 result = EncAlgInit(ENC_BASE64, &enc_funcs);
517 if (result != mStatus_NoError)
518 return result;
519
520 m->TrustAnchors = mDNSNULL;
521 m->notifyToken = 0;
522
523 return mStatus_NoError;
524 }