2 * SecSignVerifyTransform.c
3 * libsecurity_transform
5 * Created by JOsborne on 3/11/10.
6 * Copyright 2010 Apple. All rights reserved.
10 #include "SecSignVerifyTransform.h"
11 #include "SecCustomTransform.h"
12 #include "Utilities.h"
13 #include <Security/Security.h>
17 const static CFStringRef SignName
= CFSTR("com.apple.security.Sign"), VerifyName
= CFSTR("com.apple.security.Verify");
18 CFStringRef kSecKeyAttributeName
= CFSTR("KEY"), kSecSignatureAttributeName
= CFSTR("Signature"), kSecInputIsAttributeName
= CFSTR("InputIs");
19 // Internally we force kSecInputIsAttributeName to one of these 3 things, you can use == rather then CFStringCompare once that happens
20 CFStringRef kSecInputIsPlainText
= CFSTR("PlainText"), kSecInputIsDigest
= CFSTR("Digest"), kSecInputIsRaw
= CFSTR("Raw");
22 CFErrorRef
do_sec_fail(OSStatus code
, const char *func
, const char *file
, int line
) {
23 CFStringRef msg
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("Internal error #%x at %s %s:%d"), code
, func
, file
, line
);
24 CFErrorRef err
= fancy_error(CFSTR("Internal CSSM error"), code
, msg
);
29 #define SEC_FAIL(err) if (err) { \
30 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, do_sec_fail(err, __func__, __FILE__, __LINE__)); \
31 return (CFTypeRef)NULL; \
33 #define GET_SEC_FAIL(err) do_sec_fail(err, __func__, __FILE__, __LINE__)
35 CFErrorRef
accumulate_data(CFMutableArrayRef
*a
, CFDataRef d
) {
37 *a
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
39 return GetNoMemoryError();
42 CFDataRef dc
= CFDataCreateCopy(NULL
, d
);
44 return GetNoMemoryError();
46 CFIndex c
= CFArrayGetCount(*a
);
47 CFArrayAppendValue(*a
, dc
);
49 if (CFArrayGetCount(*a
) != c
+1) {
50 return GetNoMemoryError();
56 CFErrorRef
fetch_and_clear_accumulated_data(CFMutableArrayRef
*a
, CFDataRef
*data_out
) {
58 *data_out
= CFDataCreate(NULL
, NULL
, 0);
59 return (*data_out
) ? NULL
: GetNoMemoryError();
62 CFIndex i
, c
= CFArrayGetCount(*a
);
63 CFIndex total
= 0, prev_total
= 0;
65 for(i
= 0; i
< c
; i
++) {
66 total
+= CFDataGetLength((CFDataRef
)CFArrayGetValueAtIndex(*a
, i
));
67 if (total
< prev_total
) {
68 return GetNoMemoryError();
73 CFMutableDataRef out
= CFDataCreateMutable(NULL
, total
);
75 return GetNoMemoryError();
78 for(i
= 0; i
< c
; i
++) {
79 CFDataRef d
= (CFDataRef
)CFArrayGetValueAtIndex(*a
, i
);
80 CFDataAppendBytes(out
, CFDataGetBytePtr(d
), CFDataGetLength(d
));
83 if (CFDataGetLength(out
) != total
) {
85 return GetNoMemoryError();
88 CFArrayRef accumulator
= *a
;
89 CFRelease(accumulator
);
92 // This might be nice:
93 // *data_out = CFDataCreateCopy(NULL, out);
95 // but that is slow (for large values) AND isn't really all that important anyway
102 struct digest_mapping
{
103 // These 3 values are "search values"
104 CSSM_ALGORITHMS kclass
;
105 CFStringRef digest_name
;
109 CSSM_ALGORITHMS plain_text_algo
, digest_algo
;
112 Boolean
digest_mapping_equal(struct digest_mapping
*a
, struct digest_mapping
*b
) {
117 if (a
->kclass
== b
->kclass
&& a
->digest_length
== b
->digest_length
&& !CFStringCompare(a
->digest_name
, b
->digest_name
, 0)) {
124 CFHashCode
digest_mapping_hash(struct digest_mapping
*dm
) {
125 return CFHash(dm
->digest_name
) + dm
->kclass
+ dm
->digest_length
;
128 CSSM_ALGORITHMS
alg_for_signature_context(CFStringRef input_is
, const struct digest_mapping
*dm
) {
129 if (!CFStringCompare(kSecInputIsPlainText
, input_is
, 0)) {
130 return dm
->plain_text_algo
;
131 } else if (!CFStringCompare(kSecInputIsDigest
, input_is
, 0) || !CFStringCompare(kSecInputIsRaw
, input_is
, 0)) {
134 return CSSM_ALGID_NONE
;
138 CFErrorRef
pick_sign_alg(CFStringRef digest
, int digest_length
, const CSSM_KEY
*ckey
, struct digest_mapping
**picked
) {
139 static dispatch_once_t once
= 0;
140 static CFMutableSetRef algos
= NULL
;
142 dispatch_once(&once
, ^{
143 struct digest_mapping digest_mappings_stack
[] = {
144 {CSSM_ALGID_RSA
, kSecDigestSHA1
, 0, CSSM_ALGID_SHA1WithRSA
, CSSM_ALGID_SHA1
},
145 {CSSM_ALGID_RSA
, kSecDigestSHA1
, 160, CSSM_ALGID_SHA1WithRSA
, CSSM_ALGID_SHA1
},
147 {CSSM_ALGID_RSA
, kSecDigestMD2
, 0, CSSM_ALGID_MD2WithRSA
, CSSM_ALGID_MD2
},
148 {CSSM_ALGID_RSA
, kSecDigestMD2
, 128, CSSM_ALGID_MD2WithRSA
, CSSM_ALGID_MD2
},
150 {CSSM_ALGID_RSA
, kSecDigestMD5
, 0, CSSM_ALGID_MD5WithRSA
, CSSM_ALGID_MD5
},
151 {CSSM_ALGID_RSA
, kSecDigestMD5
, 128, CSSM_ALGID_MD5WithRSA
, CSSM_ALGID_MD5
},
153 {CSSM_ALGID_RSA
, kSecDigestSHA2
, 0, CSSM_ALGID_SHA512WithRSA
, CSSM_ALGID_SHA512
},
154 {CSSM_ALGID_RSA
, kSecDigestSHA2
, 512, CSSM_ALGID_SHA512WithRSA
, CSSM_ALGID_SHA512
},
155 {CSSM_ALGID_RSA
, kSecDigestSHA2
, 384, CSSM_ALGID_SHA384WithRSA
, CSSM_ALGID_SHA384
},
156 {CSSM_ALGID_RSA
, kSecDigestSHA2
, 256, CSSM_ALGID_SHA256WithRSA
, CSSM_ALGID_SHA256
},
157 {CSSM_ALGID_RSA
, kSecDigestSHA2
, 224, CSSM_ALGID_SHA224WithRSA
, CSSM_ALGID_SHA224
},
160 {CSSM_ALGID_ECDSA
, kSecDigestSHA1
, 0, CSSM_ALGID_SHA1WithECDSA
, CSSM_ALGID_SHA1
},
161 {CSSM_ALGID_ECDSA
, kSecDigestSHA1
, 160, CSSM_ALGID_SHA1WithECDSA
, CSSM_ALGID_SHA1
},
163 {CSSM_ALGID_ECDSA
, kSecDigestSHA2
, 0, CSSM_ALGID_SHA512WithECDSA
, CSSM_ALGID_SHA512
},
164 {CSSM_ALGID_ECDSA
, kSecDigestSHA2
, 512, CSSM_ALGID_SHA512WithECDSA
, CSSM_ALGID_SHA512
},
165 {CSSM_ALGID_ECDSA
, kSecDigestSHA2
, 384, CSSM_ALGID_SHA384WithECDSA
, CSSM_ALGID_SHA384
},
166 {CSSM_ALGID_ECDSA
, kSecDigestSHA2
, 256, CSSM_ALGID_SHA256WithECDSA
, CSSM_ALGID_SHA256
},
167 {CSSM_ALGID_ECDSA
, kSecDigestSHA2
, 224, CSSM_ALGID_SHA224WithECDSA
, CSSM_ALGID_SHA224
},
169 {CSSM_ALGID_DSA
, kSecDigestSHA1
, 0, CSSM_ALGID_SHA1WithDSA
, CSSM_ALGID_SHA1
},
170 {CSSM_ALGID_DSA
, kSecDigestSHA1
, 160, CSSM_ALGID_SHA1WithDSA
, CSSM_ALGID_SHA1
},
173 CFIndex mapping_count
= sizeof(digest_mappings_stack
)/sizeof(digest_mappings_stack
[0]);
174 void *digest_mappings
= malloc(sizeof(digest_mappings_stack
));
175 memcpy(digest_mappings
, digest_mappings_stack
, sizeof(digest_mappings_stack
));
177 CFSetCallBacks dmcb
= { .version
= 0, .retain
= NULL
, .release
= NULL
, .copyDescription
= NULL
, .equal
= (CFSetEqualCallBack
)digest_mapping_equal
, .hash
= (CFSetHashCallBack
)digest_mapping_hash
};
179 algos
= CFSetCreateMutable(NULL
, mapping_count
, &dmcb
);
181 for(i
= 0; i
< mapping_count
; i
++) {
182 CFSetAddValue(algos
, i
+ (struct digest_mapping
*)digest_mappings
);
186 struct digest_mapping search
;
187 search
.kclass
= ckey
->KeyHeader
.AlgorithmId
;
188 search
.digest_name
= digest
;
189 search
.digest_length
= digest_length
;
191 struct digest_mapping
*dmapping
= (void*)CFSetGetValue(algos
, &search
);
198 // It is argueable better to gennerate these messages by looking at digest_mappings, but with only 3 keytypes and 4 digests (only one of which has signifigant length variations) a case statment is likely the best way.
199 switch (ckey
->KeyHeader
.AlgorithmId
) {
201 return fancy_error(kSecTransformErrorDomain
, kSecTransformErrorInvalidAlgorithm
, CFSTR("Invalid digest algorithm for RSA signature, choose one of: SHA1, SHA2 (512bits, 348bits, 256bits, or 224 bits), MD2, or MD5"));
204 case CSSM_ALGID_ECDSA
:
205 return fancy_error(kSecTransformErrorDomain
, kSecTransformErrorInvalidAlgorithm
, CFSTR("Invalid digest algorithm for ECDSA signature, choose one of: SHA1, or SHA2 (512bits, 348bits, 256bits, or 224 bits)"));
209 return fancy_error(kSecTransformErrorDomain
, kSecTransformErrorInvalidAlgorithm
, CFSTR("Invalid digest algorithm for DSA signature, only SHA1 is supported"));
213 return fancy_error(kSecTransformErrorDomain
, kSecTransformErrorInvalidAlgorithm
, CFSTR("Expected key to be RSA, DSA or ECDSA key"));
217 static SecTransformInstanceBlock
SignTransform(CFStringRef name
,
218 SecTransformRef newTransform
,
219 SecTransformImplementationRef ref
)
221 SecTransformInstanceBlock instanceBlock
= ^
223 CFErrorRef result
= NULL
;
224 SecTransformCustomSetAttribute(ref
, kSecKeyAttributeName
, kSecTransformMetaAttributeRequired
, kCFBooleanTrue
);
225 SecTransformCustomSetAttribute(ref
, kSecInputIsAttributeName
, kSecTransformMetaAttributeRequired
, kCFBooleanTrue
);
227 __block CSSM_CC_HANDLE cch
;
228 __block SecKeyRef key
= NULL
;
229 __block SecTransformDataBlock first_process_data
= NULL
;
230 __block CFStringRef digest
= NULL
;
231 __block
int digest_length
= 0;
232 __block CFStringRef input_is
= NULL
;
233 __block CFMutableArrayRef data_accumulator
= NULL
;
234 __block
struct digest_mapping
*sign_alg
;
236 SecTransformDataBlock plain_text_process_data
=
244 c_d
.Data
= (void*)CFDataGetBytePtr(d
);
245 c_d
.Length
= CFDataGetLength(d
);
247 rc
= CSSM_SignDataUpdate(cch
, &c_d
, 1);
251 const int max_sig_size
= 32*1024;
252 unsigned char *sig_data
= malloc(max_sig_size
);
254 sig
.Length
= max_sig_size
;
256 rc
= CSSM_SignDataFinal(cch
, &sig
);
258 assert(sig
.Length
<= 32*1024);
259 CSSM_DeleteContext(cch
);
260 // Could use NoCopy and hold onto the allocation, and that will be a good idea when we can have it not so oversized
261 CFDataRef result
= CFDataCreate(NULL
, sig
.Data
, sig
.Length
);
262 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
, kSecTransformMetaAttributeValue
, result
);
273 SecTransformSetDataAction(ref
, kSecTransformActionProcessData
, first_process_data
);
275 return (CFTypeRef
)NULL
;
278 return SecTransformNoData();
281 SecTransformDataBlock cooked_process_data
=
286 accumulate_data(&data_accumulator
, d
);
289 const int max_sig_size
= 32*1024;
290 unsigned char *sig_data
= malloc(max_sig_size
);
292 sig
.Length
= max_sig_size
;
295 CFErrorRef err
= fetch_and_clear_accumulated_data(&data_accumulator
, &alldata
);
297 return (CFTypeRef
)err
;
300 c_d
.Data
= (void*)CFDataGetBytePtr(alldata
);
301 c_d
.Length
= CFDataGetLength(alldata
);
303 OSStatus rc
= CSSM_SignData(cch
, &c_d
, 1, (input_is
== kSecInputIsDigest
) ? sign_alg
->digest_algo
: CSSM_ALGID_NONE
, &sig
);
307 assert(sig
.Length
<= 32*1024);
308 CSSM_DeleteContext(cch
);
309 // Could use NoCopy and hold onto the allocation, and that will be a good idea when we can have it not so oversized
310 CFDataRef result
= CFDataCreate(NULL
, sig
.Data
, sig
.Length
);
311 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
, kSecTransformMetaAttributeValue
, result
);
322 SecTransformSetDataAction(ref
, kSecTransformActionProcessData
, first_process_data
);
324 return (CFTypeRef
)NULL
;
327 return SecTransformNoData();
330 first_process_data
= Block_copy(^(CFTypeRef value
)
333 if (key
&& digest
&& input_is
)
335 const CSSM_KEY
*cssm_key
;
336 rc
= SecKeyGetCSSMKey(key
, &cssm_key
);
339 CFErrorRef bad_alg
= pick_sign_alg(digest
, digest_length
, cssm_key
, &sign_alg
);
342 return (CFTypeRef
)bad_alg
;
346 rc
= SecKeyGetCSPHandle(key
, &csp
);
349 const CSSM_ACCESS_CREDENTIALS
*access_cred
;
350 rc
= SecKeyGetCredentials(key
, CSSM_ACL_AUTHORIZATION_SIGN
, kSecCredentialTypeDefault
, &access_cred
);
353 CSSM_CSP_CreateSignatureContext(csp
, alg_for_signature_context(input_is
, sign_alg
), access_cred
, cssm_key
, &cch
);
356 rc
= CSSM_SignDataInit(cch
);
359 SecTransformDataBlock pd
= (input_is
== kSecInputIsPlainText
) ? plain_text_process_data
: cooked_process_data
;
361 SecTransformSetDataAction(ref
, kSecTransformActionProcessData
, pd
);
366 SecTransformPushbackAttribute(ref
, kSecTransformInputAttributeName
, value
);
367 return SecTransformNoData();
371 SecTransformSetDataAction(ref
, kSecTransformActionProcessData
, first_process_data
);
373 SecTransformSetAttributeAction(ref
, kSecTransformActionAttributeNotification
, kSecDigestTypeAttribute
,
374 ^(SecTransformAttributeRef ah
, CFTypeRef value
)
376 digest
= CFRetain(value
);
380 SecTransformSetAttributeAction(ref
, kSecTransformActionAttributeNotification
, kSecKeyAttributeName
,
381 ^(SecTransformAttributeRef ah
, CFTypeRef value
)
387 const CSSM_KEY
*cssm_key
;
388 key
= (SecKeyRef
)value
;
390 OSStatus rc
= SecKeyGetCSSMKey(key
, &cssm_key
);
393 if (!cssm_key
->KeyHeader
.KeyUsage
& CSSM_KEYUSE_SIGN
)
397 CFTypeRef error
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInput
, "Key %@ can not be used to sign", key
);
398 SecTransformCustomSetAttribute(ref
, kSecTransformAbortAttributeName
, kSecTransformMetaAttributeValue
, error
);
399 return (CFTypeRef
)NULL
;
404 SecTransformSetAttributeAction(ref
, kSecTransformActionAttributeNotification
, kSecDigestLengthAttribute
,
405 ^(SecTransformAttributeRef ah
, CFTypeRef value
)
407 CFNumberGetValue(value
, kCFNumberIntType
, &digest_length
);
411 SecTransformSetAttributeAction(ref
, kSecTransformActionAttributeNotification
, kSecInputIsAttributeName
,
412 ^(SecTransformAttributeRef ah
, CFTypeRef value
)
414 if (!CFStringCompare(value
, kSecInputIsPlainText
, 0)) {
415 input_is
= kSecInputIsPlainText
;
416 } else if (!CFStringCompare(value
, kSecInputIsDigest
, 0)) {
417 input_is
= kSecInputIsDigest
;
418 } else if (!CFStringCompare(value
, kSecInputIsRaw
, 0)) {
419 input_is
= kSecInputIsRaw
;
422 return (CFTypeRef
)fancy_error(kSecTransformErrorDomain
, kSecTransformErrorInvalidType
, CFSTR("InputIs should be one of: PlainText, Digest, or Raw"));
424 return (CFTypeRef
)input_is
;
427 SecTransformSetTransformAction(ref
, kSecTransformActionFinalize
,
429 Block_release(first_process_data
);
430 return (CFTypeRef
)NULL
;
436 return Block_copy(instanceBlock
);
439 SecTransformRef
SecSignTransformCreate(SecKeyRef key
, CFErrorRef
* error
)
441 static dispatch_once_t once
;
442 __block Boolean ok
= TRUE
;
444 dispatch_block_t aBlock
= ^
446 ok
= SecTransformRegister(SignName
, &SignTransform
, error
);
449 dispatch_once(&once
, aBlock
);
456 SecTransformRef tr
= SecTransformCreate(SignName
, error
);
460 SecTransformSetAttribute(tr
, kSecKeyAttributeName
, key
, error
);
461 SecTransformSetAttribute(tr
, kSecDigestTypeAttribute
, kSecDigestSHA1
, NULL
);
462 SecTransformSetAttribute(tr
, kSecInputIsAttributeName
, kSecInputIsPlainText
, NULL
);
467 static SecTransformInstanceBlock
VerifyTransform(CFStringRef name
,
468 SecTransformRef newTransform
,
469 SecTransformImplementationRef ref
)
471 SecTransformInstanceBlock instanceBlock
= ^
473 CFErrorRef result
= NULL
;
474 SecTransformCustomSetAttribute(ref
, kSecKeyAttributeName
, kSecTransformMetaAttributeRequired
, kCFBooleanTrue
);
475 SecTransformCustomSetAttribute(ref
, kSecSignatureAttributeName
, kSecTransformMetaAttributeRequired
, kCFBooleanTrue
);
476 SecTransformCustomSetAttribute(ref
, kSecInputIsAttributeName
, kSecTransformMetaAttributeRequired
, kCFBooleanTrue
);
478 __block CSSM_CC_HANDLE cch
;
479 __block
const CSSM_KEY
*cssm_key
;
480 __block CSSM_CSP_HANDLE csp
;
481 __block
const CSSM_ACCESS_CREDENTIALS
*access_cred
;
482 __block CFDataRef signature
= NULL
;
483 __block
unsigned char had_last_input
= 0;
484 __block CFStringRef digest
= NULL
;
485 __block
int digest_length
= 0;
486 __block SecTransformDataBlock first_process_data
;
487 __block SecKeyRef key
= NULL
;
488 __block CFStringRef input_is
= NULL
;
489 __block CFMutableArrayRef data_accumulator
= NULL
;
490 __block
struct digest_mapping
*verify_alg
= NULL
;
492 SecTransformSetAttributeAction(ref
, kSecTransformActionAttributeNotification
, kSecInputIsAttributeName
,
493 ^(SecTransformAttributeRef ah
, CFTypeRef value
)
495 if (!CFStringCompare(value
, kSecInputIsPlainText
, 0)) {
496 input_is
= kSecInputIsPlainText
;
497 } else if (!CFStringCompare(value
, kSecInputIsDigest
, 0)) {
498 input_is
= kSecInputIsDigest
;
499 } else if (!CFStringCompare(value
, kSecInputIsRaw
, 0)) {
500 input_is
= kSecInputIsRaw
;
503 return (CFTypeRef
)fancy_error(kSecTransformErrorDomain
, kSecTransformErrorInvalidType
, CFSTR("InputIs should be one of: PlainText, Digest, or Raw"));
505 return (CFTypeRef
)input_is
;
508 SecTransformSetAttributeAction(ref
, kSecTransformActionAttributeNotification
, kSecKeyAttributeName
,
509 ^(SecTransformAttributeRef ah
, CFTypeRef value
)
517 rc
= SecKeyGetCSSMKey((SecKeyRef
)value
, &cssm_key
);
520 if (!cssm_key
->KeyHeader
.KeyUsage
& CSSM_KEYUSE_VERIFY
)
522 // This key cannot verify!
523 return (CFTypeRef
)CreateSecTransformErrorRef(kSecTransformErrorInvalidInput
, "Key %@ can not be used to verify", key
);
526 // we don't need to retain this because the owning transform is doing that for us
527 key
= (SecKeyRef
) value
;
531 // We call this when we get the last input and when we get the signature. If both are true when it is
532 // called we are really done, and it gennerates the output
535 if (signature
&& had_last_input
)
539 sig
.Data
= (void*)CFDataGetBytePtr(signature
);
540 sig
.Length
= CFDataGetLength(signature
);
541 CFRelease(signature
);
544 if (input_is
== kSecInputIsPlainText
) {
545 rc
= CSSM_VerifyDataFinal(cch
, &sig
);
548 CFErrorRef err
= fetch_and_clear_accumulated_data(&data_accumulator
, &alldata
);
550 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
, kSecTransformMetaAttributeValue
, (CFTypeRef
)err
);
555 c_d
.Data
= (void*)CFDataGetBytePtr(alldata
);
556 c_d
.Length
= CFDataGetLength(alldata
);
558 rc
= CSSM_VerifyData(cch
, &c_d
, 1, (input_is
== kSecInputIsDigest
) ? verify_alg
->digest_algo
: CSSM_ALGID_NONE
, &sig
);
560 CSSM_DeleteContext(cch
);
561 if (rc
== 0 || rc
== CSSMERR_CSP_VERIFY_FAILED
) {
562 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
, kSecTransformMetaAttributeValue
, rc
? kCFBooleanFalse
: kCFBooleanTrue
);
563 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
, kSecTransformMetaAttributeValue
, NULL
);
565 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
, kSecTransformMetaAttributeValue
, GET_SEC_FAIL(rc
));
567 had_last_input
= FALSE
;
568 SecTransformSetDataAction(ref
, kSecTransformActionProcessData
, first_process_data
);
572 SecTransformSetAttributeAction(ref
, kSecTransformActionAttributeNotification
, kSecSignatureAttributeName
,
573 ^(SecTransformAttributeRef ah
, CFTypeRef value
)
576 signature
= CFRetain(value
);
581 return (CFTypeRef
)value
;
584 SecTransformDataBlock process_data
=
591 if (input_is
== kSecInputIsPlainText
) {
593 c_d
.Data
= (void*)CFDataGetBytePtr(d
);
594 c_d
.Length
= CFDataGetLength(d
);
596 rc
= CSSM_VerifyDataUpdate(cch
, &c_d
, 1);
599 accumulate_data(&data_accumulator
, d
);
606 return SecTransformNoData();
612 if (key
&& digest
&& input_is
) {
613 // XXX: For RSA keys, signal an error if the digest size>keysize
615 OSStatus rc
= SecKeyGetCSPHandle(key
, &csp
);
618 rc
= SecKeyGetCredentials(key
, CSSM_ACL_AUTHORIZATION_ANY
, kSecCredentialTypeDefault
, &access_cred
);
621 CFErrorRef bad_alg
= pick_sign_alg(digest
, digest_length
, cssm_key
, &verify_alg
);
623 return (CFTypeRef
)bad_alg
;
626 CSSM_CSP_CreateSignatureContext(csp
, alg_for_signature_context(input_is
, verify_alg
), NULL
, cssm_key
, &cch
);
629 rc
= CSSM_VerifyDataInit(cch
);
632 SecTransformSetDataAction(ref
, kSecTransformActionProcessData
, process_data
);
633 return process_data(value
);
635 SecTransformPushbackAttribute(ref
, kSecTransformInputAttributeName
, value
);
636 return SecTransformNoData();
639 first_process_data
= Block_copy(first_process_data
);
641 SecTransformSetAttributeAction(ref
, kSecTransformActionAttributeNotification
, kSecDigestTypeAttribute
,
642 ^(SecTransformAttributeRef ah
, CFTypeRef value
)
644 digest
= CFRetain(value
);
648 SecTransformSetTransformAction(ref
, kSecTransformActionFinalize
,
650 Block_release(first_process_data
);
651 return (CFTypeRef
)NULL
;
654 SecTransformSetAttributeAction(ref
, kSecTransformActionAttributeNotification
, kSecDigestLengthAttribute
,
655 ^(SecTransformAttributeRef ah
, CFTypeRef value
)
657 CFNumberGetValue(value
, kCFNumberIntType
, &digest_length
);
661 SecTransformSetDataAction(ref
, kSecTransformActionProcessData
, first_process_data
);
666 return Block_copy(instanceBlock
);
669 SecTransformRef
SecVerifyTransformCreate(SecKeyRef key
, CFDataRef signature
, CFErrorRef
* error
)
671 static dispatch_once_t once
;
672 __block Boolean ok
= TRUE
;
674 dispatch_block_t aBlock
= ^
676 ok
= SecTransformRegister(VerifyName
, &VerifyTransform
, error
);
679 dispatch_once(&once
, aBlock
);
687 SecTransformRef tr
= SecTransformCreate(VerifyName
, error
);
692 SecTransformSetAttribute(tr
, kSecKeyAttributeName
, key
, error
);
695 SecTransformSetAttribute(tr
, kSecSignatureAttributeName
, signature
, error
);
697 SecTransformSetAttribute(tr
, kSecDigestTypeAttribute
, kSecDigestSHA1
, NULL
);
698 SecTransformSetAttribute(tr
, kSecDigestTypeAttribute
, kSecDigestSHA1
, NULL
);
699 SecTransformSetAttribute(tr
, kSecInputIsAttributeName
, kSecInputIsPlainText
, NULL
);