]> git.saurik.com Git - apple/security.git/blob - libsecurity_transform/lib/SecMaskGenerationFunctionTransform.c
Security-55163.44.tar.gz
[apple/security.git] / libsecurity_transform / lib / SecMaskGenerationFunctionTransform.c
1 //
2 // SecMaskGenerationFunctionTransform.c
3 // libsecurity_transform
4 //
5 // Created by Josh Osborne on 10/6/11.
6 // Copyright 2011 Apple. All rights reserved.
7 //
8
9 #include <stdio.h>
10 #include <CoreFoundation/CoreFoundation.h>
11 #include "SecMaskGenerationFunctionTransform.h"
12 #include "SecCustomTransform.h"
13 #include "SecDigestTransform.h"
14 #include "misc.h"
15 #include "Utilities.h"
16
17 static const CFStringRef kMaskGenerationFunctionTransformName = CFSTR("com.apple.security.MGF1");
18 static const CFStringRef kLengthName = CFSTR("Length");
19
20 static SecTransformInstanceBlock MaskGenerationFunctionTransform(CFStringRef name,
21 SecTransformRef newTransform,
22 SecTransformImplementationRef ref)
23 {
24 __block CFMutableDataRef accumulator = CFDataCreateMutable(NULL, 0);
25 __block int32_t outputLength = 0;
26
27 SecTransformInstanceBlock instanceBlock = ^{
28 SecTransformSetTransformAction(ref, kSecTransformActionFinalize, ^{
29 CFRelease(accumulator);
30
31 return (CFTypeRef)NULL;
32 });
33
34 // XXX: be a good citizen, put a validator in for the types.
35
36 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, kLengthName, ^CFTypeRef(SecTransformAttributeRef attribute, CFTypeRef value) {
37 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &outputLength);
38 if (outputLength <= 0) {
39 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, CreateSecTransformErrorRef(kSecTransformErrorInvalidLength, "MaskGenerationFunction Length must be one or more (not %@)", value));
40 }
41
42 return (CFTypeRef)NULL;
43 });
44
45 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, kSecTransformInputAttributeName, ^CFTypeRef(SecTransformAttributeRef attribute, CFTypeRef value) {
46 if (value) {
47 CFDataRef d = value;
48 CFDataAppendBytes(accumulator, CFDataGetBytePtr(d), CFDataGetLength(d));
49 } else {
50 int32_t i = 0, l = 0;
51 (void)transforms_assume(outputLength > 0);
52 CFStringRef digestType = SecTranformCustomGetAttribute(ref, kSecDigestTypeAttribute, kSecTransformMetaAttributeValue);
53 SecTransformRef digest0 = transforms_assume(SecDigestTransformCreate(digestType, 0, NULL));
54 int32_t digestLength = 0;
55 {
56 CFNumberRef digestLengthAsCFNumber = SecTransformGetAttribute(digest0, kSecDigestLengthAttribute);
57 CFNumberGetValue(transforms_assume(digestLengthAsCFNumber), kCFNumberSInt32Type, &digestLength);
58 }
59 (void)transforms_assume(digestLength >= 0);
60
61 UInt8 *buffer = malloc(outputLength + digestLength);
62 if (!buffer) {
63 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, GetNoMemoryErrorAndRetain());
64 return (CFErrorRef)NULL;
65 }
66
67 dispatch_group_t all_hashed = dispatch_group_create();
68 dispatch_group_enter(all_hashed);
69 for(; l < outputLength; l += digestLength, i++) {
70 dispatch_group_enter(all_hashed);
71 CFErrorRef err = NULL;
72 SecTransformRef digest = NULL;
73 if (l == 0) {
74 digest = digest0;
75 } else {
76 digest = SecDigestTransformCreate(digestType, 0, &err);
77 if (digest == NULL) {
78 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, err);
79 return (CFErrorRef)NULL;
80 }
81 }
82
83 // NOTE: we shuld be able to do this without the copy, make a transform that takes an
84 // array and outputs each item in the array followed by a NULL ought to be quicker.
85 CFMutableDataRef accumulatorPlusCounter = CFDataCreateMutableCopy(NULL, CFDataGetLength(accumulator) + sizeof(uint32_t), accumulator);
86 int32_t bigendian_i = htonl(i);
87 CFDataAppendBytes(accumulatorPlusCounter, (UInt8*)&bigendian_i, sizeof(bigendian_i));
88 SecTransformSetAttribute(digest, kSecTransformInputAttributeName, accumulatorPlusCounter, &err);
89 CFRelease(accumulatorPlusCounter);
90
91 UInt8 *buf = buffer + l;
92 SecTransformExecuteAsync(digest, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFTypeRef message, CFErrorRef error, Boolean isFinal) {
93 if (message) {
94 CFIndex messageLen = CFDataGetLength(message);
95 CFDataGetBytes(message, CFRangeMake(0, messageLen), buf);
96 }
97 if (error) {
98 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, error);
99 }
100 if (isFinal) {
101 dispatch_group_leave(all_hashed);
102 }
103 });
104 CFRelease(digest);
105 }
106
107 dispatch_group_leave(all_hashed);
108 dispatch_group_wait(all_hashed, DISPATCH_TIME_FOREVER);
109 CFDataRef out = CFDataCreateWithBytesNoCopy(NULL, buffer, outputLength, kCFAllocatorMalloc);
110 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, out);
111 CFRelease(out);
112 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, NULL);
113 }
114 return (CFErrorRef)NULL;
115 });
116
117 return (CFErrorRef)NULL;
118 };
119
120 return Block_copy(instanceBlock);
121 }
122
123 SecTransformRef SecCreateMaskGenerationFunctionTransform(CFStringRef hashType, int length, CFErrorRef *error)
124 {
125 static dispatch_once_t once;
126 __block Boolean ok = TRUE;
127
128 if (length <= 0) {
129 if (error) {
130 *error = CreateSecTransformErrorRef(kSecTransformErrorInvalidLength, "MaskGenerationFunction Length must be one or more (not %d)", length);
131 }
132 return NULL;
133 }
134
135 dispatch_once(&once, ^(void) {
136 ok = SecTransformRegister(kMaskGenerationFunctionTransformName, MaskGenerationFunctionTransform, error);
137 });
138
139 if (!ok) {
140 return NULL;
141 }
142
143 SecTransformRef ret = SecTransformCreate(kMaskGenerationFunctionTransformName, error);
144 if (!ret) {
145 return NULL;
146 }
147
148 if (!SecTransformSetAttribute(ret, kSecDigestTypeAttribute, hashType ? hashType : kSecDigestSHA1, error)) {
149 CFRelease(ret);
150 return NULL;
151 }
152
153 CFNumberRef len = CFNumberCreate(NULL, kCFNumberIntType, &length);
154 ok = SecTransformSetAttribute(ret, kLengthName, len, error);
155 CFRelease(len);
156 if (!ok) {
157 CFRelease(ret);
158 return NULL;
159 }
160
161 return ret;
162 }