]> git.saurik.com Git - apple/security.git/blob - utilities/src/SecCFCanonicalHashes.c
Security-55471.14.tar.gz
[apple/security.git] / utilities / src / SecCFCanonicalHashes.c
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
20 struct AddKeyValueHashContext {
21 CFMutableArrayRef array;
22 const struct ccdigest_info* di;
23 bool fail;
24 };
25
26 static 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
72 static 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
85 static CFComparisonResult CFEqualComparitor(const void *val1, const void *val2, void * context __unused)
86 {
87 return CFDataCompare((CFDataRef) val1, (CFDataRef) val2);
88 }
89
90 struct array_hashing_context {
91 const struct ccdigest_info* di;
92 struct ccdigest_ctx * ctx;
93 };
94
95 static 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
103 bool 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 }