2 // SecCFCanonicalHashes.c
5 // Created by Mitch Adler on 2/8/12.
6 // Copyright (c) 2012 Apple Inc. All rights reserved.
11 #include "utilities/SecCFCanonicalHashes.h"
12 #include "utilities/comparison.h"
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>
20 struct AddKeyValueHashContext
{
21 CFMutableArrayRef array
;
22 const struct ccdigest_info
* di
;
26 static void AddKeyValueHashData(const void *key
, const void *value
, void *context
)
28 struct AddKeyValueHashContext
* akvContext
= (struct AddKeyValueHashContext
*) context
;
32 if (CFGetTypeID(key
) == CFStringGetTypeID()) {
33 key_len
= CFStringGetLength((CFStringRef
) key
);
34 key_data
= CFStringGetCharactersPtr((CFStringRef
) key
);
36 akvContext
->fail
= true;
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
);
49 akvContext
->fail
= true;
53 UInt8 hashBuffer
[akvContext
->di
->output_size
];
55 ccdigest_di_decl(akvContext
->di
, finalContext
);
57 ccdigest(akvContext
->di
, key_len
, key_data
, hashBuffer
);
59 ccdigest_init(akvContext
->di
, finalContext
);
60 ccdigest_update(akvContext
->di
, finalContext
, sizeof(hashBuffer
), hashBuffer
);
62 ccdigest_update(akvContext
->di
, finalContext
, sizeof(hashBuffer
), hashBuffer
);
63 ccdigest(akvContext
->di
, value_len
, value_data
, hashBuffer
);
65 ccdigest_final(akvContext
->di
, finalContext
, (void*)hashBuffer
);
67 CFDataRef hash
= CFDataCreate(kCFAllocatorDefault
, hashBuffer
, sizeof(hashBuffer
));
68 CFArrayAppendValue(akvContext
->array
, hash
);
72 static CFComparisonResult
CFDataCompare(CFDataRef d1
, CFDataRef d2
)
74 CFIndex d1_size
= CFDataGetLength(d1
);
75 CFIndex d2_size
= CFDataGetLength(d2
);
77 CFIndex comparison
= memcmp(CFDataGetBytePtr(d1
), CFDataGetBytePtr(d2
), MIN(d1_size
, d2_size
));
80 comparison
= d1_size
- d2_size
;
82 return (comparison
> 0) ? kCFCompareGreaterThan
: ((comparison
< 0) ? kCFCompareLessThan
: kCFCompareEqualTo
);
85 static CFComparisonResult
CFEqualComparitor(const void *val1
, const void *val2
, void * context __unused
)
87 return CFDataCompare((CFDataRef
) val1
, (CFDataRef
) val2
);
90 struct array_hashing_context
{
91 const struct ccdigest_info
* di
;
92 struct ccdigest_ctx
* ctx
;
95 static void hash_CFDatas(const void *value
, void *context
)
97 struct array_hashing_context
* ahc
= (struct array_hashing_context
*) context
;
99 ccdigest_update(ahc
->di
, ahc
->ctx
, CFDataGetLength((CFDataRef
) value
), CFDataGetBytePtr((CFDataRef
) value
));
103 bool SecCFAppendCFDictionaryHash(CFDictionaryRef thisDictionary
, const struct ccdigest_info
* di
, CFMutableDataRef toThis
)
105 CFMutableArrayRef hashArray
= CFArrayCreateMutable(kCFAllocatorDefault
, CFDictionaryGetCount(thisDictionary
), &kCFTypeArrayCallBacks
);
107 CFDictionaryApplyFunction(thisDictionary
, &AddKeyValueHashData
, hashArray
);
109 CFRange wholeArray
= CFRangeMake(0, CFArrayGetCount(hashArray
));
111 CFArraySortValues(hashArray
, wholeArray
, &CFEqualComparitor
, NULL
);
113 ccdigest_di_decl(di
, finalContext
);
115 struct array_hashing_context ahc
= { .di
= di
, .ctx
= (struct ccdigest_ctx
*)&finalContext
};
117 CFArrayApplyFunction(hashArray
, wholeArray
, hash_CFDatas
, &ahc
);