3 * Copyright (c) 2001-2004 Apple Computer, Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * The contents of this file constitute Original Code as defined in and
8 * are subject to the Apple Public Source License Version 1.1 (the
9 * "License"). You may not use this file except in compliance with the
10 * License. Please obtain a copy of the License at
11 * http://www.apple.com/publicsource and read it before using this file.
13 * This 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 OR NON-INFRINGEMENT. Please see the
18 * License for the specific language governing rights and limitations
21 * @APPLE_LICENSE_HEADER_END@
26 * Racoon module for verifying and signing certificates through Security
30 #include <Security/SecCertificate.h>
31 #include <Security/SecPolicy.h>
32 #include <Security/SecTrust.h>
33 #include <Security/SecKey.h>
34 #include <Security/SecIdentity.h>
35 #include <Security/SecItem.h>
36 #include <TargetConditionals.h>
37 #if TARGET_OS_EMBEDDED
38 #include <Security/SecTrustPriv.h>
39 #include <Security/SecPolicyPriv.h>
40 #include <Security/SecCertificatePriv.h>
42 #include <Security/SecBase.h>
43 #include <Security/SecIdentityPriv.h>
44 #include <Security/SecIdentitySearch.h>
45 #include <Security/SecKeychain.h>
46 #include <Security/SecKeychainItem.h>
47 #include <Security/SecKeychainItemPriv.h>
49 #include <Security/SecKeyPriv.h>
50 #include <Security/oidsalg.h>
51 #include <Security/cssmapi.h>
52 #include <Security/SecPolicySearch.h>
55 #include <CoreFoundation/CoreFoundation.h>
56 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
63 #include "crypto_cssm.h"
66 static OSStatus
EvaluateCert(SecCertificateRef evalCertArray
[], CFIndex evalCertArrayNumValues
, CFTypeRef policyRef
, SecKeyRef
*publicKeyRef
);
68 #if !TARGET_OS_EMBEDDED
69 static OSStatus
FindPolicy(const CSSM_OID
*policyOID
, SecPolicyRef
*policyRef
);
70 static OSStatus
CopySystemKeychain(SecKeychainRef
*keychainRef
);
74 crypto_cssm_x509cert_get_SecPolicyRef (CFStringRef hostname
)
76 SecPolicyRef policyRef
= NULL
;
77 #if !TARGET_OS_EMBEDDED
79 CSSM_OID ourPolicyOID
= CSSMOID_APPLE_TP_IP_SEC
;
81 // get our policy object
82 status
= FindPolicy(&ourPolicyOID
, &policyRef
);
83 if (status
!= noErr
&& status
!= -1) {
84 plog(LLV_ERROR
, LOCATION
, NULL
,
85 "error %d %s.\n", status
, GetSecurityErrorString(status
));
89 policyRef
= SecPolicyCreateIPSec(FALSE
, hostname
);
90 if (policyRef
== NULL
) {
91 plog(LLV_ERROR
, LOCATION
, NULL
,
92 "unable to create a SSL policyRef.\n");
100 crypto_cssm_x509cert_get_SecCertificateRef (vchar_t
*cert
)
102 SecCertificateRef certRef
= NULL
;
104 CFDataRef cert_data
= CFDataCreateWithBytesNoCopy(NULL
, cert
->v
, cert
->l
, kCFAllocatorNull
);
106 certRef
= SecCertificateCreateWithData(NULL
, cert_data
);
107 CFRelease(cert_data
);
110 if (certRef
== NULL
) {
111 plog(LLV_ERROR
, LOCATION
, NULL
,
112 "unable to create a certRef.\n");
118 crypto_cssm_check_x509cert_dates (SecCertificateRef certificateRef
)
120 cert_status_t certStatus
= CERT_STATUS_OK
;
121 #if TARGET_OS_EMBEDDED
122 CFAbsoluteTime timeNow
= 0;
123 CFAbsoluteTime notvalidbeforedate
= 0;
124 CFAbsoluteTime notvalidafterdate
= 0;
125 CFDateRef nowcfdatedata
= NULL
;
126 CFDateRef notvalidbeforedatedata
= NULL
;
127 CFDateRef notvalidafterdatedata
= NULL
;
128 CFArrayRef certProparray
= NULL
;
129 CFDictionaryRef propDict
= NULL
;
130 const void *datevalue
= NULL
;
131 const void *labelvalue
= NULL
;
132 CFGregorianDate gregoriandate
;
136 if ((certProparray
= SecCertificateCopyProperties(certificateRef
))){
137 if ((count
= CFArrayGetCount( certProparray
))){
138 for( i
= 0; i
< count
; i
++) {
139 if ((propDict
= CFArrayGetValueAtIndex(certProparray
, i
))) {
140 if ( CFDictionaryGetValueIfPresent(propDict
, kSecPropertyKeyValue
, (const void**)&datevalue
)){
141 /* get kSecPropertyKeyLabel */
142 if ( (datevalue
) && (CFDictionaryGetValueIfPresent(propDict
, kSecPropertyKeyLabel
, (const void**)&labelvalue
))){
143 if ( (labelvalue
) && (CFStringCompare( (CFStringRef
)labelvalue
, CFSTR("Not Valid Before"), 0) == kCFCompareEqualTo
)){
144 if ( notvalidbeforedate
= CFDateGetAbsoluteTime(datevalue
)) {
145 if (notvalidbeforedatedata
) {
146 CFRelease(notvalidbeforedatedata
);
148 notvalidbeforedatedata
= CFDateCreate(NULL
, notvalidbeforedate
);
150 }else if ((labelvalue
) && (CFStringCompare( (CFStringRef
)labelvalue
, CFSTR("Not Valid After"), 0 ) == kCFCompareEqualTo
)){
151 if ( notvalidafterdate
= CFDateGetAbsoluteTime(datevalue
)) {
152 if (notvalidafterdatedata
) {
153 CFRelease(notvalidafterdatedata
);
155 notvalidafterdatedata
= CFDateCreate(NULL
, notvalidafterdate
);
165 if ( (timeNow
= CFAbsoluteTimeGetCurrent()) && (nowcfdatedata
= CFDateCreate( NULL
, timeNow
))){
166 if ( notvalidbeforedatedata
){
167 gregoriandate
= CFAbsoluteTimeGetGregorianDate(notvalidbeforedate
, NULL
);
168 plog(LLV_DEBUG
, LOCATION
, NULL
,
169 "cert not valid before yr %d, mon %d, days %d, hours %d, min %d\n", gregoriandate
.year
, gregoriandate
.month
, gregoriandate
.day
, gregoriandate
.hour
, gregoriandate
.minute
);
170 gregoriandate
= CFAbsoluteTimeGetGregorianDate(notvalidafterdate
, NULL
);
171 plog(LLV_DEBUG
, LOCATION
, NULL
,
172 "cert not valid after yr %d, mon %d, days %d, hours %d, min %d\n", gregoriandate
.year
, gregoriandate
.month
, gregoriandate
.day
, gregoriandate
.hour
, gregoriandate
.minute
);
173 if ( CFDateCompare( nowcfdatedata
, notvalidbeforedatedata
, NULL
) == kCFCompareLessThan
){
174 plog(LLV_ERROR
, LOCATION
, NULL
,
175 "current time before valid time\n");
176 certStatus
= CERT_STATUS_PREMATURE
;
177 } else if (notvalidafterdatedata
&& (CFDateCompare( nowcfdatedata
, notvalidafterdatedata
, NULL
) == kCFCompareGreaterThan
)){
178 plog(LLV_ERROR
, LOCATION
, NULL
,
179 "current time after valid time\n");
180 certStatus
= CERT_STATUS_EXPIRED
;
182 plog(LLV_INFO
, LOCATION
, NULL
, "certificate expiration date OK\n");
183 certStatus
= CERT_STATUS_OK
;
188 if (notvalidbeforedatedata
)
189 CFRelease(notvalidbeforedatedata
);
190 if (notvalidafterdatedata
)
191 CFRelease(notvalidafterdatedata
);
193 CFRelease(certProparray
);
195 CFRelease(nowcfdatedata
);
201 * Verify cert using security framework
203 int crypto_cssm_check_x509cert (cert_t
*hostcert
, cert_t
*certchain
, CFStringRef hostname
, SecKeyRef
*publicKeyRef
)
206 cert_status_t certStatus
= 0;
208 CFIndex certArrayRefNumValues
= 0;
211 SecCertificateRef
*certArrayRef
= NULL
;
212 SecPolicyRef policyRef
= crypto_cssm_x509cert_get_SecPolicyRef(hostname
);
214 if (!hostcert
|| !certchain
) {
218 // find the total number of certs
219 for (p
= certchain
; p
; p
= p
->chain
, n
++);
221 plog(LLV_DEBUG2
, LOCATION
, NULL
,
222 "%s: checking chain of %d certificates.\n", __FUNCTION__
, n
);
225 certArraySiz
= n
* sizeof(CFTypeRef
);
226 certArrayRef
= CFAllocatorAllocate(NULL
, certArraySiz
, 0);
230 bzero(certArrayRef
, certArraySiz
);
231 if ((certArrayRef
[certArrayRefNumValues
] = crypto_cssm_x509cert_get_SecCertificateRef(&hostcert
->cert
))) {
232 /* don't overwrite any pending status */
233 if (!hostcert
->status
) {
234 hostcert
->status
= crypto_cssm_check_x509cert_dates(certArrayRef
[certArrayRefNumValues
]);
235 if (hostcert
->status
) {
236 plog(LLV_ERROR
, LOCATION
, NULL
,
237 "host certificate failed date verification: %d.\n", hostcert
->status
);
238 certStatus
= hostcert
->status
;
241 certArrayRefNumValues
++;
243 for (p
= certchain
; p
&& certArrayRefNumValues
< n
; p
= p
->chain
) {
245 if ((certArrayRef
[certArrayRefNumValues
] = crypto_cssm_x509cert_get_SecCertificateRef(&p
->cert
))) {
246 /* don't overwrite any pending status */
248 p
->status
= crypto_cssm_check_x509cert_dates(certArrayRef
[certArrayRefNumValues
]);
250 plog(LLV_ERROR
, LOCATION
, NULL
,
251 "other certificate in chain failed date verification: %d.\n", p
->status
);
253 certStatus
= p
->status
;
257 certArrayRefNumValues
++;
263 status
= EvaluateCert(certArrayRef
, certArrayRefNumValues
, policyRef
, publicKeyRef
);
265 while (certArrayRefNumValues
) {
266 CFRelease(certArrayRef
[--certArrayRefNumValues
]);
268 CFAllocatorDeallocate(NULL
, certArrayRef
);
271 CFRelease(policyRef
);
273 if (status
!= noErr
&& status
!= -1) {
274 plog(LLV_ERROR
, LOCATION
, NULL
,
275 "error %d %s.\n", status
, GetSecurityErrorString(status
));
277 } else if (certStatus
== CERT_STATUS_PREMATURE
|| certStatus
== CERT_STATUS_EXPIRED
) {
285 int crypto_cssm_verify_x509sign(SecKeyRef publicKeyRef
, vchar_t
*hash
, vchar_t
*signature
)
287 return SecKeyRawVerify(publicKeyRef
, kSecPaddingPKCS1
, hash
->v
, hash
->l
, signature
->v
, signature
->l
);
291 * Encrypt a hash via CSSM using the private key in the keychain
294 vchar_t
* crypto_cssm_getsign(CFDataRef persistentCertRef
, vchar_t
* hash
)
297 OSStatus status
= -1;
298 SecIdentityRef identityRef
= NULL
;
299 SecKeyRef privateKeyRef
= NULL
;
303 CFDictionaryRef persistFind
= NULL
;
304 const void *keys_persist
[] = { kSecReturnRef
, kSecValuePersistentRef
, kSecClass
};
305 const void *values_persist
[] = { kCFBooleanTrue
, persistentCertRef
, kSecClassIdentity
};
307 #define SIG_BUF_SIZE 1024
309 /* find identity by persistent ref */
310 persistFind
= CFDictionaryCreate(NULL
, keys_persist
, values_persist
,
311 (sizeof(keys_persist
) / sizeof(*keys_persist
)), NULL
, NULL
);
312 if (persistFind
== NULL
)
315 status
= SecItemCopyMatching(persistFind
, (CFTypeRef
*)&identityRef
);
319 status
= SecIdentityCopyPrivateKey(identityRef
, &privateKeyRef
);
323 // alloc buffer for result
324 sig
= vmalloc(SIG_BUF_SIZE
);
328 status
= SecKeyRawSign(privateKeyRef
, kSecPaddingPKCS1
, hash
->v
,
329 hash
->l
, sig
->v
, &sig
->l
);
334 CFRelease(identityRef
);
336 CFRelease(privateKeyRef
);
339 CFRelease(persistFind
);
341 if (status
!= noErr
) {
348 if (status
!= noErr
&& status
!= -1) {
349 plog(LLV_ERROR
, LOCATION
, NULL
,
350 "error %d %s.\n", status
, GetSecurityErrorString(status
));
359 * Retrieve a cert from the keychain
361 vchar_t
* crypto_cssm_get_x509cert(CFDataRef persistentCertRef
,
362 cert_status_t
*certStatus
)
365 OSStatus status
= -1;
366 vchar_t
*cert
= NULL
;
367 SecIdentityRef identityRef
= NULL
;
368 SecCertificateRef certificateRef
= NULL
;
370 #if !TARGET_OS_EMBEDDED
372 SecIdentitySearchRef idSearchRef
= NULL
;
373 SecKeychainRef keychainRef
= NULL
;
376 if (persistentCertRef
) {
377 status
= SecKeychainItemCopyFromPersistentReference(persistentCertRef
, (SecKeychainItemRef
*)&certificateRef
);
381 // copy system keychain
382 status
= CopySystemKeychain(&keychainRef
);
386 // find first identity in system keychain
387 status
= SecIdentitySearchCreate(keychainRef
, CSSM_KEYUSE_SIGN
, &idSearchRef
);
391 status
= SecIdentitySearchCopyNext(idSearchRef
, &identityRef
);
395 // get certificate from identity
396 status
= SecIdentityCopyCertificate(identityRef
, &certificateRef
);
402 // get certificate data
404 cssmData
.Data
= NULL
;
405 status
= SecCertificateGetData(certificateRef
, &cssmData
);
409 if (cssmData
.Length
== 0)
412 cert
= vmalloc(cssmData
.Length
);
416 // cssmData struct just points to the data
417 // data must be copied to be returned
418 memcpy(cert
->v
, cssmData
.Data
, cssmData
.Length
);
420 // verify expiry or missing fields
422 *certStatus
= CERT_STATUS_OK
;
426 CFDictionaryRef persistFind
= NULL
;
427 const void *keys_persist
[] = { kSecReturnRef
, kSecValuePersistentRef
};
428 const void *values_persist
[] = { kCFBooleanTrue
, persistentCertRef
};
430 CFDataRef certData
= NULL
;
432 /* find identity by persistent ref */
433 persistFind
= CFDictionaryCreate(NULL
, keys_persist
, values_persist
,
434 (sizeof(keys_persist
) / sizeof(*keys_persist
)), &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
435 if (persistFind
== NULL
)
438 status
= SecItemCopyMatching(persistFind
, (CFTypeRef
*)&identityRef
);
442 status
= SecIdentityCopyCertificate(identityRef
, &certificateRef
);
446 certData
= SecCertificateCopyData(certificateRef
);
447 if (certData
== NULL
)
450 dataLen
= CFDataGetLength(certData
);
454 cert
= vmalloc(dataLen
);
458 CFDataGetBytes(certData
, CFRangeMake(0, dataLen
), cert
->v
);
460 // verify expiry or missing fields
462 *certStatus
= crypto_cssm_check_x509cert_dates(certificateRef
);
469 CFRelease(certificateRef
);
471 CFRelease(identityRef
);
472 #if !TARGET_OS_EMBEDDED
474 CFRelease(idSearchRef
);
476 CFRelease(keychainRef
);
479 CFRelease(persistFind
);
484 if (status
!= noErr
&& status
!= -1) {
485 plog(LLV_ERROR
, LOCATION
, NULL
,
486 "error %d %s.\n", status
, GetSecurityErrorString(status
));
493 #if !TARGET_OS_EMBEDDED
495 * Find a policy ref by OID
497 static OSStatus
FindPolicy(const CSSM_OID
*policyOID
, SecPolicyRef
*policyRef
)
501 SecPolicySearchRef searchRef
= nil
;
503 status
= SecPolicySearchCreate(CSSM_CERT_X_509v3
, policyOID
, NULL
, &searchRef
);
507 status
= SecPolicySearchCopyNext(searchRef
, policyRef
);
511 CFRelease(searchRef
);
513 if (status
!= noErr
) {
514 plog(LLV_ERROR
, LOCATION
, NULL
,
515 "error %d %s.\n", status
, GetSecurityErrorString(status
));
523 * Evaluate the trust of a cert using the policy provided
525 static OSStatus
EvaluateCert(SecCertificateRef evalCertArray
[], CFIndex evalCertArrayNumValues
, CFTypeRef policyRef
, SecKeyRef
*publicKeyRef
)
528 SecTrustRef trustRef
= 0;
529 SecTrustResultType evalResult
;
531 CFArrayRef errorStrings
;
533 CFArrayRef cfCertRef
= CFArrayCreate((CFAllocatorRef
) NULL
, (void*)evalCertArray
, evalCertArrayNumValues
,
534 &kCFTypeArrayCallBacks
);
537 plog(LLV_ERROR
, LOCATION
, NULL
,
538 "unable to create CFArray.\n");
542 status
= SecTrustCreateWithCertificates(cfCertRef
, policyRef
, &trustRef
);
546 status
= SecTrustEvaluate(trustRef
, &evalResult
);
550 if (evalResult
!= kSecTrustResultProceed
&& evalResult
!= kSecTrustResultUnspecified
) {
551 plog(LLV_ERROR
, LOCATION
, NULL
, "Error evaluating certificate.\n");
553 switch (evalResult
) {
554 case kSecTrustResultInvalid
:
555 plog(LLV_DEBUG
, LOCATION
, NULL
, "eval result = kSecTrustResultInvalid.\n");
557 case kSecTrustResultProceed
:
558 plog(LLV_DEBUG
, LOCATION
, NULL
, "eval result = kSecTrustResultProceed.\n");
560 case kSecTrustResultDeny
:
561 plog(LLV_DEBUG
, LOCATION
, NULL
, "eval result = kSecTrustResultDeny.\n");
563 case kSecTrustResultUnspecified
:
564 plog(LLV_DEBUG
, LOCATION
, NULL
, "eval result = kSecTrustResultUnspecified.\n");
566 case kSecTrustResultRecoverableTrustFailure
:
567 plog(LLV_DEBUG
, LOCATION
, NULL
, "eval result = kSecTrustResultRecoverableTrustFailure.\n");
569 case kSecTrustResultFatalTrustFailure
:
570 plog(LLV_DEBUG
, LOCATION
, NULL
, "eval result = kSecTrustResultFatalTrustFailure.\n");
572 case kSecTrustResultOtherError
:
573 plog(LLV_DEBUG
, LOCATION
, NULL
, "eval result = kSecTrustResultOtherError.\n");
576 plog(LLV_DEBUG
, LOCATION
, NULL
, "eval result unknown: value = %d.\n", (int)evalResult
);
580 errorStrings
= SecTrustCopyProperties(trustRef
);
583 CFDictionaryRef dict
;
586 CFIndex count
, maxcount
= CFArrayGetCount(errorStrings
);
588 plog(LLV_ERROR
, LOCATION
, NULL
, "---------------Returned error strings: ---------------.\n");
589 for (count
= 0; count
< maxcount
; count
++) {
590 dict
= CFArrayGetValueAtIndex(errorStrings
, count
);
591 if (dict
&& (CFGetTypeID(dict
) == CFDictionaryGetTypeID())) {
592 val
= CFDictionaryGetValue(dict
, kSecPropertyKeyType
);
593 if (val
&& (CFGetTypeID(val
) == CFStringGetTypeID())) {
594 str
= CFStringGetCStringPtr(val
, kCFStringEncodingMacRoman
);
596 plog(LLV_ERROR
, LOCATION
, NULL
, "type = %s.\n", str
);
598 val
= CFDictionaryGetValue(dict
, kSecPropertyKeyValue
);
599 if (val
&& (CFGetTypeID(val
) == CFStringGetTypeID())) {
600 str
= CFStringGetCStringPtr(val
, kCFStringEncodingMacRoman
);
602 plog(LLV_ERROR
, LOCATION
, NULL
, "value = %s.\n", str
);
606 plog(LLV_ERROR
, LOCATION
, NULL
, "-----------------------------------------------------.\n");
607 CFRelease(errorStrings
);
614 /* get and return the public key */
615 *publicKeyRef
= SecTrustCopyPublicKey(trustRef
);
619 CFRelease(cfCertRef
);
623 if (status
!= noErr
&& status
!= -1) {
624 plog(LLV_ERROR
, LOCATION
, NULL
,
625 "error %d %s.\n", status
, GetSecurityErrorString(status
));
631 #if !TARGET_OS_EMBEDDED
633 * Copy the system keychain
635 static OSStatus
CopySystemKeychain(SecKeychainRef
*keychainRef
)
640 status
= SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem
);
644 status
= SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem
, keychainRef
);
648 if (status
!= noErr
) {
649 plog(LLV_ERROR
, LOCATION
, NULL
,
650 "error %d %s.\n", status
, GetSecurityErrorString(status
));
659 * Return string representation of Security-related OSStatus.
662 GetSecurityErrorString(OSStatus err
)
675 case errSecNotAvailable
:
676 return "errSecNotAvailable";
677 #if !TARGET_OS_EMBEDDED
679 return "errSecReadOnly";
680 case errSecAuthFailed
:
681 return "errSecAuthFailed";
682 case errSecNoSuchKeychain
:
683 return "errSecNoSuchKeychain";
684 case errSecInvalidKeychain
:
685 return "errSecInvalidKeychain";
686 case errSecDuplicateKeychain
:
687 return "errSecDuplicateKeychain";
688 case errSecDuplicateCallback
:
689 return "errSecDuplicateCallback";
690 case errSecInvalidCallback
:
691 return "errSecInvalidCallback";
692 case errSecBufferTooSmall
:
693 return "errSecBufferTooSmall";
694 case errSecDataTooLarge
:
695 return "errSecDataTooLarge";
696 case errSecNoSuchAttr
:
697 return "errSecNoSuchAttr";
698 case errSecInvalidItemRef
:
699 return "errSecInvalidItemRef";
700 case errSecInvalidSearchRef
:
701 return "errSecInvalidSearchRef";
702 case errSecNoSuchClass
:
703 return "errSecNoSuchClass";
704 case errSecNoDefaultKeychain
:
705 return "errSecNoDefaultKeychain";
706 case errSecInteractionNotAllowed
:
707 return "errSecInteractionNotAllowed";
708 case errSecReadOnlyAttr
:
709 return "errSecReadOnlyAttr";
710 case errSecWrongSecVersion
:
711 return "errSecWrongSecVersion";
712 case errSecKeySizeNotAllowed
:
713 return "errSecKeySizeNotAllowed";
714 case errSecNoStorageModule
:
715 return "errSecNoStorageModule";
716 case errSecNoCertificateModule
:
717 return "errSecNoCertificateModule";
718 case errSecNoPolicyModule
:
719 return "errSecNoPolicyModule";
720 case errSecInteractionRequired
:
721 return "errSecInteractionRequired";
722 case errSecDataNotAvailable
:
723 return "errSecDataNotAvailable";
724 case errSecDataNotModifiable
:
725 return "errSecDataNotModifiable";
726 case errSecCreateChainFailed
:
727 return "errSecCreateChainFailed";
728 case errSecACLNotSimple
:
729 return "errSecACLNotSimple";
730 case errSecPolicyNotFound
:
731 return "errSecPolicyNotFound";
732 case errSecInvalidTrustSetting
:
733 return "errSecInvalidTrustSetting";
734 case errSecNoAccessForItem
:
735 return "errSecNoAccessForItem";
736 case errSecInvalidOwnerEdit
:
737 return "errSecInvalidOwnerEdit";
739 case errSecDuplicateItem
:
740 return "errSecDuplicateItem";
741 case errSecItemNotFound
:
742 return "errSecItemNotFound";