]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/crypto_cssm.c
ipsec-317.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / crypto_cssm.c
1
2 /*
3 * Copyright (c) 2001-2004 Apple Computer, Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
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.
12 *
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
19 * under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 /*
26 * Racoon module for verifying and signing certificates through Security
27 * Framework and CSSM
28 */
29
30 #include "config.h"
31
32 #include <Security/SecCertificate.h>
33 #include <Security/SecPolicy.h>
34 #include <Security/SecTrust.h>
35 #include <Security/SecKeyPriv.h>
36 #include <Security/SecIdentity.h>
37 #include <Security/SecItem.h>
38 #include <TargetConditionals.h>
39 #include <Security/SecItemPriv.h>
40 #ifndef HAVE_OPENSSL
41 #include <Security/SecTrustPriv.h>
42 #include <Security/SecPolicyPriv.h>
43 #include <Security/SecCertificatePriv.h>
44 #else
45 #include <Security/SecBase.h>
46 #include <Security/SecIdentityPriv.h>
47 #include <Security/SecCertificateOIDs.h>
48 #include <Security/SecKeyPriv.h>
49 #include <Security/oidsalg.h>
50 #include <Security/cssmapi.h>
51 #include <Security/SecPolicySearch.h>
52 #endif
53 #include <CoreFoundation/CoreFoundation.h>
54 #if !TARGET_OS_EMBEDDED
55 #include <Security/SecIdentitySearch.h>
56 #include <Security/SecKeychain.h>
57 #include <Security/SecKeychainItem.h>
58 #include <Security/SecKeychainItemPriv.h>
59 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
60 #endif
61 #include "plog.h"
62 #include "debug.h"
63 #include "misc.h"
64 #include "oakley.h"
65 #include "gcmalloc.h"
66
67
68 #include "crypto_cssm.h"
69
70
71 static OSStatus EvaluateCert(SecCertificateRef evalCertArray[], CFIndex evalCertArrayNumValues, CFTypeRef policyRef, SecKeyRef *publicKeyRef);
72
73
74
75 static SecPolicyRef
76 crypto_cssm_x509cert_get_SecPolicyRef (CFStringRef hostname)
77 {
78 SecPolicyRef policyRef = NULL;
79 CFDictionaryRef properties = NULL;
80 const void *key[] = { kSecPolicyName };
81 const void *value[] = { hostname };
82
83 if (hostname) {
84 properties = CFDictionaryCreate(NULL, key, value, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
85 if (properties == NULL) {
86 plog(ASL_LEVEL_ERR,
87 "unable to create dictionary for policy properties.\n");
88 }
89 }
90 policyRef = SecPolicyCreateWithProperties(kSecPolicyAppleIPsec, properties);
91 if (properties)
92 CFRelease(properties);
93 return policyRef;
94 }
95
96 SecCertificateRef
97 crypto_cssm_x509cert_CreateSecCertificateRef (vchar_t *cert)
98 {
99 SecCertificateRef certRef = NULL;
100
101 CFDataRef cert_data = CFDataCreateWithBytesNoCopy(NULL, (uint8_t*)cert->v, cert->l, kCFAllocatorNull);
102 if (cert_data) {
103 certRef = SecCertificateCreateWithData(NULL, cert_data);
104 CFRelease(cert_data);
105 }
106
107 if (certRef == NULL) {
108 plog(ASL_LEVEL_ERR,
109 "unable to get a certifcate reference.\n");
110 }
111 return certRef;
112 }
113
114 /* HACK!!! - temporary until this prototype gets moved */
115 extern CFDataRef SecCertificateCopySubjectSequence( SecCertificateRef certificate);
116
117 CFDataRef
118 crypto_cssm_CopySubjectSequence(SecCertificateRef certRef)
119 {
120 CFDataRef subject = NULL;
121
122 subject = SecCertificateCopySubjectSequence(certRef);
123 return subject;
124
125 }
126
127
128 cert_status_t
129 crypto_cssm_check_x509cert_dates (SecCertificateRef certificateRef)
130 {
131 cert_status_t certStatus = CERT_STATUS_OK;
132 #ifndef HAVE_OPENSSL
133 CFAbsoluteTime timeNow = 0;
134 CFAbsoluteTime notvalidbeforedate = 0;
135 CFAbsoluteTime notvalidafterdate = 0;
136 CFDateRef nowcfdatedata = NULL;
137 CFDateRef notvalidbeforedatedata = NULL;
138 CFDateRef notvalidafterdatedata = NULL;
139 CFArrayRef certProparray = NULL;
140
141 if ((timeNow = CFAbsoluteTimeGetCurrent())) {
142 if (SecCertificateIsValid(certificateRef, timeNow)) {
143 plog(ASL_LEVEL_NOTICE, "Certificate expiration date is OK\n");
144 certStatus = CERT_STATUS_OK;
145 } else {
146 nowcfdatedata = CFDateCreate( NULL, timeNow);
147
148 if ((notvalidbeforedate = SecCertificateNotValidBefore(certificateRef))) {
149 notvalidbeforedatedata = CFDateCreate(NULL, notvalidbeforedate);
150 }
151
152 if ((notvalidafterdate = SecCertificateNotValidAfter(certificateRef))) {
153 notvalidafterdatedata = CFDateCreate(NULL, notvalidafterdate);
154 }
155
156 int year = 0;
157 int month = 0;
158 int day = 0;
159 int hour = 0;
160 int minute = 0;
161 CFCalendarRef calendar = CFCalendarCreateWithIdentifier(kCFAllocatorDefault, kCFGregorianCalendar);
162 if (calendar)
163 {
164 if (notvalidbeforedate) {
165 CFCalendarDecomposeAbsoluteTime(calendar, notvalidbeforedate, "yMdHm", &year, &month, &day, &hour, &minute);
166 plog(ASL_LEVEL_DEBUG, "Certificate not valid before yr %d, mon %d, days %d, hours %d, min %d\n", year, month, day, hour, minute);
167 }
168
169 if (notvalidafterdate) {
170 CFCalendarDecomposeAbsoluteTime(calendar, notvalidafterdate, "yMdHm", &year, &month, &day, &hour, &minute);
171 plog(ASL_LEVEL_DEBUG, "Certificate not valid after yr %d, mon %d, days %d, hours %d, min %d\n", year, month, day, hour, minute);
172 }
173 CFRelease(calendar);
174 }
175
176 if (nowcfdatedata != NULL) {
177 if (notvalidbeforedatedata && CFDateCompare(nowcfdatedata, notvalidbeforedatedata, NULL) == kCFCompareLessThan){
178 plog(ASL_LEVEL_ERR,
179 "current time before valid time\n");
180 certStatus = CERT_STATUS_PREMATURE;
181 } else if (notvalidafterdatedata && (CFDateCompare( nowcfdatedata, notvalidafterdatedata, NULL ) == kCFCompareGreaterThan)){
182 plog(ASL_LEVEL_ERR,
183 "current time after valid time\n");
184 certStatus = CERT_STATUS_EXPIRED;
185 }
186 }
187 }
188 } else {
189 plog(ASL_LEVEL_ERR, "CFAbsoluteTimeGetCurrent() failed");
190 certStatus = CERT_STATUS_INVALID;
191 }
192
193 if (notvalidbeforedatedata)
194 CFRelease(notvalidbeforedatedata);
195 if (notvalidafterdatedata)
196 CFRelease(notvalidafterdatedata);
197 if (certProparray)
198 CFRelease(certProparray);
199 if (nowcfdatedata)
200 CFRelease(nowcfdatedata);
201 #endif
202 return certStatus;
203 }
204
205 /*
206 * Verify cert using security framework
207 */
208 int crypto_cssm_check_x509cert (cert_t *hostcert, cert_t *certchain, CFStringRef hostname, SecKeyRef *publicKeyRef)
209 {
210 cert_t *p;
211 cert_status_t certStatus = 0;
212 OSStatus status;
213 CFIndex certArrayRefNumValues = 0;
214 CFIndex n = 0;
215 int certArraySiz;
216 SecCertificateRef *certArrayRef = NULL;
217 SecPolicyRef policyRef = crypto_cssm_x509cert_get_SecPolicyRef(hostname);
218
219 if (!hostcert || !certchain) {
220 return -1;
221 }
222
223 // find the total number of certs
224 for (p = certchain; p; p = p->chain, n++);
225 if (n> 1) {
226 plog(ASL_LEVEL_DEBUG,
227 "%s: checking chain of %d certificates.\n", __FUNCTION__, (int)n);
228 }
229
230 certArraySiz = n * sizeof(CFTypeRef);
231 certArrayRef = CFAllocatorAllocate(NULL, certArraySiz, 0);
232 if (!certArrayRef) {
233 return -1;
234 }
235 bzero(certArrayRef, certArraySiz);
236 if ((certArrayRef[certArrayRefNumValues] = crypto_cssm_x509cert_CreateSecCertificateRef(&hostcert->cert))) {
237 /* don't overwrite any pending status */
238 if (!hostcert->status) {
239 hostcert->status = crypto_cssm_check_x509cert_dates(certArrayRef[certArrayRefNumValues]);
240 if (hostcert->status) {
241 plog(ASL_LEVEL_ERR,
242 "host certificate failed date verification: %d.\n", hostcert->status);
243 certStatus = hostcert->status;
244 }
245 }
246 certArrayRefNumValues++;
247 }
248 for (p = certchain; p && certArrayRefNumValues < n; p = p->chain) {
249 if (p != hostcert) {
250 if ((certArrayRef[certArrayRefNumValues] = crypto_cssm_x509cert_CreateSecCertificateRef(&p->cert))) {
251 /* don't overwrite any pending status */
252 if (!p->status) {
253 p->status = crypto_cssm_check_x509cert_dates(certArrayRef[certArrayRefNumValues]);
254 if (p->status) {
255 plog(ASL_LEVEL_ERR,
256 "other certificate in chain failed date verification: %d.\n", p->status);
257 if (!certStatus) {
258 certStatus = p->status;
259 }
260 }
261 }
262 certArrayRefNumValues++;
263 }
264 }
265 }
266
267 // evaluate cert
268 status = EvaluateCert(certArrayRef, certArrayRefNumValues, policyRef, publicKeyRef);
269
270 while (certArrayRefNumValues) {
271 CFRelease(certArrayRef[--certArrayRefNumValues]);
272 }
273 CFAllocatorDeallocate(NULL, certArrayRef);
274
275 if (policyRef)
276 CFRelease(policyRef);
277
278 if (status != noErr && status != -1) {
279 plog(ASL_LEVEL_ERR,
280 "check_x509cert error %d %s.\n", (int)status, GetSecurityErrorString(status));
281 status = -1;
282 } else if (certStatus == CERT_STATUS_PREMATURE || certStatus == CERT_STATUS_EXPIRED) {
283 status = -1;
284 }
285 return status;
286
287 }
288
289
290 int crypto_cssm_verify_x509sign(SecKeyRef publicKeyRef, vchar_t *hash, vchar_t *signature, Boolean useSHA1)
291 {
292 return SecKeyRawVerify(publicKeyRef, useSHA1 ? kSecPaddingPKCS1SHA1 : kSecPaddingPKCS1, (uint8_t*)hash->v, hash->l, (uint8_t*)signature->v, signature->l);
293 }
294
295 /*
296 * Encrypt a hash via CSSM using the private key in the keychain
297 * from an identity.
298 */
299 vchar_t* crypto_cssm_getsign(CFDataRef persistentCertRef, vchar_t* hash)
300 {
301
302 OSStatus status = -1;
303 SecIdentityRef identityRef = NULL;
304 SecKeyRef privateKeyRef = NULL;
305 vchar_t *sig = NULL;
306
307
308 CFDictionaryRef persistFind = NULL;
309 const void *keys_persist[] = { kSecReturnRef, kSecValuePersistentRef, kSecClass,
310 #if TARGET_OS_EMBEDDED || TARGET_OS_IPHONE
311 kSecUseSystemKeychain,
312 #endif
313 };
314 const void *values_persist[] = { kCFBooleanTrue, persistentCertRef, kSecClassIdentity,
315 #if TARGET_OS_EMBEDDED || TARGET_OS_IPHONE
316 kCFBooleanTrue,
317 #endif
318 };
319
320 #define SIG_BUF_SIZE 1024
321
322 /* find identity by persistent ref */
323 persistFind = CFDictionaryCreate(NULL, keys_persist, values_persist,
324 (sizeof(keys_persist) / sizeof(*keys_persist)), NULL, NULL);
325 if (persistFind == NULL)
326 goto end;
327
328 status = SecItemCopyMatching(persistFind, (CFTypeRef *)&identityRef);
329 if (status != noErr)
330 goto end;
331
332 status = SecIdentityCopyPrivateKey(identityRef, &privateKeyRef);
333 if (status != noErr)
334 goto end;
335
336 // alloc buffer for result
337 sig = vmalloc(SIG_BUF_SIZE);
338 if (sig == NULL)
339 goto end;
340
341 status = SecKeyRawSign(privateKeyRef, kSecPaddingPKCS1, (uint8_t*)hash->v,
342 hash->l, (uint8_t*)sig->v, &sig->l);
343
344
345 end:
346 if (identityRef)
347 CFRelease(identityRef);
348 if (privateKeyRef)
349 CFRelease(privateKeyRef);
350
351 if (persistFind)
352 CFRelease(persistFind);
353
354 if (status != noErr) {
355 if (sig) {
356 vfree(sig);
357 sig = NULL;
358 }
359 }
360
361 if (status != noErr && status != -1) {
362 plog(ASL_LEVEL_ERR,
363 "getsign error %d %s.\n", (int)status, GetSecurityErrorString(status));
364 status = -1;
365 }
366 return sig;
367
368 }
369
370
371 /*
372 * Retrieve a cert from the keychain
373 */
374 vchar_t* crypto_cssm_get_x509cert(CFDataRef persistentCertRef,
375 cert_status_t *certStatus)
376 {
377
378 OSStatus status = -1;
379 vchar_t *cert = NULL;
380 SecCertificateRef certificateRef = NULL;
381 CFDictionaryRef persistFind = NULL;
382 size_t dataLen;
383 CFDataRef certData = NULL;
384 SecIdentityRef identityRef = NULL;
385 const void *keys_persist[] = { kSecReturnRef, kSecValuePersistentRef, kSecClass,
386 #if TARGET_OS_EMBEDDED || TARGET_OS_IPHONE
387 kSecUseSystemKeychain,
388 #endif
389 };
390 const void *values_persist[] = { kCFBooleanTrue, persistentCertRef, kSecClassIdentity,
391 #if TARGET_OS_EMBEDDED || TARGET_OS_IPHONE
392 kCFBooleanTrue,
393 #endif
394 };
395
396 /* find identity by persistent ref */
397 persistFind = CFDictionaryCreate(NULL, keys_persist, values_persist,
398 (sizeof(keys_persist) / sizeof(*keys_persist)), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
399 if (persistFind == NULL)
400 goto end;
401
402 status = SecItemCopyMatching(persistFind, (CFTypeRef *)&identityRef);
403 if (status != noErr)
404 goto end;
405
406 status = SecIdentityCopyCertificate(identityRef, &certificateRef);
407 if (status != noErr)
408 goto end;
409
410 certData = SecCertificateCopyData(certificateRef);
411 if (certData == NULL)
412 goto end;
413
414 dataLen = CFDataGetLength(certData);
415 if (dataLen == 0)
416 goto end;
417
418 cert = vmalloc(dataLen);
419 if (cert == NULL)
420 goto end;
421
422 CFDataGetBytes(certData, CFRangeMake(0, dataLen), (uint8_t*)cert->v);
423
424 // verify expiry or missing fields
425 if (certStatus) {
426 *certStatus = crypto_cssm_check_x509cert_dates(certificateRef);
427 }
428
429 end:
430 if (identityRef)
431 CFRelease(identityRef);
432 if (certificateRef)
433 CFRelease(certificateRef);
434 if (persistFind)
435 CFRelease(persistFind);
436 if (certData)
437 CFRelease(certData);
438
439 if (status != noErr && status != -1) {
440 plog(ASL_LEVEL_ERR,
441 "get_x509cert error %d %s.\n", (int)status, GetSecurityErrorString(status));
442 status = -1;
443 }
444 return cert;
445
446 }
447
448 /*
449 * Evaluate the trust of a cert using the policy provided
450 */
451 static OSStatus EvaluateCert(SecCertificateRef evalCertArray[], CFIndex evalCertArrayNumValues, CFTypeRef policyRef, SecKeyRef *publicKeyRef)
452 {
453 OSStatus status;
454 SecTrustRef trustRef = 0;
455 SecTrustResultType evalResult;
456
457 CFArrayRef errorStrings;
458
459 CFArrayRef cfCertRef = CFArrayCreate((CFAllocatorRef) NULL, (void*)evalCertArray, evalCertArrayNumValues,
460 &kCFTypeArrayCallBacks);
461
462 if (!cfCertRef) {
463 plog(ASL_LEVEL_ERR,
464 "unable to create CFArray.\n");
465 return -1;
466 }
467
468 status = SecTrustCreateWithCertificates(cfCertRef, policyRef, &trustRef);
469 if (status != noErr)
470 goto end;
471
472 status = SecTrustEvaluate(trustRef, &evalResult);
473 if (status != noErr)
474 goto end;
475
476 if (evalResult != kSecTrustResultProceed && evalResult != kSecTrustResultUnspecified) {
477 plog(ASL_LEVEL_ERR, "Error evaluating certificate.\n");
478
479 switch (evalResult) {
480 case kSecTrustResultInvalid:
481 plog(ASL_LEVEL_DEBUG, "eval result = kSecTrustResultInvalid.\n");
482 break;
483 case kSecTrustResultProceed:
484 plog(ASL_LEVEL_DEBUG, "eval result = kSecTrustResultProceed.\n");
485 break;
486 case kSecTrustResultDeny:
487 plog(ASL_LEVEL_DEBUG, "eval result = kSecTrustResultDeny.\n");
488 break;
489 case kSecTrustResultUnspecified:
490 plog(ASL_LEVEL_DEBUG, "eval result = kSecTrustResultUnspecified.\n");
491 break;
492 case kSecTrustResultRecoverableTrustFailure:
493 plog(ASL_LEVEL_DEBUG, "eval result = kSecTrustResultRecoverableTrustFailure.\n");
494 break;
495 case kSecTrustResultFatalTrustFailure:
496 plog(ASL_LEVEL_DEBUG, "eval result = kSecTrustResultFatalTrustFailure.\n");
497 break;
498 case kSecTrustResultOtherError:
499 plog(ASL_LEVEL_DEBUG, "eval result = kSecTrustResultOtherError.\n");
500 break;
501 default:
502 plog(ASL_LEVEL_DEBUG, "eval result unknown: value = %d.\n", (int)evalResult);
503 break;
504 }
505
506 errorStrings = SecTrustCopyProperties(trustRef);
507 if (errorStrings) {
508
509 CFDictionaryRef dict;
510 CFStringRef val;
511 const char *str;
512 CFIndex count, maxcount = CFArrayGetCount(errorStrings);
513
514 plog(ASL_LEVEL_ERR, "---------------Returned error strings: ---------------.\n");
515 for (count = 0; count < maxcount; count++) {
516 dict = CFArrayGetValueAtIndex(errorStrings, count);
517 if (dict && (CFGetTypeID(dict) == CFDictionaryGetTypeID())) {
518 val = CFDictionaryGetValue(dict, kSecPropertyKeyType);
519 if (val && (CFGetTypeID(val) == CFStringGetTypeID())) {
520 str = CFStringGetCStringPtr(val, kCFStringEncodingMacRoman);
521 if (str)
522 plog(ASL_LEVEL_ERR, "type = %s.\n", str);
523 }
524 val = CFDictionaryGetValue(dict, kSecPropertyKeyValue);
525 if (val && (CFGetTypeID(val) == CFStringGetTypeID())) {
526 str = CFStringGetCStringPtr(val, kCFStringEncodingMacRoman);
527 if (str)
528 plog(ASL_LEVEL_ERR, "value = %s.\n", str);
529 }
530 }
531 }
532 plog(ASL_LEVEL_ERR, "-----------------------------------------------------.\n");
533 CFRelease(errorStrings);
534 }
535
536 status = -1;
537 goto end;
538 }
539
540 /* get and return the public key */
541 *publicKeyRef = SecTrustCopyPublicKey(trustRef);
542
543 end:
544 if (cfCertRef)
545 CFRelease(cfCertRef);
546 if (trustRef)
547 CFRelease(trustRef);
548
549 if (status != noErr && status != -1) {
550 plog(ASL_LEVEL_ERR,
551 "EvaluateCert error %d %s.\n", (int)status, GetSecurityErrorString(status));
552 status = -1;
553 }
554 return status;
555 }
556
557 /*
558 * Return string representation of Security-related OSStatus.
559 */
560 const char *
561 GetSecurityErrorString(OSStatus err)
562 {
563 switch(err) {
564 case noErr:
565 return "noErr";
566
567 /* SecBase.h: */
568 case errSecNotAvailable:
569 return "errSecNotAvailable";
570
571 #if !TARGET_OS_EMBEDDED
572 case memFullErr:
573 return "memFullErr";
574 case paramErr:
575 return "paramErr";
576 case unimpErr:
577 return "unimpErr";
578 #endif
579
580 #ifndef HAVE_OPENSSL
581 /* SecBase.h: */
582 case errSecReadOnly:
583 return "errSecReadOnly";
584 case errSecAuthFailed:
585 return "errSecAuthFailed";
586 case errSecNoSuchKeychain:
587 return "errSecNoSuchKeychain";
588 case errSecInvalidKeychain:
589 return "errSecInvalidKeychain";
590 case errSecDuplicateKeychain:
591 return "errSecDuplicateKeychain";
592 case errSecDuplicateCallback:
593 return "errSecDuplicateCallback";
594 case errSecInvalidCallback:
595 return "errSecInvalidCallback";
596 case errSecBufferTooSmall:
597 return "errSecBufferTooSmall";
598 case errSecDataTooLarge:
599 return "errSecDataTooLarge";
600 case errSecNoSuchAttr:
601 return "errSecNoSuchAttr";
602 case errSecInvalidItemRef:
603 return "errSecInvalidItemRef";
604 case errSecInvalidSearchRef:
605 return "errSecInvalidSearchRef";
606 case errSecNoSuchClass:
607 return "errSecNoSuchClass";
608 case errSecNoDefaultKeychain:
609 return "errSecNoDefaultKeychain";
610 case errSecInteractionNotAllowed:
611 return "errSecInteractionNotAllowed";
612 case errSecReadOnlyAttr:
613 return "errSecReadOnlyAttr";
614 case errSecWrongSecVersion:
615 return "errSecWrongSecVersion";
616 case errSecKeySizeNotAllowed:
617 return "errSecKeySizeNotAllowed";
618 case errSecNoStorageModule:
619 return "errSecNoStorageModule";
620 case errSecNoCertificateModule:
621 return "errSecNoCertificateModule";
622 case errSecNoPolicyModule:
623 return "errSecNoPolicyModule";
624 case errSecInteractionRequired:
625 return "errSecInteractionRequired";
626 case errSecDataNotAvailable:
627 return "errSecDataNotAvailable";
628 case errSecDataNotModifiable:
629 return "errSecDataNotModifiable";
630 case errSecCreateChainFailed:
631 return "errSecCreateChainFailed";
632 case errSecACLNotSimple:
633 return "errSecACLNotSimple";
634 case errSecPolicyNotFound:
635 return "errSecPolicyNotFound";
636 case errSecInvalidTrustSetting:
637 return "errSecInvalidTrustSetting";
638 case errSecNoAccessForItem:
639 return "errSecNoAccessForItem";
640 case errSecInvalidOwnerEdit:
641 return "errSecInvalidOwnerEdit";
642 #endif
643 case errSecDuplicateItem:
644 return "errSecDuplicateItem";
645 case errSecItemNotFound:
646 return "errSecItemNotFound";
647 default:
648 return "<unknown>";
649 }
650 }
651