1// 2// SecCFCanonicalHashes.c 3// utilities 4// 5// Created by Mitch Adler on 2/8/12. 6// Copyright (c) 2012 Apple Inc. All rights reserved. 7// 8 9#include <stdio.h> 10 11#include "utilities/SecCFCanonicalHashes.h" 12#include "utilities/comparison.h" 13 14#include <CoreFoundation/CFArray.h> 15#include <CoreFoundation/CFString.h> 16#include <CoreFoundation/CFData.h> 17#include <utilities/SecCFRelease.h> 18#include <corecrypto/ccdigest.h> 19 20struct AddKeyValueHashContext { 21 CFMutableArrayRef array; 22 const struct ccdigest_info* di; 23 bool fail; 24}; 25 26static void AddKeyValueHashData(const void *key, const void *value, void *context) 27{ 28 struct AddKeyValueHashContext* akvContext = (struct AddKeyValueHashContext*) context; 29 30 size_t key_len; 31 const void* key_data; 32 if (CFGetTypeID(key) == CFStringGetTypeID()) { 33 key_len = CFStringGetLength((CFStringRef) key); 34 key_data = CFStringGetCharactersPtr((CFStringRef) key); 35 } else { 36 akvContext->fail = true; 37 return; 38 } 39 40 size_t value_len; 41 const void* value_data; 42 if (CFGetTypeID(key) == CFStringGetTypeID()) { 43 value_len = CFStringGetLength((CFStringRef) value); 44 value_data = CFStringGetCharactersPtr((CFStringRef) value); 45 } else if (CFGetTypeID(key) == CFDataGetTypeID()) { 46 value_len = CFDataGetLength((CFDataRef)value); 47 value_data = CFDataGetBytePtr((CFDataRef)value); 48 } else { 49 akvContext->fail = true; 50 return; 51 } 52 53 UInt8 hashBuffer[akvContext->di->output_size]; 54 55 ccdigest_di_decl(akvContext->di, finalContext); 56 57 ccdigest(akvContext->di, key_len, key_data, hashBuffer); 58 59 ccdigest_init(akvContext->di, finalContext); 60 ccdigest_update(akvContext->di, finalContext, sizeof(hashBuffer), hashBuffer); 61 62 ccdigest_update(akvContext->di, finalContext, sizeof(hashBuffer), hashBuffer); 63 ccdigest(akvContext->di, value_len, value_data, hashBuffer); 64 65 ccdigest_final(akvContext->di, finalContext, (void*)hashBuffer); 66 67 CFDataRef hash = CFDataCreate(kCFAllocatorDefault, hashBuffer, sizeof(hashBuffer)); 68 CFArrayAppendValue(akvContext->array, hash); 69 CFReleaseSafe(hash); 70} 71 72static CFComparisonResult CFDataCompare(CFDataRef d1, CFDataRef d2) 73{ 74 CFIndex d1_size = CFDataGetLength(d1); 75 CFIndex d2_size = CFDataGetLength(d2); 76 77 CFIndex comparison = memcmp(CFDataGetBytePtr(d1), CFDataGetBytePtr(d2), MIN(d1_size, d2_size)); 78 79 if (comparison == 0) 80 comparison = d1_size - d2_size; 81 82 return (comparison > 0) ? kCFCompareGreaterThan : ((comparison < 0) ? kCFCompareLessThan : kCFCompareEqualTo); 83} 84 85static CFComparisonResult CFEqualComparitor(const void *val1, const void *val2, void * context __unused) 86{ 87 return CFDataCompare((CFDataRef) val1, (CFDataRef) val2); 88} 89 90struct array_hashing_context { 91 const struct ccdigest_info* di; 92 struct ccdigest_ctx * ctx; 93}; 94 95static void hash_CFDatas(const void *value, void *context) 96{ 97 struct array_hashing_context* ahc = (struct array_hashing_context*) context; 98 99 ccdigest_update(ahc->di, ahc->ctx, CFDataGetLength((CFDataRef) value), CFDataGetBytePtr((CFDataRef) value)); 100} 101 102 103bool SecCFAppendCFDictionaryHash(CFDictionaryRef thisDictionary, const struct ccdigest_info* di, CFMutableDataRef toThis) 104{ 105 CFMutableArrayRef hashArray = CFArrayCreateMutable(kCFAllocatorDefault, CFDictionaryGetCount(thisDictionary), &kCFTypeArrayCallBacks); 106 107 CFDictionaryApplyFunction(thisDictionary, &AddKeyValueHashData, hashArray); 108 109 CFRange wholeArray = CFRangeMake(0, CFArrayGetCount(hashArray)); 110 111 CFArraySortValues(hashArray, wholeArray, &CFEqualComparitor, NULL); 112 113 ccdigest_di_decl(di, finalContext); 114 115 struct array_hashing_context ahc = { .di = di, .ctx = (struct ccdigest_ctx*)&finalContext}; 116 117 CFArrayApplyFunction(hashArray, wholeArray, hash_CFDatas, &ahc); 118 119 return true; 120} 121