2 * Copyright (c) 2011-2012,2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 #include <CoreFoundation/CoreFoundation.h>
27 #include "SecMaskGenerationFunctionTransform.h"
28 #include "SecCustomTransform.h"
29 #include "SecDigestTransform.h"
31 #include "Utilities.h"
33 static const CFStringRef kMaskGenerationFunctionTransformName
= CFSTR("com.apple.security.MGF1");
34 static const CFStringRef kLengthName
= CFSTR("Length");
36 static SecTransformInstanceBlock
MaskGenerationFunctionTransform(CFStringRef name
,
37 SecTransformRef newTransform
,
38 SecTransformImplementationRef ref
)
40 __block CFMutableDataRef accumulator
= CFDataCreateMutable(NULL
, 0);
41 __block
int32_t outputLength
= 0;
43 SecTransformInstanceBlock instanceBlock
= ^{
44 SecTransformSetTransformAction(ref
, kSecTransformActionFinalize
, ^{
45 CFRelease(accumulator
);
47 return (CFTypeRef
)NULL
;
50 // XXX: be a good citizen, put a validator in for the types.
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
));
58 return (CFTypeRef
)NULL
;
61 SecTransformSetAttributeAction(ref
, kSecTransformActionAttributeNotification
, kSecTransformInputAttributeName
, ^CFTypeRef(SecTransformAttributeRef attribute
, CFTypeRef value
) {
64 CFDataAppendBytes(accumulator
, CFDataGetBytePtr(d
), CFDataGetLength(d
));
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;
72 CFNumberRef digestLengthAsCFNumber
= SecTransformGetAttribute(digest0
, kSecDigestLengthAttribute
);
73 CFNumberGetValue(transforms_assume(digestLengthAsCFNumber
), kCFNumberSInt32Type
, &digestLength
);
75 (void)transforms_assume(digestLength
>= 0);
77 UInt8
*buffer
= malloc(outputLength
+ digestLength
);
79 SecTransformCustomSetAttribute(ref
, kSecTransformAbortAttributeName
, kSecTransformMetaAttributeValue
, GetNoMemoryErrorAndRetain());
80 return (CFErrorRef
)NULL
;
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
;
92 digest
= SecDigestTransformCreate(digestType
, 0, &err
);
94 SecTransformCustomSetAttribute(ref
, kSecTransformAbortAttributeName
, kSecTransformMetaAttributeValue
, err
);
95 return (CFErrorRef
)NULL
;
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
);
107 UInt8
*buf
= buffer
+ l
;
108 SecTransformExecuteAsync(digest
, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^(CFTypeRef message
, CFErrorRef error
, Boolean isFinal
) {
110 CFIndex messageLen
= CFDataGetLength(message
);
111 CFDataGetBytes(message
, CFRangeMake(0, messageLen
), buf
);
114 SecTransformCustomSetAttribute(ref
, kSecTransformAbortAttributeName
, kSecTransformMetaAttributeValue
, error
);
117 dispatch_group_leave(all_hashed
);
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
);
128 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
, kSecTransformMetaAttributeValue
, NULL
);
130 return (CFErrorRef
)NULL
;
133 return (CFErrorRef
)NULL
;
136 return Block_copy(instanceBlock
);
139 SecTransformRef
SecCreateMaskGenerationFunctionTransform(CFStringRef hashType
, int length
, CFErrorRef
*error
)
141 static dispatch_once_t once
;
142 __block Boolean ok
= TRUE
;
146 *error
= CreateSecTransformErrorRef(kSecTransformErrorInvalidLength
, "MaskGenerationFunction Length must be one or more (not %d)", length
);
151 dispatch_once(&once
, ^(void) {
152 ok
= SecTransformRegister(kMaskGenerationFunctionTransformName
, MaskGenerationFunctionTransform
, error
);
159 SecTransformRef ret
= SecTransformCreate(kMaskGenerationFunctionTransformName
, error
);
164 if (!SecTransformSetAttribute(ret
, kSecDigestTypeAttribute
, hashType
? hashType
: kSecDigestSHA1
, error
)) {
169 CFNumberRef len
= CFNumberCreate(NULL
, kCFNumberIntType
, &length
);
170 ok
= SecTransformSetAttribute(ret
, kLengthName
, len
, error
);