mirror of
https://git.rtems.org/rtems-libbsd/
synced 2025-06-05 17:00:21 +08:00

The sources can be obtained via: https://opensource.apple.com/tarballs/mDNSResponder/mDNSResponder-625.41.2.tar.gz Update #3522.
781 lines
23 KiB
C
781 lines
23 KiB
C
/* -*- Mode: C; tab-width: 4 -*-
|
|
*
|
|
* Copyright (c) 2011-2013 Apple Inc. All rights reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
// ***************************************************************************
|
|
// CryptoSupport.c
|
|
// Supporting routines for DNSSEC crypto
|
|
// ***************************************************************************
|
|
|
|
#include "mDNSEmbeddedAPI.h"
|
|
#include <CommonCrypto/CommonDigest.h> // For Hash algorithms SHA1 etc.
|
|
#include <dispatch/dispatch.h> // For Base32/Base64 encoding/decoding
|
|
#include <dispatch/private.h> // dispatch_data_create_with_transform
|
|
#include "CryptoAlg.h"
|
|
#include "CryptoSupport.h"
|
|
#include "dnssec.h"
|
|
#include "DNSSECSupport.h"
|
|
|
|
#if TARGET_OS_IPHONE
|
|
#include "SecRSAKey.h" // For RSA_SHA1 etc. verification
|
|
#else
|
|
#include <Security/Security.h>
|
|
#endif
|
|
|
|
#if !TARGET_OS_IPHONE
|
|
mDNSlocal SecKeyRef SecKeyCreateRSAPublicKey_OSX(unsigned char *asn1, int length);
|
|
#endif
|
|
|
|
typedef struct
|
|
{
|
|
dispatch_data_t encData;
|
|
dispatch_data_t encMap;
|
|
dispatch_data_t encNULL;
|
|
}encContext;
|
|
|
|
mDNSlocal mStatus enc_create(AlgContext *ctx)
|
|
{
|
|
encContext *ptr;
|
|
|
|
switch (ctx->alg)
|
|
{
|
|
case ENC_BASE32:
|
|
case ENC_BASE64:
|
|
ptr = (encContext *)mDNSPlatformMemAllocate(sizeof(encContext));
|
|
if (!ptr) return mStatus_NoMemoryErr;
|
|
break;
|
|
default:
|
|
LogMsg("enc_create: Unsupported algorithm %d", ctx->alg);
|
|
return mStatus_BadParamErr;
|
|
}
|
|
ptr->encData = NULL;
|
|
ptr->encMap = NULL;
|
|
// The encoded data is not NULL terminated. So, we concatenate a null byte later when we encode and map
|
|
// the real data.
|
|
ptr->encNULL = dispatch_data_create("", 1, dispatch_get_global_queue(0, 0), ^{});
|
|
if (!ptr->encNULL)
|
|
{
|
|
mDNSPlatformMemFree(ptr);
|
|
return mStatus_NoMemoryErr;
|
|
}
|
|
ctx->context = ptr;
|
|
return mStatus_NoError;
|
|
}
|
|
|
|
mDNSlocal mStatus enc_destroy(AlgContext *ctx)
|
|
{
|
|
encContext *ptr = (encContext *)ctx->context;
|
|
if (ptr->encData) dispatch_release(ptr->encData);
|
|
if (ptr->encMap) dispatch_release(ptr->encMap);
|
|
if (ptr->encNULL) dispatch_release(ptr->encNULL);
|
|
mDNSPlatformMemFree(ptr);
|
|
return mStatus_NoError;
|
|
}
|
|
|
|
mDNSlocal mStatus enc_add(AlgContext *ctx, const void *data, mDNSu32 len)
|
|
{
|
|
switch (ctx->alg)
|
|
{
|
|
case ENC_BASE32:
|
|
case ENC_BASE64:
|
|
{
|
|
encContext *ptr = (encContext *)ctx->context;
|
|
dispatch_data_t src_data = dispatch_data_create(data, len, dispatch_get_global_queue(0, 0), ^{});
|
|
if (!src_data)
|
|
{
|
|
LogMsg("enc_add: dispatch_data_create src failed");
|
|
return mStatus_BadParamErr;
|
|
}
|
|
dispatch_data_t dest_data = dispatch_data_create_with_transform(src_data, DISPATCH_DATA_FORMAT_TYPE_NONE,
|
|
(ctx->alg == ENC_BASE32 ? DISPATCH_DATA_FORMAT_TYPE_BASE32HEX : DISPATCH_DATA_FORMAT_TYPE_BASE64));
|
|
dispatch_release(src_data);
|
|
if (!dest_data)
|
|
{
|
|
LogMsg("enc_add: dispatch_data_create dst failed");
|
|
return mStatus_BadParamErr;
|
|
}
|
|
ptr->encData = dest_data;
|
|
|
|
return mStatus_NoError;
|
|
}
|
|
default:
|
|
LogMsg("enc_add: Unsupported algorithm %d", ctx->alg);
|
|
return mStatus_BadParamErr;
|
|
}
|
|
}
|
|
|
|
mDNSlocal mDNSu8* enc_encode(AlgContext *ctx)
|
|
{
|
|
const void *result = NULL;
|
|
|
|
switch (ctx->alg)
|
|
{
|
|
case ENC_BASE32:
|
|
case ENC_BASE64:
|
|
{
|
|
encContext *ptr = (encContext *)ctx->context;
|
|
size_t size;
|
|
dispatch_data_t dest_data = ptr->encData;
|
|
dispatch_data_t data = dispatch_data_create_concat(dest_data, ptr->encNULL);
|
|
|
|
if (!data)
|
|
{
|
|
LogMsg("enc_encode: cannot concatenate");
|
|
return NULL;
|
|
}
|
|
|
|
dispatch_data_t map = dispatch_data_create_map(data, &result, &size);
|
|
if (!map)
|
|
{
|
|
LogMsg("enc_encode: cannot create map %d", ctx->alg);
|
|
return NULL;
|
|
}
|
|
dispatch_release(dest_data);
|
|
ptr->encData = data;
|
|
ptr->encMap = map;
|
|
|
|
return (mDNSu8 *)result;
|
|
}
|
|
default:
|
|
LogMsg("enc_encode: Unsupported algorithm %d", ctx->alg);
|
|
return mDNSNULL;
|
|
}
|
|
}
|
|
|
|
mDNSlocal mStatus sha_create(AlgContext *ctx)
|
|
{
|
|
mDNSu8 *ptr;
|
|
switch (ctx->alg)
|
|
{
|
|
case SHA1_DIGEST_TYPE:
|
|
ptr = mDNSPlatformMemAllocate(sizeof(CC_SHA1_CTX));
|
|
if (!ptr) return mStatus_NoMemoryErr;
|
|
CC_SHA1_Init((CC_SHA1_CTX *)ptr);
|
|
break;
|
|
case SHA256_DIGEST_TYPE:
|
|
ptr = mDNSPlatformMemAllocate(sizeof(CC_SHA256_CTX));
|
|
if (!ptr) return mStatus_NoMemoryErr;
|
|
CC_SHA256_Init((CC_SHA256_CTX *)ptr);
|
|
break;
|
|
default:
|
|
LogMsg("sha_create: Unsupported algorithm %d", ctx->alg);
|
|
return mStatus_BadParamErr;
|
|
}
|
|
ctx->context = ptr;
|
|
return mStatus_NoError;
|
|
}
|
|
|
|
mDNSlocal mStatus sha_destroy(AlgContext *ctx)
|
|
{
|
|
mDNSPlatformMemFree(ctx->context);
|
|
return mStatus_NoError;
|
|
}
|
|
|
|
mDNSlocal mDNSu32 sha_len(AlgContext *ctx)
|
|
{
|
|
switch (ctx->alg)
|
|
{
|
|
case SHA1_DIGEST_TYPE:
|
|
return CC_SHA1_DIGEST_LENGTH;
|
|
case SHA256_DIGEST_TYPE:
|
|
return CC_SHA256_DIGEST_LENGTH;
|
|
default:
|
|
LogMsg("sha_len: Unsupported algorithm %d", ctx->alg);
|
|
return mStatus_BadParamErr;
|
|
}
|
|
}
|
|
|
|
mDNSlocal mStatus sha_add(AlgContext *ctx, const void *data, mDNSu32 len)
|
|
{
|
|
switch (ctx->alg)
|
|
{
|
|
case SHA1_DIGEST_TYPE:
|
|
CC_SHA1_Update((CC_SHA1_CTX *)ctx->context, data, len);
|
|
break;
|
|
case SHA256_DIGEST_TYPE:
|
|
CC_SHA256_Update((CC_SHA256_CTX *)ctx->context, data, len);
|
|
break;
|
|
default:
|
|
LogMsg("sha_add: Unsupported algorithm %d", ctx->alg);
|
|
return mStatus_BadParamErr;
|
|
}
|
|
return mStatus_NoError;
|
|
}
|
|
|
|
mDNSlocal mStatus sha_verify(AlgContext *ctx, mDNSu8 *key, mDNSu32 keylen, mDNSu8 *digestIn, mDNSu32 dlen)
|
|
{
|
|
mDNSu8 digest[CC_SHA512_DIGEST_LENGTH];
|
|
mDNSu32 digestLen;
|
|
|
|
(void) key; //unused
|
|
(void)keylen; //unused
|
|
switch (ctx->alg)
|
|
{
|
|
case SHA1_DIGEST_TYPE:
|
|
digestLen = CC_SHA1_DIGEST_LENGTH;
|
|
CC_SHA1_Final(digest, (CC_SHA1_CTX *)ctx->context);
|
|
break;
|
|
case SHA256_DIGEST_TYPE:
|
|
digestLen = CC_SHA256_DIGEST_LENGTH;
|
|
CC_SHA256_Final(digest, (CC_SHA256_CTX *)ctx->context);
|
|
break;
|
|
default:
|
|
LogMsg("sha_verify: Unsupported algorithm %d", ctx->alg);
|
|
return mStatus_BadParamErr;
|
|
}
|
|
if (dlen != digestLen)
|
|
{
|
|
LogMsg("sha_verify(Alg %d): digest len mismatch len %u, expected %u", ctx->alg, (unsigned int)dlen, (unsigned int)digestLen);
|
|
return mStatus_BadParamErr;
|
|
}
|
|
if (!memcmp(digest, digestIn, digestLen))
|
|
return mStatus_NoError;
|
|
else
|
|
return mStatus_NoAuth;
|
|
}
|
|
|
|
mDNSlocal mStatus sha_final(AlgContext *ctx, void *digestOut, mDNSu32 dlen)
|
|
{
|
|
mDNSu8 digest[CC_SHA512_DIGEST_LENGTH];
|
|
mDNSu32 digestLen;
|
|
|
|
switch (ctx->alg)
|
|
{
|
|
case SHA1_DIGEST_TYPE:
|
|
digestLen = CC_SHA1_DIGEST_LENGTH;
|
|
CC_SHA1_Final(digest, (CC_SHA1_CTX *)ctx->context);
|
|
break;
|
|
case SHA256_DIGEST_TYPE:
|
|
digestLen = CC_SHA256_DIGEST_LENGTH;
|
|
CC_SHA256_Final(digest, (CC_SHA256_CTX *)ctx->context);
|
|
break;
|
|
default:
|
|
LogMsg("sha_final: Unsupported algorithm %d", ctx->alg);
|
|
return mStatus_BadParamErr;
|
|
}
|
|
if (dlen != digestLen)
|
|
{
|
|
LogMsg("sha_final(Alg %d): digest len mismatch len %u, expected %u", ctx->alg, (unsigned int)dlen, (unsigned int)digestLen);
|
|
return mStatus_BadParamErr;
|
|
}
|
|
memcpy(digestOut, digest, digestLen);
|
|
return mStatus_NoError;
|
|
}
|
|
|
|
mDNSlocal mStatus rsa_sha_create(AlgContext *ctx)
|
|
{
|
|
mDNSu8 *ptr;
|
|
switch (ctx->alg)
|
|
{
|
|
case CRYPTO_RSA_NSEC3_SHA1:
|
|
case CRYPTO_RSA_SHA1:
|
|
ptr = mDNSPlatformMemAllocate(sizeof(CC_SHA1_CTX));
|
|
if (!ptr) return mStatus_NoMemoryErr;
|
|
CC_SHA1_Init((CC_SHA1_CTX *)ptr);
|
|
break;
|
|
case CRYPTO_RSA_SHA256:
|
|
ptr = mDNSPlatformMemAllocate(sizeof(CC_SHA256_CTX));
|
|
if (!ptr) return mStatus_NoMemoryErr;
|
|
CC_SHA256_Init((CC_SHA256_CTX *)ptr);
|
|
break;
|
|
case CRYPTO_RSA_SHA512:
|
|
ptr = mDNSPlatformMemAllocate(sizeof(CC_SHA512_CTX));
|
|
if (!ptr) return mStatus_NoMemoryErr;
|
|
CC_SHA512_Init((CC_SHA512_CTX *)ptr);
|
|
break;
|
|
default:
|
|
LogMsg("rsa_sha_create: Unsupported algorithm %d", ctx->alg);
|
|
return mStatus_BadParamErr;
|
|
}
|
|
ctx->context = ptr;
|
|
return mStatus_NoError;
|
|
}
|
|
|
|
mDNSlocal mStatus rsa_sha_destroy(AlgContext *ctx)
|
|
{
|
|
mDNSPlatformMemFree(ctx->context);
|
|
return mStatus_NoError;
|
|
}
|
|
|
|
mDNSlocal mDNSu32 rsa_sha_len(AlgContext *ctx)
|
|
{
|
|
switch (ctx->alg)
|
|
{
|
|
case CRYPTO_RSA_NSEC3_SHA1:
|
|
case CRYPTO_RSA_SHA1:
|
|
return CC_SHA1_DIGEST_LENGTH;
|
|
case CRYPTO_RSA_SHA256:
|
|
return CC_SHA256_DIGEST_LENGTH;
|
|
case CRYPTO_RSA_SHA512:
|
|
return CC_SHA512_DIGEST_LENGTH;
|
|
default:
|
|
LogMsg("rsa_sha_len: Unsupported algorithm %d", ctx->alg);
|
|
return mStatus_BadParamErr;
|
|
}
|
|
}
|
|
|
|
mDNSlocal mStatus rsa_sha_add(AlgContext *ctx, const void *data, mDNSu32 len)
|
|
{
|
|
switch (ctx->alg)
|
|
{
|
|
case CRYPTO_RSA_NSEC3_SHA1:
|
|
case CRYPTO_RSA_SHA1:
|
|
CC_SHA1_Update((CC_SHA1_CTX *)ctx->context, data, len);
|
|
break;
|
|
case CRYPTO_RSA_SHA256:
|
|
CC_SHA256_Update((CC_SHA256_CTX *)ctx->context, data, len);
|
|
break;
|
|
case CRYPTO_RSA_SHA512:
|
|
CC_SHA512_Update((CC_SHA512_CTX *)ctx->context, data, len);
|
|
break;
|
|
default:
|
|
LogMsg("rsa_sha_add: Unsupported algorithm %d", ctx->alg);
|
|
return mStatus_BadParamErr;
|
|
}
|
|
return mStatus_NoError;
|
|
}
|
|
|
|
mDNSlocal SecKeyRef rfc3110_import(const mDNSu8 *data, const mDNSu32 len)
|
|
{
|
|
static const int max_modulus_bytes = 512; // Modulus is limited to 4096 bits (512 octets) in length.
|
|
static const int max_exp_bytes = 512; // Exponent is limited to 4096 bits (512 octets) in length.
|
|
static const int asn1_type_bytes = 3; // Since there is an ASN1 SEQ and two INTs.
|
|
static const int asn1_max_len_bytes = 3 * 3; // Capped at 3 due to max payload size.
|
|
unsigned char asn1[max_modulus_bytes + 1 + max_exp_bytes + asn1_type_bytes + asn1_max_len_bytes]; // +1 is for leading 0 for non negative asn1 number
|
|
const mDNSu8 *modulus;
|
|
unsigned int modulus_length;
|
|
const mDNSu8 *exponent;
|
|
unsigned int exp_length;
|
|
unsigned int num_length_bytes;
|
|
mDNSu32 index = 0;
|
|
mDNSu32 asn1_length = 0;
|
|
|
|
// Validate Input
|
|
if (!data)
|
|
return NULL;
|
|
|
|
// we have to have at least 1 byte for the length
|
|
if (len < 1)
|
|
return NULL;
|
|
|
|
// Parse Modulus and Exponent
|
|
|
|
// If the first byte is zero, then the exponent length is in the three-byte format, otherwise the length is in the first byte.
|
|
if (data[0] == 0)
|
|
{
|
|
if (len < 3)
|
|
return NULL;
|
|
exp_length = (data[1] << 8) | data[2];
|
|
num_length_bytes = 3;
|
|
}
|
|
else
|
|
{
|
|
exp_length = data[0];
|
|
num_length_bytes = 1;
|
|
}
|
|
|
|
// RFC3110 limits the exponent length to 4096 bits (512 octets).
|
|
if (exp_length > 512)
|
|
return NULL;
|
|
|
|
// We have to have at least len bytes + size of exponent.
|
|
if (len < (num_length_bytes + exp_length))
|
|
return NULL;
|
|
|
|
// The modulus is the remaining space.
|
|
modulus_length = len - (num_length_bytes + exp_length);
|
|
|
|
// RFC3110 limits the modulus length to 4096 bits (512 octets).
|
|
if (modulus_length > 512)
|
|
return NULL;
|
|
|
|
if (modulus_length < 1)
|
|
return NULL;
|
|
|
|
// add 1 to modulus length for pre-ceding 0 t make ASN1 value non-negative
|
|
++modulus_length;
|
|
|
|
exponent = &data[num_length_bytes];
|
|
modulus = &data[num_length_bytes + exp_length];
|
|
|
|
// 2 bytes for commands since first doesn't count
|
|
// 2 bytes for min 1 byte length field
|
|
asn1_length = modulus_length + exp_length + 2 + 2;
|
|
|
|
// Account for modulus length causing INT length field to grow.
|
|
if (modulus_length >= 128)
|
|
{
|
|
if (modulus_length > 255)
|
|
asn1_length += 2;
|
|
else
|
|
asn1_length += 1;
|
|
}
|
|
|
|
// Account for exponent length causing INT length field to grow.
|
|
if (exp_length >= 128)
|
|
{
|
|
if (exp_length > 255)
|
|
asn1_length += 2;
|
|
else
|
|
asn1_length += 1;
|
|
}
|
|
|
|
// Construct ASN1 formatted public key
|
|
// Write ASN1 SEQ byte
|
|
asn1[index++] = 0x30;
|
|
|
|
// Write ASN1 length for SEQ
|
|
if (asn1_length < 128)
|
|
{
|
|
asn1[index++] = asn1_length & 0xFF;
|
|
}
|
|
else
|
|
{
|
|
asn1[index++] = (0x80 | ((asn1_length > 255) ? 2 : 1));
|
|
if (asn1_length > 255)
|
|
asn1[index++] = (asn1_length & 0xFF00) >> 8;
|
|
asn1[index++] = asn1_length & 0xFF;
|
|
}
|
|
|
|
// Write ASN1 INT for modulus
|
|
asn1[index++] = 0x02;
|
|
// Write ASN1 length for INT
|
|
if (modulus_length < 128)
|
|
{
|
|
asn1[index++] = modulus_length & 0xFF;
|
|
}
|
|
else
|
|
{
|
|
asn1[index++] = 0x80 | ((modulus_length > 255) ? 2 : 1);
|
|
if (modulus_length > 255)
|
|
asn1[index++] = (modulus_length & 0xFF00) >> 8;
|
|
asn1[index++] = modulus_length & 0xFF;
|
|
}
|
|
|
|
// Write preceding 0 so our integer isn't negative
|
|
asn1[index++] = 0x00;
|
|
// Write actual modulus (-1 for preceding 0)
|
|
memcpy(&asn1[index], modulus, modulus_length - 1);
|
|
index += (modulus_length - 1);
|
|
|
|
// Write ASN1 INT for exponent
|
|
asn1[index++] = 0x02;
|
|
// Write ASN1 length for INT
|
|
if (exp_length < 128)
|
|
{
|
|
asn1[index++] = exp_length & 0xFF;
|
|
}
|
|
else
|
|
{
|
|
asn1[index++] = 0x80 | ((exp_length > 255) ? 2 : 1);
|
|
if (exp_length > 255)
|
|
asn1[index++] = (exp_length & 0xFF00) >> 8;
|
|
asn1[index++] = exp_length & 0xFF;
|
|
}
|
|
// Write exponent bytes
|
|
memcpy(&asn1[index], exponent, exp_length);
|
|
index += exp_length;
|
|
|
|
#if TARGET_OS_IPHONE
|
|
// index contains bytes written, use it for length
|
|
return (SecKeyCreateRSAPublicKey(NULL, asn1, index, kSecKeyEncodingPkcs1));
|
|
#else
|
|
return (SecKeyCreateRSAPublicKey_OSX(asn1, index));
|
|
#endif
|
|
}
|
|
|
|
#if TARGET_OS_IPHONE
|
|
mDNSlocal mStatus rsa_sha_verify(AlgContext *ctx, mDNSu8 *key, mDNSu32 keylen, mDNSu8 *signature, mDNSu32 siglen)
|
|
{
|
|
SecKeyRef keyref;
|
|
OSStatus result;
|
|
mDNSu8 digest[CC_SHA512_DIGEST_LENGTH];
|
|
int digestlen;
|
|
int cryptoAlg;
|
|
|
|
switch (ctx->alg)
|
|
{
|
|
case CRYPTO_RSA_NSEC3_SHA1:
|
|
case CRYPTO_RSA_SHA1:
|
|
cryptoAlg = kSecPaddingPKCS1SHA1;
|
|
digestlen = CC_SHA1_DIGEST_LENGTH;
|
|
CC_SHA1_Final(digest, (CC_SHA1_CTX *)ctx->context);
|
|
break;
|
|
case CRYPTO_RSA_SHA256:
|
|
cryptoAlg = kSecPaddingPKCS1SHA256;
|
|
digestlen = CC_SHA256_DIGEST_LENGTH;
|
|
CC_SHA256_Final(digest, (CC_SHA256_CTX *)ctx->context);
|
|
break;
|
|
case CRYPTO_RSA_SHA512:
|
|
cryptoAlg = kSecPaddingPKCS1SHA512;
|
|
digestlen = CC_SHA512_DIGEST_LENGTH;
|
|
CC_SHA512_Final(digest, (CC_SHA512_CTX *)ctx->context);
|
|
break;
|
|
default:
|
|
LogMsg("rsa_sha_verify: Unsupported algorithm %d", ctx->alg);
|
|
return mStatus_BadParamErr;
|
|
}
|
|
|
|
keyref = rfc3110_import(key, keylen);
|
|
if (!keyref)
|
|
{
|
|
LogMsg("rsa_sha_verify: Error decoding rfc3110 key data");
|
|
return mStatus_NoMemoryErr;
|
|
}
|
|
result = SecKeyRawVerify(keyref, cryptoAlg, digest, digestlen, signature, siglen);
|
|
CFRelease(keyref);
|
|
if (result != noErr)
|
|
{
|
|
LogMsg("rsa_sha_verify: Failed for alg %d", ctx->alg);
|
|
return mStatus_BadParamErr;
|
|
}
|
|
else
|
|
{
|
|
LogInfo("rsa_sha_verify: Passed for alg %d", ctx->alg);
|
|
return mStatus_NoError;
|
|
}
|
|
}
|
|
#else // TARGET_OS_IPHONE
|
|
|
|
mDNSlocal SecKeyRef SecKeyCreateRSAPublicKey_OSX(unsigned char *asn1, int length)
|
|
{
|
|
SecKeyRef result = NULL;
|
|
|
|
SecExternalFormat extFormat = kSecFormatBSAFE;
|
|
SecExternalItemType itemType = kSecItemTypePublicKey;
|
|
CFArrayRef outArray = NULL;
|
|
|
|
CFDataRef keyData = CFDataCreate(NULL, asn1, length);
|
|
if (!keyData)
|
|
return NULL;
|
|
|
|
OSStatus err = SecItemImport(keyData, NULL, &extFormat, &itemType, 0, NULL, NULL, &outArray);
|
|
|
|
CFRelease(keyData);
|
|
if (noErr != err || outArray == NULL)
|
|
{
|
|
if (outArray)
|
|
CFRelease(outArray);
|
|
return NULL;
|
|
}
|
|
|
|
result = (SecKeyRef)CFArrayGetValueAtIndex(outArray, 0);
|
|
if (result == NULL)
|
|
{
|
|
CFRelease(outArray);
|
|
return NULL;
|
|
}
|
|
|
|
CFRetain(result);
|
|
CFRelease(outArray);
|
|
return result;
|
|
}
|
|
|
|
mDNSlocal Boolean VerifyData(SecKeyRef key, CFStringRef digestStr, mDNSu8 *digest, int dlen, int digestlenAttr, mDNSu8 *sig, int siglen, CFStringRef digest_type)
|
|
{
|
|
CFErrorRef error;
|
|
Boolean ret;
|
|
|
|
CFDataRef signature = CFDataCreate(NULL, sig, siglen);
|
|
if (!signature)
|
|
return false;
|
|
|
|
SecTransformRef verifyXForm = SecVerifyTransformCreate(key, signature, &error);
|
|
CFRelease(signature);
|
|
if (verifyXForm == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// tell the transform what type of data it is geting
|
|
if (!SecTransformSetAttribute(verifyXForm, kSecInputIsAttributeName, digest_type, &error))
|
|
{
|
|
LogMsg("VerifyData: SecTransformSetAttribute digest_type");
|
|
goto err;
|
|
}
|
|
|
|
if (!SecTransformSetAttribute(verifyXForm, kSecDigestTypeAttribute, digestStr, &error))
|
|
{
|
|
LogMsg("VerifyData: SecTransformSetAttribute digestStr");
|
|
goto err;
|
|
}
|
|
|
|
CFNumberRef digestLengthRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &digestlenAttr);
|
|
if (digestLengthRef == NULL)
|
|
{
|
|
LogMsg("VerifyData: CFNumberCreate failed");
|
|
goto err;
|
|
}
|
|
|
|
ret = SecTransformSetAttribute(verifyXForm, kSecDigestLengthAttribute, digestLengthRef, &error);
|
|
CFRelease(digestLengthRef);
|
|
if (!ret)
|
|
{
|
|
LogMsg("VerifyData: SecTransformSetAttribute digestLengthRef");
|
|
goto err;
|
|
}
|
|
|
|
CFDataRef dataToSign = CFDataCreate(NULL, digest, dlen);
|
|
if (dataToSign == NULL)
|
|
{
|
|
LogMsg("VerifyData: CFDataCreate failed");
|
|
goto err;
|
|
}
|
|
|
|
ret = SecTransformSetAttribute(verifyXForm, kSecTransformInputAttributeName, dataToSign, &error);
|
|
CFRelease(dataToSign);
|
|
if (!ret)
|
|
{
|
|
LogMsg("VerifyData: SecTransformSetAttribute TransformAttributeName");
|
|
goto err;
|
|
}
|
|
|
|
CFBooleanRef boolRef = SecTransformExecute(verifyXForm, &error);
|
|
ret = boolRef ? CFBooleanGetValue(boolRef) : false;
|
|
if (boolRef) CFRelease(boolRef);
|
|
CFRelease(verifyXForm);
|
|
|
|
if (error != NULL)
|
|
{
|
|
CFStringRef errStr = CFErrorCopyDescription(error);
|
|
char errorbuf[128];
|
|
errorbuf[0] = 0;
|
|
if (errStr != NULL)
|
|
{
|
|
if (!CFStringGetCString(errStr, errorbuf, sizeof(errorbuf), kCFStringEncodingUTF8))
|
|
{
|
|
LogMsg("VerifyData: CFStringGetCString failed");
|
|
}
|
|
CFRelease(errStr);
|
|
}
|
|
LogMsg("VerifyData: SecTransformExecute failed with %s", errorbuf);
|
|
return false;
|
|
}
|
|
return ret;
|
|
err:
|
|
CFRelease(verifyXForm);
|
|
return false;
|
|
}
|
|
|
|
mDNSlocal mStatus rsa_sha_verify(AlgContext *ctx, mDNSu8 *key, mDNSu32 keylen, mDNSu8 *signature, mDNSu32 siglen)
|
|
{
|
|
SecKeyRef keyref;
|
|
mDNSu8 digest[CC_SHA512_DIGEST_LENGTH];
|
|
int digestlen;
|
|
int digestlenAttr;
|
|
CFStringRef digestStr;
|
|
mDNSBool ret;
|
|
|
|
switch (ctx->alg)
|
|
{
|
|
case CRYPTO_RSA_NSEC3_SHA1:
|
|
case CRYPTO_RSA_SHA1:
|
|
digestStr = kSecDigestSHA1;
|
|
digestlen = CC_SHA1_DIGEST_LENGTH;
|
|
digestlenAttr = 0;
|
|
CC_SHA1_Final(digest, (CC_SHA1_CTX *)ctx->context);
|
|
break;
|
|
case CRYPTO_RSA_SHA256:
|
|
digestStr = kSecDigestSHA2;
|
|
digestlen = CC_SHA256_DIGEST_LENGTH;
|
|
digestlenAttr = 256;
|
|
CC_SHA256_Final(digest, (CC_SHA256_CTX *)ctx->context);
|
|
break;
|
|
case CRYPTO_RSA_SHA512:
|
|
digestStr = kSecDigestSHA2;
|
|
digestlen = CC_SHA512_DIGEST_LENGTH;
|
|
digestlenAttr = 512;
|
|
CC_SHA512_Final(digest, (CC_SHA512_CTX *)ctx->context);
|
|
break;
|
|
default:
|
|
LogMsg("rsa_sha_verify: Unsupported algorithm %d", ctx->alg);
|
|
return mStatus_BadParamErr;
|
|
}
|
|
|
|
keyref = rfc3110_import(key, keylen);
|
|
if (!keyref)
|
|
{
|
|
LogMsg("rsa_sha_verify: Error decoding rfc3110 key data");
|
|
return mStatus_NoMemoryErr;
|
|
}
|
|
ret = VerifyData(keyref, digestStr, digest, digestlen, digestlenAttr, signature, siglen, kSecInputIsDigest);
|
|
CFRelease(keyref);
|
|
if (!ret)
|
|
{
|
|
LogMsg("rsa_sha_verify: Failed for alg %d", ctx->alg);
|
|
return mStatus_BadParamErr;
|
|
}
|
|
else
|
|
{
|
|
LogInfo("rsa_sha_verify: Passed for alg %d", ctx->alg);
|
|
return mStatus_NoError;
|
|
}
|
|
}
|
|
#endif // TARGET_OS_IPHONE
|
|
|
|
AlgFuncs sha_funcs = {sha_create, sha_destroy, sha_len, sha_add, sha_verify, mDNSNULL, sha_final};
|
|
AlgFuncs rsa_sha_funcs = {rsa_sha_create, rsa_sha_destroy, rsa_sha_len, rsa_sha_add, rsa_sha_verify, mDNSNULL, mDNSNULL};
|
|
AlgFuncs enc_funcs = {enc_create, enc_destroy, mDNSNULL, enc_add, mDNSNULL, enc_encode, mDNSNULL};
|
|
|
|
#ifndef DNSSEC_DISABLED
|
|
|
|
mDNSexport mStatus DNSSECCryptoInit(mDNS *const m)
|
|
{
|
|
mStatus result;
|
|
|
|
result = DigestAlgInit(SHA1_DIGEST_TYPE, &sha_funcs);
|
|
if (result != mStatus_NoError)
|
|
return result;
|
|
result = DigestAlgInit(SHA256_DIGEST_TYPE, &sha_funcs);
|
|
if (result != mStatus_NoError)
|
|
return result;
|
|
result = CryptoAlgInit(CRYPTO_RSA_SHA1, &rsa_sha_funcs);
|
|
if (result != mStatus_NoError)
|
|
return result;
|
|
result = CryptoAlgInit(CRYPTO_RSA_NSEC3_SHA1, &rsa_sha_funcs);
|
|
if (result != mStatus_NoError)
|
|
return result;
|
|
result = CryptoAlgInit(CRYPTO_RSA_SHA256, &rsa_sha_funcs);
|
|
if (result != mStatus_NoError)
|
|
return result;
|
|
result = CryptoAlgInit(CRYPTO_RSA_SHA512, &rsa_sha_funcs);
|
|
if (result != mStatus_NoError)
|
|
return result;
|
|
result = EncAlgInit(ENC_BASE32, &enc_funcs);
|
|
if (result != mStatus_NoError)
|
|
return result;
|
|
result = EncAlgInit(ENC_BASE64, &enc_funcs);
|
|
if (result != mStatus_NoError)
|
|
return result;
|
|
|
|
result = DNSSECPlatformInit(m);
|
|
|
|
return result;
|
|
}
|
|
|
|
#else // !DNSSEC_DISABLED
|
|
|
|
mDNSexport mStatus DNSSECCryptoInit(mDNS *const m)
|
|
{
|
|
(void) m;
|
|
|
|
return mStatus_NoError;
|
|
}
|
|
|
|
#endif // !DNSSEC_DISABLED
|
|
|
|
|