]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_transform/lib/SecMaskGenerationFunctionTransform.c
Security-57337.40.85.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 CFRelease(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 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, CreateSecTransformErrorRef(kSecTransformErrorInvalidLength, "MaskGenerationFunction Length must be one or more (not %@)", value));
56 }
57
58 return (CFTypeRef)NULL;
59 });
60
61 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, kSecTransformInputAttributeName, ^CFTypeRef(SecTransformAttributeRef attribute, CFTypeRef value) {
62 if (value) {
63 CFDataRef d = value;
64 CFDataAppendBytes(accumulator, CFDataGetBytePtr(d), CFDataGetLength(d));
65 } else {
66 int32_t i = 0, l = 0;
67 (void)transforms_assume(outputLength > 0);
68 CFStringRef digestType = SecTranformCustomGetAttribute(ref, kSecDigestTypeAttribute, kSecTransformMetaAttributeValue);
69 SecTransformRef digest0 = transforms_assume(SecDigestTransformCreate(digestType, 0, NULL));
70 int32_t digestLength = 0;
71 {
72 CFNumberRef digestLengthAsCFNumber = SecTransformGetAttribute(digest0, kSecDigestLengthAttribute);
73 CFNumberGetValue(transforms_assume(digestLengthAsCFNumber), kCFNumberSInt32Type, &digestLength);
74 }
75 (void)transforms_assume(digestLength >= 0);
76
77 UInt8 *buffer = malloc(outputLength + digestLength);
78 if (!buffer) {
79 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, GetNoMemoryErrorAndRetain());
80 return (CFErrorRef)NULL;
81 }
82
83 dispatch_group_t all_hashed = dispatch_group_create();
84 dispatch_group_enter(all_hashed);
85 for(; l < outputLength; l += digestLength, i++) {
86 dispatch_group_enter(all_hashed);
87 CFErrorRef err = NULL;
88 SecTransformRef digest = NULL;
89 if (l == 0) {
90 digest = digest0;
91 } else {
92 digest = SecDigestTransformCreate(digestType, 0, &err);
93 if (digest == NULL) {
94 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, err);
95 return (CFErrorRef)NULL;
96 }
97 }
98
99 // NOTE: we shuld be able to do this without the copy, make a transform that takes an
100 // array and outputs each item in the array followed by a NULL ought to be quicker.
101 CFMutableDataRef accumulatorPlusCounter = CFDataCreateMutableCopy(NULL, CFDataGetLength(accumulator) + sizeof(uint32_t), accumulator);
102 int32_t bigendian_i = htonl(i);
103 CFDataAppendBytes(accumulatorPlusCounter, (UInt8*)&bigendian_i, sizeof(bigendian_i));
104 SecTransformSetAttribute(digest, kSecTransformInputAttributeName, accumulatorPlusCounter, &err);
105 CFRelease(accumulatorPlusCounter);
106
107 UInt8 *buf = buffer + l;
108 SecTransformExecuteAsync(digest, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFTypeRef message, CFErrorRef error, Boolean isFinal) {
109 if (message) {
110 CFIndex messageLen = CFDataGetLength(message);
111 CFDataGetBytes(message, CFRangeMake(0, messageLen), buf);
112 }
113 if (error) {
114 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, error);
115 }
116 if (isFinal) {
117 dispatch_group_leave(all_hashed);
118 }
119 });
120 CFRelease(digest);
121 }
122
123 dispatch_group_leave(all_hashed);
124 dispatch_group_wait(all_hashed, DISPATCH_TIME_FOREVER);
125 CFDataRef out = CFDataCreateWithBytesNoCopy(NULL, buffer, outputLength, kCFAllocatorMalloc);
126 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, out);
127 CFRelease(out);
128 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, NULL);
129 }
130 return (CFErrorRef)NULL;
131 });
132
133 return (CFErrorRef)NULL;
134 };
135
136 return Block_copy(instanceBlock);
137 }
138
139 SecTransformRef SecCreateMaskGenerationFunctionTransform(CFStringRef hashType, int length, CFErrorRef *error)
140 {
141 static dispatch_once_t once;
142 __block Boolean ok = TRUE;
143
144 if (length <= 0) {
145 if (error) {
146 *error = CreateSecTransformErrorRef(kSecTransformErrorInvalidLength, "MaskGenerationFunction Length must be one or more (not %d)", length);
147 }
148 return NULL;
149 }
150
151 dispatch_once(&once, ^(void) {
152 ok = SecTransformRegister(kMaskGenerationFunctionTransformName, MaskGenerationFunctionTransform, error);
153 });
154
155 if (!ok) {
156 return NULL;
157 }
158
159 SecTransformRef ret = SecTransformCreate(kMaskGenerationFunctionTransformName, error);
160 if (!ret) {
161 return NULL;
162 }
163
164 if (!SecTransformSetAttribute(ret, kSecDigestTypeAttribute, hashType ? hashType : kSecDigestSHA1, error)) {
165 CFRelease(ret);
166 return NULL;
167 }
168
169 CFNumberRef len = CFNumberCreate(NULL, kCFNumberIntType, &length);
170 ok = SecTransformSetAttribute(ret, kLengthName, len, error);
171 CFRelease(len);
172 if (!ok) {
173 CFRelease(ret);
174 return NULL;
175 }
176
177 return ret;
178 }