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");
23 CFErrorRef
do_sec_fail(OSStatus code
, const char *func
, const char *file
, int line
) {
24 CFStringRef msg
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("Internal error #%x at %s %s:%d"), (unsigned)code
, func
, file
, line
);
25 CFErrorRef err
= fancy_error(CFSTR("Internal CSSM error"), code
, msg
);
30 #define SEC_FAIL(err) if (err) { \
31 SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, do_sec_fail(err, __func__, __FILE__, __LINE__)); \
32 return (CFTypeRef)NULL; \
34 #define GET_SEC_FAIL(err) do_sec_fail(err, __func__, __FILE__, __LINE__)
37 CFErrorRef
accumulate_data(CFMutableArrayRef
*a
, CFDataRef d
) {
39 *a
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
41 return GetNoMemoryError();
44 CFDataRef dc
= CFDataCreateCopy(NULL
, d
);
46 return GetNoMemoryError();
48 CFIndex c
= CFArrayGetCount(*a
);
49 CFArrayAppendValue(*a
, dc
);
51 if (CFArrayGetCount(*a
) != c
+1) {
52 return GetNoMemoryError();
59 CFErrorRef
fetch_and_clear_accumulated_data(CFMutableArrayRef
*a
, CFDataRef
*data_out
) {
61 *data_out
= CFDataCreate(NULL
, NULL
, 0);
62 return (*data_out
) ? NULL
: GetNoMemoryError();
65 CFIndex i
, c
= CFArrayGetCount(*a
);
66 CFIndex total
= 0, prev_total
= 0;
68 for(i
= 0; i
< c
; i
++) {
69 total
+= CFDataGetLength((CFDataRef
)CFArrayGetValueAtIndex(*a
, i
));
70 if (total
< prev_total
) {
71 return GetNoMemoryError();
76 CFMutableDataRef out
= CFDataCreateMutable(NULL
, total
);
78 return GetNoMemoryError();
81 for(i
= 0; i
< c
; i
++) {
82 CFDataRef d
= (CFDataRef
)CFArrayGetValueAtIndex(*a
, i
);
83 CFDataAppendBytes(out
, CFDataGetBytePtr(d
), CFDataGetLength(d
));
86 if (CFDataGetLength(out
) != total
) {
88 return GetNoMemoryError();
91 CFArrayRef accumulator
= *a
;
92 CFRelease(accumulator
);
95 // This might be nice:
96 // *data_out = CFDataCreateCopy(NULL, out);
98 // but that is slow (for large values) AND isn't really all that important anyway
105 struct digest_mapping
{
106 // These 3 values are "search values"
107 CSSM_ALGORITHMS kclass
;
108 CFStringRef digest_name
;
112 CSSM_ALGORITHMS plain_text_algo
, digest_algo
;
116 Boolean
digest_mapping_equal(struct digest_mapping
*a
, struct digest_mapping
*b
) {
121 if (a
->kclass
== b
->kclass
&& a
->digest_length
== b
->digest_length
&& !CFStringCompare(a
->digest_name
, b
->digest_name
, 0)) {
129 CFHashCode
digest_mapping_hash(struct digest_mapping
*dm
) {
130 return CFHash(dm
->digest_name
) + dm
->kclass
+ dm
->digest_length
;
134 CSSM_ALGORITHMS
alg_for_signature_context(CFStringRef input_is
, const struct digest_mapping
*dm
) {
135 if (!CFStringCompare(kSecInputIsPlainText
, input_is
, 0)) {
136 return dm
->plain_text_algo
;
137 } else if (!CFStringCompare(kSecInputIsDigest
, input_is
, 0) || !CFStringCompare(kSecInputIsRaw
, input_is
, 0)) {
140 return CSSM_ALGID_NONE
;
145 CFErrorRef
pick_sign_alg(CFStringRef digest
, int digest_length
, const CSSM_KEY
*ckey
, struct digest_mapping
**picked
) {
146 static dispatch_once_t once
= 0;
147 static CFMutableSetRef algos
= NULL
;
149 dispatch_once(&once
, ^{
150 struct digest_mapping digest_mappings_stack
[] = {
151 {CSSM_ALGID_RSA
, kSecDigestSHA1
, 0, CSSM_ALGID_SHA1WithRSA
, CSSM_ALGID_SHA1
},
152 {CSSM_ALGID_RSA
, kSecDigestSHA1
, 160, CSSM_ALGID_SHA1WithRSA
, CSSM_ALGID_SHA1
},
154 {CSSM_ALGID_RSA
, kSecDigestMD2
, 0, CSSM_ALGID_MD2WithRSA
, CSSM_ALGID_MD2
},
155 {CSSM_ALGID_RSA
, kSecDigestMD2
, 128, CSSM_ALGID_MD2WithRSA
, CSSM_ALGID_MD2
},
157 {CSSM_ALGID_RSA
, kSecDigestMD5
, 0, CSSM_ALGID_MD5WithRSA
, CSSM_ALGID_MD5
},
158 {CSSM_ALGID_RSA
, kSecDigestMD5
, 128, CSSM_ALGID_MD5WithRSA
, CSSM_ALGID_MD5
},
160 {CSSM_ALGID_RSA
, kSecDigestSHA2
, 0, CSSM_ALGID_SHA512WithRSA
, CSSM_ALGID_SHA512
},
161 {CSSM_ALGID_RSA
, kSecDigestSHA2
, 512, CSSM_ALGID_SHA512WithRSA
, CSSM_ALGID_SHA512
},
162 {CSSM_ALGID_RSA
, kSecDigestSHA2
, 384, CSSM_ALGID_SHA384WithRSA
, CSSM_ALGID_SHA384
},
163 {CSSM_ALGID_RSA
, kSecDigestSHA2
, 256, CSSM_ALGID_SHA256WithRSA
, CSSM_ALGID_SHA256
},
164 {CSSM_ALGID_RSA
, kSecDigestSHA2
, 224, CSSM_ALGID_SHA224WithRSA
, CSSM_ALGID_SHA224
},
167 {CSSM_ALGID_ECDSA
, kSecDigestSHA1
, 0, CSSM_ALGID_SHA1WithECDSA
, CSSM_ALGID_SHA1
},
168 {CSSM_ALGID_ECDSA
, kSecDigestSHA1
, 160, CSSM_ALGID_SHA1WithECDSA
, CSSM_ALGID_SHA1
},
170 {CSSM_ALGID_ECDSA
, kSecDigestSHA2
, 0, CSSM_ALGID_SHA512WithECDSA
, CSSM_ALGID_SHA512
},
171 {CSSM_ALGID_ECDSA
, kSecDigestSHA2
, 512, CSSM_ALGID_SHA512WithECDSA
, CSSM_ALGID_SHA512
},
172 {CSSM_ALGID_ECDSA
, kSecDigestSHA2
, 384, CSSM_ALGID_SHA384WithECDSA
, CSSM_ALGID_SHA384
},
173 {CSSM_ALGID_ECDSA
, kSecDigestSHA2
, 256, CSSM_ALGID_SHA256WithECDSA
, CSSM_ALGID_SHA256
},
174 {CSSM_ALGID_ECDSA
, kSecDigestSHA2
, 224, CSSM_ALGID_SHA224WithECDSA
, CSSM_ALGID_SHA224
},
176 {CSSM_ALGID_DSA
, kSecDigestSHA1
, 0, CSSM_ALGID_SHA1WithDSA
, CSSM_ALGID_SHA1
},
177 {CSSM_ALGID_DSA
, kSecDigestSHA1
, 160, CSSM_ALGID_SHA1WithDSA
, CSSM_ALGID_SHA1
},
180 CFIndex mapping_count
= sizeof(digest_mappings_stack
)/sizeof(digest_mappings_stack
[0]);
181 void *digest_mappings
= malloc(sizeof(digest_mappings_stack
));
182 memcpy(digest_mappings
, digest_mappings_stack
, sizeof(digest_mappings_stack
));
184 CFSetCallBacks dmcb
= { .version
= 0, .retain
= NULL
, .release
= NULL
, .copyDescription
= NULL
, .equal
= (CFSetEqualCallBack
)digest_mapping_equal
, .hash
= (CFSetHashCallBack
)digest_mapping_hash
};
186 algos
= CFSetCreateMutable(NULL
, mapping_count
, &dmcb
);
188 for(i
= 0; i
< mapping_count
; i
++) {
189 CFSetAddValue(algos
, i
+ (struct digest_mapping
*)digest_mappings
);
193 struct digest_mapping search
;
194 search
.kclass
= ckey
->KeyHeader
.AlgorithmId
;
195 search
.digest_name
= digest
;
196 search
.digest_length
= digest_length
;
198 struct digest_mapping
*dmapping
= (void*)CFSetGetValue(algos
, &search
);
205 // 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.
206 switch (ckey
->KeyHeader
.AlgorithmId
) {
208 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"));
211 case CSSM_ALGID_ECDSA
:
212 return fancy_error(kSecTransformErrorDomain
, kSecTransformErrorInvalidAlgorithm
, CFSTR("Invalid digest algorithm for ECDSA signature, choose one of: SHA1, or SHA2 (512bits, 348bits, 256bits, or 224 bits)"));
216 return fancy_error(kSecTransformErrorDomain
, kSecTransformErrorInvalidAlgorithm
, CFSTR("Invalid digest algorithm for DSA signature, only SHA1 is supported"));
220 return fancy_error(kSecTransformErrorDomain
, kSecTransformErrorInvalidAlgorithm
, CFSTR("Expected key to be RSA, DSA or ECDSA key"));
224 static SecTransformInstanceBlock
SignTransform(CFStringRef name
,
225 SecTransformRef newTransform
,
226 SecTransformImplementationRef ref
)
228 SecTransformInstanceBlock instanceBlock
= ^
230 CFErrorRef result
= NULL
;
231 SecTransformCustomSetAttribute(ref
, kSecKeyAttributeName
, kSecTransformMetaAttributeRequired
, kCFBooleanTrue
);
232 SecTransformCustomSetAttribute(ref
, kSecInputIsAttributeName
, kSecTransformMetaAttributeRequired
, kCFBooleanTrue
);
234 __block CSSM_CC_HANDLE cch
;
235 __block SecKeyRef key
= NULL
;
236 __block SecTransformDataBlock first_process_data
= NULL
;
237 __block CFStringRef digest
= NULL
;
238 __block
int digest_length
= 0;
239 __block CFStringRef input_is
= NULL
;
240 __block CFMutableArrayRef data_accumulator
= NULL
;
241 __block
struct digest_mapping
*sign_alg
;
243 SecTransformDataBlock plain_text_process_data
=
251 c_d
.Data
= (void*)CFDataGetBytePtr(d
);
252 c_d
.Length
= CFDataGetLength(d
);
254 rc
= CSSM_SignDataUpdate(cch
, &c_d
, 1);
258 const int max_sig_size
= 32*1024;
259 unsigned char *sig_data
= malloc(max_sig_size
);
261 sig
.Length
= max_sig_size
;
263 rc
= CSSM_SignDataFinal(cch
, &sig
);
265 assert(sig
.Length
<= 32*1024);
266 CSSM_DeleteContext(cch
);
267 // Could use NoCopy and hold onto the allocation, and that will be a good idea when we can have it not so oversized
268 CFDataRef result
= CFDataCreate(NULL
, sig
.Data
, sig
.Length
);
269 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
, kSecTransformMetaAttributeValue
, result
);
280 SecTransformSetDataAction(ref
, kSecTransformActionProcessData
, first_process_data
);
282 return (CFTypeRef
)NULL
;
285 return SecTransformNoData();
288 SecTransformDataBlock cooked_process_data
=
293 accumulate_data(&data_accumulator
, d
);
296 const int max_sig_size
= 32*1024;
297 unsigned char *sig_data
= malloc(max_sig_size
);
299 sig
.Length
= max_sig_size
;
302 CFErrorRef err
= fetch_and_clear_accumulated_data(&data_accumulator
, &alldata
);
304 return (CFTypeRef
)err
;
307 c_d
.Data
= (void*)CFDataGetBytePtr(alldata
);
308 c_d
.Length
= CFDataGetLength(alldata
);
310 OSStatus rc
= CSSM_SignData(cch
, &c_d
, 1, (input_is
== kSecInputIsDigest
) ? sign_alg
->digest_algo
: CSSM_ALGID_NONE
, &sig
);
314 assert(sig
.Length
<= 32*1024);
315 CSSM_DeleteContext(cch
);
316 // Could use NoCopy and hold onto the allocation, and that will be a good idea when we can have it not so oversized
317 CFDataRef result
= CFDataCreate(NULL
, sig
.Data
, sig
.Length
);
318 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
, kSecTransformMetaAttributeValue
, result
);
329 SecTransformSetDataAction(ref
, kSecTransformActionProcessData
, first_process_data
);
331 return (CFTypeRef
)NULL
;
334 return SecTransformNoData();
337 first_process_data
= Block_copy(^(CFTypeRef value
)
340 if (key
&& digest
&& input_is
)
342 const CSSM_KEY
*cssm_key
;
343 rc
= SecKeyGetCSSMKey(key
, &cssm_key
);
346 CFErrorRef bad_alg
= pick_sign_alg(digest
, digest_length
, cssm_key
, &sign_alg
);
349 return (CFTypeRef
)bad_alg
;
353 rc
= SecKeyGetCSPHandle(key
, &csp
);
356 const CSSM_ACCESS_CREDENTIALS
*access_cred
;
357 rc
= SecKeyGetCredentials(key
, CSSM_ACL_AUTHORIZATION_SIGN
, kSecCredentialTypeDefault
, &access_cred
);
360 CSSM_CSP_CreateSignatureContext(csp
, alg_for_signature_context(input_is
, sign_alg
), access_cred
, cssm_key
, &cch
);
363 rc
= CSSM_SignDataInit(cch
);
366 SecTransformDataBlock pd
= (input_is
== kSecInputIsPlainText
) ? plain_text_process_data
: cooked_process_data
;
368 SecTransformSetDataAction(ref
, kSecTransformActionProcessData
, pd
);
373 SecTransformPushbackAttribute(ref
, kSecTransformInputAttributeName
, value
);
374 return SecTransformNoData();
378 SecTransformSetDataAction(ref
, kSecTransformActionProcessData
, first_process_data
);
380 SecTransformSetAttributeAction(ref
, kSecTransformActionAttributeNotification
, kSecDigestTypeAttribute
,
381 ^(SecTransformAttributeRef ah
, CFTypeRef value
)
383 digest
= CFRetain(value
);
387 SecTransformSetAttributeAction(ref
, kSecTransformActionAttributeNotification
, kSecKeyAttributeName
,
388 ^(SecTransformAttributeRef ah
, CFTypeRef value
)
394 const CSSM_KEY
*cssm_key
;
395 key
= (SecKeyRef
)value
;
397 OSStatus rc
= SecKeyGetCSSMKey(key
, &cssm_key
);
400 if (!cssm_key
->KeyHeader
.KeyUsage
& CSSM_KEYUSE_SIGN
)
404 CFTypeRef error
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInput
, "Key %@ can not be used to sign", key
);
405 SecTransformCustomSetAttribute(ref
, kSecTransformAbortAttributeName
, kSecTransformMetaAttributeValue
, error
);
406 return (CFTypeRef
)NULL
;
411 SecTransformSetAttributeAction(ref
, kSecTransformActionAttributeNotification
, kSecDigestLengthAttribute
,
412 ^(SecTransformAttributeRef ah
, CFTypeRef value
)
414 CFNumberGetValue(value
, kCFNumberIntType
, &digest_length
);
418 SecTransformSetAttributeAction(ref
, kSecTransformActionAttributeNotification
, kSecInputIsAttributeName
,
419 ^(SecTransformAttributeRef ah
, CFTypeRef value
)
421 if (!CFStringCompare(value
, kSecInputIsPlainText
, 0)) {
422 input_is
= kSecInputIsPlainText
;
423 } else if (!CFStringCompare(value
, kSecInputIsDigest
, 0)) {
424 input_is
= kSecInputIsDigest
;
425 } else if (!CFStringCompare(value
, kSecInputIsRaw
, 0)) {
426 input_is
= kSecInputIsRaw
;
429 return (CFTypeRef
)fancy_error(kSecTransformErrorDomain
, kSecTransformErrorInvalidType
, CFSTR("InputIs should be one of: PlainText, Digest, or Raw"));
431 return (CFTypeRef
)input_is
;
434 SecTransformSetTransformAction(ref
, kSecTransformActionFinalize
,
436 Block_release(first_process_data
);
437 return (CFTypeRef
)NULL
;
443 return Block_copy(instanceBlock
);
446 SecTransformRef
SecSignTransformCreate(SecKeyRef key
, CFErrorRef
* error
)
448 static dispatch_once_t once
;
449 __block Boolean ok
= TRUE
;
451 dispatch_block_t aBlock
= ^
453 ok
= SecTransformRegister(SignName
, &SignTransform
, error
);
456 dispatch_once(&once
, aBlock
);
463 SecTransformRef tr
= SecTransformCreate(SignName
, error
);
467 SecTransformSetAttribute(tr
, kSecKeyAttributeName
, key
, error
);
468 SecTransformSetAttribute(tr
, kSecDigestTypeAttribute
, kSecDigestSHA1
, NULL
);
469 SecTransformSetAttribute(tr
, kSecInputIsAttributeName
, kSecInputIsPlainText
, NULL
);
474 static SecTransformInstanceBlock
VerifyTransform(CFStringRef name
,
475 SecTransformRef newTransform
,
476 SecTransformImplementationRef ref
)
478 SecTransformInstanceBlock instanceBlock
= ^
480 CFErrorRef result
= NULL
;
481 SecTransformCustomSetAttribute(ref
, kSecKeyAttributeName
, kSecTransformMetaAttributeRequired
, kCFBooleanTrue
);
482 SecTransformCustomSetAttribute(ref
, kSecSignatureAttributeName
, kSecTransformMetaAttributeRequired
, kCFBooleanTrue
);
483 SecTransformCustomSetAttribute(ref
, kSecInputIsAttributeName
, kSecTransformMetaAttributeRequired
, kCFBooleanTrue
);
485 __block CSSM_CC_HANDLE cch
;
486 __block
const CSSM_KEY
*cssm_key
;
487 __block CSSM_CSP_HANDLE csp
;
488 __block
const CSSM_ACCESS_CREDENTIALS
*access_cred
;
489 __block CFDataRef signature
= NULL
;
490 __block
unsigned char had_last_input
= 0;
491 __block CFStringRef digest
= NULL
;
492 __block
int digest_length
= 0;
493 __block SecTransformDataBlock first_process_data
;
494 __block SecKeyRef key
= NULL
;
495 __block CFStringRef input_is
= NULL
;
496 __block CFMutableArrayRef data_accumulator
= NULL
;
497 __block
struct digest_mapping
*verify_alg
= NULL
;
499 SecTransformSetAttributeAction(ref
, kSecTransformActionAttributeNotification
, kSecInputIsAttributeName
,
500 ^(SecTransformAttributeRef ah
, CFTypeRef value
)
502 if (!CFStringCompare(value
, kSecInputIsPlainText
, 0)) {
503 input_is
= kSecInputIsPlainText
;
504 } else if (!CFStringCompare(value
, kSecInputIsDigest
, 0)) {
505 input_is
= kSecInputIsDigest
;
506 } else if (!CFStringCompare(value
, kSecInputIsRaw
, 0)) {
507 input_is
= kSecInputIsRaw
;
510 return (CFTypeRef
)fancy_error(kSecTransformErrorDomain
, kSecTransformErrorInvalidType
, CFSTR("InputIs should be one of: PlainText, Digest, or Raw"));
512 return (CFTypeRef
)input_is
;
515 SecTransformSetAttributeAction(ref
, kSecTransformActionAttributeNotification
, kSecKeyAttributeName
,
516 ^(SecTransformAttributeRef ah
, CFTypeRef value
)
524 rc
= SecKeyGetCSSMKey((SecKeyRef
)value
, &cssm_key
);
527 if (!cssm_key
->KeyHeader
.KeyUsage
& CSSM_KEYUSE_VERIFY
)
529 // This key cannot verify!
530 return (CFTypeRef
)CreateSecTransformErrorRef(kSecTransformErrorInvalidInput
, "Key %@ can not be used to verify", key
);
533 // we don't need to retain this because the owning transform is doing that for us
534 key
= (SecKeyRef
) value
;
538 // We call this when we get the last input and when we get the signature. If both are true when it is
539 // called we are really done, and it gennerates the output
542 if (signature
&& had_last_input
)
546 sig
.Data
= (void*)CFDataGetBytePtr(signature
);
547 sig
.Length
= CFDataGetLength(signature
);
548 CFRelease(signature
);
551 if (input_is
== kSecInputIsPlainText
) {
552 rc
= CSSM_VerifyDataFinal(cch
, &sig
);
555 CFErrorRef err
= fetch_and_clear_accumulated_data(&data_accumulator
, &alldata
);
557 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
, kSecTransformMetaAttributeValue
, (CFTypeRef
)err
);
562 c_d
.Data
= (void*)CFDataGetBytePtr(alldata
);
563 c_d
.Length
= CFDataGetLength(alldata
);
564 rc
= CSSM_VerifyData(cch
, &c_d
, 1, (input_is
== kSecInputIsDigest
) ? verify_alg
->digest_algo
: CSSM_ALGID_NONE
, &sig
);
568 CSSM_DeleteContext(cch
);
569 if (rc
== 0 || rc
== CSSMERR_CSP_VERIFY_FAILED
) {
570 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
, kSecTransformMetaAttributeValue
, rc
? kCFBooleanFalse
: kCFBooleanTrue
);
571 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
, kSecTransformMetaAttributeValue
, NULL
);
573 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
, kSecTransformMetaAttributeValue
, GET_SEC_FAIL(rc
));
575 had_last_input
= FALSE
;
576 SecTransformSetDataAction(ref
, kSecTransformActionProcessData
, first_process_data
);
580 SecTransformSetAttributeAction(ref
, kSecTransformActionAttributeNotification
, kSecSignatureAttributeName
,
581 ^(SecTransformAttributeRef ah
, CFTypeRef value
)
584 signature
= CFRetain(value
);
589 return (CFTypeRef
)value
;
592 SecTransformDataBlock process_data
=
599 if (input_is
== kSecInputIsPlainText
) {
601 c_d
.Data
= (void*)CFDataGetBytePtr(d
);
602 c_d
.Length
= CFDataGetLength(d
);
604 rc
= CSSM_VerifyDataUpdate(cch
, &c_d
, 1);
607 accumulate_data(&data_accumulator
, d
);
614 return SecTransformNoData();
620 if (key
&& digest
&& input_is
) {
621 // XXX: For RSA keys, signal an error if the digest size>keysize
623 OSStatus rc
= SecKeyGetCSPHandle(key
, &csp
);
626 rc
= SecKeyGetCredentials(key
, CSSM_ACL_AUTHORIZATION_ANY
, kSecCredentialTypeDefault
, &access_cred
);
629 CFErrorRef bad_alg
= pick_sign_alg(digest
, digest_length
, cssm_key
, &verify_alg
);
631 return (CFTypeRef
)bad_alg
;
634 CSSM_CSP_CreateSignatureContext(csp
, alg_for_signature_context(input_is
, verify_alg
), NULL
, cssm_key
, &cch
);
637 rc
= CSSM_VerifyDataInit(cch
);
640 SecTransformSetDataAction(ref
, kSecTransformActionProcessData
, process_data
);
641 return process_data(value
);
643 SecTransformPushbackAttribute(ref
, kSecTransformInputAttributeName
, value
);
644 return SecTransformNoData();
647 first_process_data
= Block_copy(first_process_data
);
649 SecTransformSetAttributeAction(ref
, kSecTransformActionAttributeNotification
, kSecDigestTypeAttribute
,
650 ^(SecTransformAttributeRef ah
, CFTypeRef value
)
652 digest
= CFRetain(value
);
656 SecTransformSetTransformAction(ref
, kSecTransformActionFinalize
,
658 Block_release(first_process_data
);
659 return (CFTypeRef
)NULL
;
662 SecTransformSetAttributeAction(ref
, kSecTransformActionAttributeNotification
, kSecDigestLengthAttribute
,
663 ^(SecTransformAttributeRef ah
, CFTypeRef value
)
665 CFNumberGetValue(value
, kCFNumberIntType
, &digest_length
);
669 SecTransformSetDataAction(ref
, kSecTransformActionProcessData
, first_process_data
);
674 return Block_copy(instanceBlock
);
677 SecTransformRef
SecVerifyTransformCreate(SecKeyRef key
, CFDataRef signature
, CFErrorRef
* error
)
679 static dispatch_once_t once
;
680 __block Boolean ok
= TRUE
;
682 dispatch_block_t aBlock
= ^
684 ok
= SecTransformRegister(VerifyName
, &VerifyTransform
, error
);
687 dispatch_once(&once
, aBlock
);
695 SecTransformRef tr
= SecTransformCreate(VerifyName
, error
);
700 SecTransformSetAttribute(tr
, kSecKeyAttributeName
, key
, error
);
703 SecTransformSetAttribute(tr
, kSecSignatureAttributeName
, signature
, error
);
705 SecTransformSetAttribute(tr
, kSecDigestTypeAttribute
, kSecDigestSHA1
, NULL
);
706 SecTransformSetAttribute(tr
, kSecDigestTypeAttribute
, kSecDigestSHA1
, NULL
);
707 SecTransformSetAttribute(tr
, kSecInputIsAttributeName
, kSecInputIsPlainText
, NULL
);