]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_transform/lib/SecMaskGenerationFunctionTransform.c
Security-58286.200.222.tar.gz
[apple/security.git] / OSX / libsecurity_transform / lib / SecMaskGenerationFunctionTransform.c
1 /*
2 * Copyright (c) 2011-2012,2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 #include <stdio.h>
26 #include <CoreFoundation/CoreFoundation.h>
27 #include "SecMaskGenerationFunctionTransform.h"
28 #include "SecCustomTransform.h"
29 #include "SecDigestTransform.h"
30 #include "misc.h"
31 #include "Utilities.h"
32
33 static const CFStringRef kMaskGenerationFunctionTransformName = CFSTR("com.apple.security.MGF1");
34 static const CFStringRef kLengthName = CFSTR("Length");
35
36 static SecTransformInstanceBlock MaskGenerationFunctionTransform(CFStringRef name,
37 SecTransformRef newTransform,
38 SecTransformImplementationRef ref)
39 {
40 __block CFMutableDataRef accumulator = CFDataCreateMutable(NULL, 0);
41 __block int32_t outputLength = 0;
42
43 SecTransformInstanceBlock instanceBlock = ^{
44 SecTransformSetTransformAction(ref, kSecTransformActionFinalize, ^{
45 CFReleaseNull(accumulator);
46
47 return (CFTypeRef)NULL;
48 });
49
50 // XXX: be a good citizen, put a validator in for the types.
51
52 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, kLengthName, ^CFTypeRef(SecTransformAttributeRef attribute, CFTypeRef value) {
53 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &outputLength);
54 if (outputLength <= 0) {
55 CFErrorRef error = CreateSecTransformErrorRef(kSecTransformErrorInvalidLength, "MaskGenerationFunction Length must be one or more (not %@)", value);
56 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, error);
57 CFSafeRelease(error);
58 }
59
60 return (CFTypeRef)NULL;
61 });
62
63 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, kSecTransformInputAttributeName, ^CFTypeRef(SecTransformAttributeRef attribute, CFTypeRef value) {
64 if (value) {
65 CFDataRef d = value;
66 CFDataAppendBytes(accumulator, CFDataGetBytePtr(d), CFDataGetLength(d));
67 } else {
68 int32_t i = 0, l = 0;
69 (void)transforms_assume(outputLength > 0);
70 CFStringRef digestType = SecTranformCustomGetAttribute(ref, kSecDigestTypeAttribute, kSecTransformMetaAttributeValue);
71 SecTransformRef digest0 = transforms_assume(SecDigestTransformCreate(digestType, 0, NULL));
72 int32_t digestLength = 0;
73 {
74 // we've already asserted that digest0 is non-null, but clang doesn't know that
75 #ifndef __clang_analyzer__
76 CFNumberRef digestLengthAsCFNumber = SecTransformGetAttribute(digest0, kSecDigestLengthAttribute);
77 CFNumberGetValue(transforms_assume(digestLengthAsCFNumber), kCFNumberSInt32Type, &digestLength);
78 #endif
79 }
80 (void)transforms_assume(digestLength >= 0);
81
82 UInt8 *buffer = malloc(outputLength + digestLength);
83 if (!buffer) {
84 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, GetNoMemoryErrorAndRetain());
85 return (CFErrorRef)NULL;
86 }
87
88 dispatch_group_t all_hashed = dispatch_group_create();
89 dispatch_group_enter(all_hashed);
90 for(; l < outputLength; l += digestLength, i++) {
91 dispatch_group_enter(all_hashed);
92 CFErrorRef err = NULL;
93 SecTransformRef digest = NULL;
94 if (l == 0) {
95 digest = digest0;
96 } else {
97 digest = SecDigestTransformCreate(digestType, 0, &err);
98 }
99
100 if (digest == NULL) {
101 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, err);
102 free(buffer);
103 return (CFErrorRef)NULL;
104 }
105
106 // NOTE: we shuld be able to do this without the copy, make a transform that takes an
107 // array and outputs each item in the array followed by a NULL ought to be quicker.
108 CFMutableDataRef accumulatorPlusCounter = CFDataCreateMutableCopy(NULL, CFDataGetLength(accumulator) + sizeof(uint32_t), accumulator);
109 int32_t bigendian_i = htonl(i);
110 CFDataAppendBytes(accumulatorPlusCounter, (UInt8*)&bigendian_i, sizeof(bigendian_i));
111 SecTransformSetAttribute(digest, kSecTransformInputAttributeName, accumulatorPlusCounter, &err);
112 CFReleaseNull(accumulatorPlusCounter);
113
114 UInt8 *buf = buffer + l;
115 SecTransformExecuteAsync(digest, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFTypeRef message, CFErrorRef error, Boolean isFinal) {
116 if (message) {
117 CFIndex messageLen = CFDataGetLength(message);
118 CFDataGetBytes(message, CFRangeMake(0, messageLen), buf);
119 }
120 if (error) {
121 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, error);
122 }
123 if (isFinal) {
124 dispatch_group_leave(all_hashed);
125 }
126 });
127 CFReleaseNull(digest);
128 }
129
130 dispatch_group_leave(all_hashed);
131 dispatch_group_wait(all_hashed, DISPATCH_TIME_FOREVER);
132 CFDataRef out = CFDataCreateWithBytesNoCopy(NULL, buffer, outputLength, kCFAllocatorMalloc);
133 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, out);
134 CFReleaseNull(out);
135 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, NULL);
136 }
137 return (CFErrorRef)NULL;
138 });
139
140 return (CFErrorRef)NULL;
141 };
142
143 return Block_copy(instanceBlock);
144 }
145
146 SecTransformRef SecCreateMaskGenerationFunctionTransform(CFStringRef hashType, int length, CFErrorRef *error)
147 {
148 static dispatch_once_t once;
149 __block Boolean ok = TRUE;
150
151 if (length <= 0) {
152 if (error) {
153 *error = CreateSecTransformErrorRef(kSecTransformErrorInvalidLength, "MaskGenerationFunction Length must be one or more (not %d)", length);
154 }
155 return NULL;
156 }
157
158 dispatch_once(&once, ^(void) {
159 ok = SecTransformRegister(kMaskGenerationFunctionTransformName, MaskGenerationFunctionTransform, error);
160 });
161
162 if (!ok) {
163 return NULL;
164 }
165
166 SecTransformRef ret = SecTransformCreate(kMaskGenerationFunctionTransformName, error);
167 if (!ret) {
168 return NULL;
169 }
170
171 if (!SecTransformSetAttribute(ret, kSecDigestTypeAttribute, hashType ? hashType : kSecDigestSHA1, error)) {
172 CFReleaseNull(ret);
173 return NULL;
174 }
175
176 CFNumberRef len = CFNumberCreate(NULL, kCFNumberIntType, &length);
177 ok = SecTransformSetAttribute(ret, kLengthName, len, error);
178 CFReleaseNull(len);
179 if (!ok) {
180 CFReleaseNull(ret);
181 return NULL;
182 }
183
184 return ret;
185 }