1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2011 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 // ***************************************************************************
20 // Supporting routines for DNSSEC crypto
21 // ***************************************************************************
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"
32 #include "SecRSAKey.h" // For RSA_SHA1 etc. verification
37 #if DISPATCH_API_VERSION >= 20111008
38 dispatch_data_t encData
;
39 dispatch_data_t encMap
;
40 dispatch_data_t encNULL
;
44 mDNSlocal mStatus
enc_create(AlgContext
*ctx
)
52 ptr
= (encContext
*)mDNSPlatformMemAllocate(sizeof(encContext
));
53 if (!ptr
) return mStatus_NoMemoryErr
;
56 LogMsg("enc_create: Unsupported algorithm %d", ctx
->alg
);
57 return mStatus_BadParamErr
;
59 #if DISPATCH_API_VERSION >= 20111008
62 // The encoded data is not NULL terminated. So, we concatenate a null byte later when we encode and map
64 ptr
->encNULL
= dispatch_data_create("", 1, dispatch_get_global_queue(0, 0), ^{});
67 mDNSPlatformMemFree(ptr
);
68 return mStatus_NoMemoryErr
;
72 return mStatus_NoError
;
75 mDNSlocal mStatus
enc_destroy(AlgContext
*ctx
)
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
);
83 mDNSPlatformMemFree(ptr
);
84 return mStatus_NoError
;
87 mDNSlocal mStatus
enc_add(AlgContext
*ctx
, void *data
, mDNSu32 len
)
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), ^{});
99 LogMsg("enc_add: dispatch_data_create src failed");
100 return mStatus_BadParamErr
;
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
);
107 LogMsg("enc_add: dispatch_data_create dst failed");
108 return mStatus_BadParamErr
;
110 ptr
->encData
= dest_data
;
115 return mStatus_NoError
;
118 LogMsg("enc_add: Unsupported algorithm %d", ctx
->alg
);
119 return mStatus_BadParamErr
;
123 mDNSlocal mDNSu8
* enc_encode(AlgContext
*ctx
)
125 const void *result
= NULL
;
132 #if DISPATCH_API_VERSION >= 20111008
133 encContext
*ptr
= (encContext
*)ctx
->context
;
135 dispatch_data_t dest_data
= ptr
->encData
;
136 dispatch_data_t data
= dispatch_data_create_concat(dest_data
, ptr
->encNULL
);
140 LogMsg("enc_encode: cannot concatenate");
144 dispatch_data_t map
= dispatch_data_create_map(data
, &result
, &size
);
147 LogMsg("enc_encode: cannot create map %d", ctx
->alg
);
150 dispatch_release(dest_data
);
154 return (mDNSu8
*)result
;
157 LogMsg("enc_encode: Unsupported algorithm %d", ctx
->alg
);
162 mDNSlocal mStatus
sha_create(AlgContext
*ctx
)
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
);
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
);
178 LogMsg("sha_create: Unsupported algorithm %d", ctx
->alg
);
179 return mStatus_BadParamErr
;
182 return mStatus_NoError
;
185 mDNSlocal mStatus
sha_destroy(AlgContext
*ctx
)
187 mDNSPlatformMemFree(ctx
->context
);
188 return mStatus_NoError
;
191 mDNSlocal mDNSu32
sha_len(AlgContext
*ctx
)
195 case SHA1_DIGEST_TYPE
:
196 return CC_SHA1_DIGEST_LENGTH
;
197 case SHA256_DIGEST_TYPE
:
198 return CC_SHA256_DIGEST_LENGTH
;
200 LogMsg("sha_len: Unsupported algorithm %d", ctx
->alg
);
201 return mStatus_BadParamErr
;
205 mDNSlocal mStatus
sha_add(AlgContext
*ctx
, void *data
, mDNSu32 len
)
209 case SHA1_DIGEST_TYPE
:
210 CC_SHA1_Update((CC_SHA1_CTX
*)ctx
->context
, data
, len
);
212 case SHA256_DIGEST_TYPE
:
213 CC_SHA256_Update((CC_SHA256_CTX
*)ctx
->context
, data
, len
);
216 LogMsg("sha_add: Unsupported algorithm %d", ctx
->alg
);
217 return mStatus_BadParamErr
;
219 return mStatus_NoError
;
222 mDNSlocal mStatus
sha_verify(AlgContext
*ctx
, mDNSu8
*key
, mDNSu32 keylen
, mDNSu8
*digestIn
, mDNSu32 dlen
)
224 mDNSu8 digest
[CC_SHA512_DIGEST_LENGTH
];
228 (void)keylen
; //unused
231 case SHA1_DIGEST_TYPE
:
232 digestLen
= CC_SHA1_DIGEST_LENGTH
;
233 CC_SHA1_Final(digest
, (CC_SHA1_CTX
*)ctx
->context
);
235 case SHA256_DIGEST_TYPE
:
236 digestLen
= CC_SHA256_DIGEST_LENGTH
;
237 CC_SHA256_Final(digest
, (CC_SHA256_CTX
*)ctx
->context
);
240 LogMsg("sha_verify: Unsupported algorithm %d", ctx
->alg
);
241 return mStatus_BadParamErr
;
243 if (dlen
!= digestLen
)
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
;
248 if (!memcmp(digest
, digestIn
, digestLen
))
249 return mStatus_NoError
;
251 return mStatus_NoAuth
;
254 mDNSlocal mStatus
rsa_sha_create(AlgContext
*ctx
)
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
);
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
);
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
);
276 LogMsg("rsa_sha_create: Unsupported algorithm %d", ctx
->alg
);
277 return mStatus_BadParamErr
;
280 return mStatus_NoError
;
283 mDNSlocal mStatus
rsa_sha_destroy(AlgContext
*ctx
)
285 mDNSPlatformMemFree(ctx
->context
);
286 return mStatus_NoError
;
289 mDNSlocal mDNSu32
rsa_sha_len(AlgContext
*ctx
)
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
;
301 LogMsg("rsa_sha_len: Unsupported algorithm %d", ctx
->alg
);
302 return mStatus_BadParamErr
;
306 mDNSlocal mStatus
rsa_sha_add(AlgContext
*ctx
, void *data
, mDNSu32 len
)
310 case CRYPTO_RSA_NSEC3_SHA1
:
311 case CRYPTO_RSA_SHA1
:
312 CC_SHA1_Update((CC_SHA1_CTX
*)ctx
->context
, data
, len
);
314 case CRYPTO_RSA_SHA256
:
315 CC_SHA256_Update((CC_SHA256_CTX
*)ctx
->context
, data
, len
);
317 case CRYPTO_RSA_SHA512
:
318 CC_SHA512_Update((CC_SHA512_CTX
*)ctx
->context
, data
, len
);
321 LogMsg("rsa_sha_add: Unsupported algorithm %d", ctx
->alg
);
322 return mStatus_BadParamErr
;
324 return mStatus_NoError
;
328 mDNSlocal SecKeyRef
rfc3110_import(const mDNSu8
*data
, const mDNSu32 len
)
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
;
340 mDNSu32 asn1_length
= 0;
347 // we have to have at least 1 byte for the length
351 // Parse Modulus and Exponent
352 exp_length
= data
[0];
354 // we have to have at least len byte + size of exponent
355 if (len
< 1+exp_length
)
358 // -1 is for the exp_length byte
359 modulus_length
= len
- 1 - exp_length
;
361 // rfc3110 limits modulus to 4096 bits
362 if (modulus_length
> 512)
365 if (modulus_length
< 1)
368 // add 1 to modulus length for pre-ceding 0 t make ASN1 value non-negative
371 // 1 is to skip exp_length byte
372 modulus
= &data
[1+exp_length
];
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;
378 // account for modulus length causing INT length field to grow
379 if (modulus_length
> 0xFF)
381 else if (modulus_length
>= 128)
384 // Construct ASN1 formatted public key
385 // Write ASN1 SEQ byte
386 asn1
[index
++] = 0x30;
388 // Write ASN1 length for SEQ
389 if (asn1_length
< 128)
391 asn1
[index
++] = asn1_length
& 0xFF;
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;
401 // Write ASN1 INT for modulus
402 asn1
[index
++] = 0x02;
403 // Write ASN1 length for INT
404 if (modulus_length
< 128)
406 asn1
[index
++] = asn1_length
& 0xFF;
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;
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;
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
];
430 // index contains bytes written, use it for length
431 return SecKeyCreateRSAPublicKey(NULL
, asn1
, index
, kSecKeyEncodingPkcs1
);
434 mDNSlocal mStatus
rsa_sha_verify(AlgContext
*ctx
, mDNSu8
*key
, mDNSu32 keylen
, mDNSu8
*signature
, mDNSu32 siglen
)
438 mDNSu8 digest
[CC_SHA512_DIGEST_LENGTH
];
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
);
448 case CRYPTO_RSA_SHA256
:
449 digestlen
= CC_SHA256_DIGEST_LENGTH
;
450 CC_SHA256_Final(digest
, (CC_SHA256_CTX
*)ctx
->context
);
452 case CRYPTO_RSA_SHA512
:
453 digestlen
= CC_SHA512_DIGEST_LENGTH
;
454 CC_SHA512_Final(digest
, (CC_SHA512_CTX
*)ctx
->context
);
457 LogMsg("rsa_sha_verify: Unsupported algorithm %d", ctx
->alg
);
458 return mStatus_BadParamErr
;
461 keyref
= rfc3110_import(key
, keylen
);
464 LogMsg("rsa_sha_verify: Error decoding rfc3110 key data");
465 return mStatus_NoMemoryErr
;
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
);
471 return mStatus_NoError
;
473 return mStatus_BadParamErr
;
476 mDNSlocal mStatus
rsa_sha_verify(AlgContext
*ctx
, mDNSu8
*key
, mDNSu32 keylen
, mDNSu8
*signature
, mDNSu32 siglen
)
483 return mStatus_NoError
;
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
};
491 mDNSexport mStatus
DNSSECCryptoInit(mDNS
*const m
)
495 result
= DigestAlgInit(SHA1_DIGEST_TYPE
, &sha_funcs
);
496 if (result
!= mStatus_NoError
)
498 result
= DigestAlgInit(SHA256_DIGEST_TYPE
, &sha_funcs
);
499 if (result
!= mStatus_NoError
)
501 result
= CryptoAlgInit(CRYPTO_RSA_SHA1
, &rsa_sha_funcs
);
502 if (result
!= mStatus_NoError
)
504 result
= CryptoAlgInit(CRYPTO_RSA_NSEC3_SHA1
, &rsa_sha_funcs
);
505 if (result
!= mStatus_NoError
)
507 result
= CryptoAlgInit(CRYPTO_RSA_SHA256
, &rsa_sha_funcs
);
508 if (result
!= mStatus_NoError
)
510 result
= CryptoAlgInit(CRYPTO_RSA_SHA512
, &rsa_sha_funcs
);
511 if (result
!= mStatus_NoError
)
513 result
= EncAlgInit(ENC_BASE32
, &enc_funcs
);
514 if (result
!= mStatus_NoError
)
516 result
= EncAlgInit(ENC_BASE64
, &enc_funcs
);
517 if (result
!= mStatus_NoError
)
520 m
->TrustAnchors
= mDNSNULL
;
523 return mStatus_NoError
;