2 * Copyright (c) 2003-2010,2012-2019 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 "keychain_find.h"
28 #include "keychain_utilities.h"
29 #include "readline_cssm.h"
30 #include "security_tool.h"
36 #include <libkern/OSByteOrder.h>
37 #include <Security/SecACL.h>
38 #include <Security/SecItem.h>
39 #include <Security/SecItemPriv.h>
40 #include <Security/SecKeychainItem.h>
41 #include <Security/SecKeychainItemPriv.h>
42 #include <Security/SecKeychainSearch.h>
43 #include <Security/SecCertificate.h>
44 #include <CommonCrypto/CommonDigest.h>
45 #include <CoreFoundation/CFString.h>
47 #include <utilities/SecCFRelease.h>
49 // SecDigestGetData, SecKeychainSearchCreateForCertificateByEmail, SecCertificateFindByEmail
50 #include <Security/SecCertificatePriv.h>
52 Boolean gDeleteIt
= 0;
54 // find_first_generic_password
56 // Returns a SecKeychainItemRef for the first item
57 // which matches the specified attributes. Caller is
58 // responsible for releasing the item (with CFRelease).
61 find_first_generic_password(CFTypeRef keychainOrArray
,
62 FourCharCode itemCreator
,
63 FourCharCode itemType
,
68 const char *serviceName
,
69 const char *accountName
)
71 OSStatus status
= noErr
;
72 SecKeychainSearchRef searchRef
= NULL
;
73 SecKeychainItemRef itemRef
= NULL
;
75 SecKeychainAttribute attrs
[8]; // maximum number of searchable attributes
76 SecKeychainAttributeList attrList
= { 0, attrs
};
78 // the primary key for a generic password item (i.e. the combination of
79 // attributes which determine whether the item is unique) consists of:
80 // { kSecAccountItemAttr, kSecServiceItemAttr }
82 // if we have a primary key, we don't need to search on other attributes
83 // (and we don't want to, if non-primary attributes are being updated)
84 Boolean primaryKey
= (accountName
&& serviceName
);
86 // build the attribute list for searching
87 if ((UInt32
)itemCreator
!= 0 && !primaryKey
) {
88 attrs
[attrList
.count
].tag
= kSecCreatorItemAttr
;
89 attrs
[attrList
.count
].length
= sizeof(FourCharCode
);
90 attrs
[attrList
.count
].data
= (FourCharCode
*)&itemCreator
;
93 if ((UInt32
)itemType
!= 0 && !primaryKey
) {
94 attrs
[attrList
.count
].tag
= kSecTypeItemAttr
;
95 attrs
[attrList
.count
].length
= sizeof(FourCharCode
);
96 attrs
[attrList
.count
].data
= (FourCharCode
*)&itemType
;
99 if (kind
!= NULL
&& !primaryKey
) {
100 attrs
[attrList
.count
].tag
= kSecDescriptionItemAttr
;
101 attrs
[attrList
.count
].length
= (UInt32
) strlen(kind
);
102 attrs
[attrList
.count
].data
= (void*)kind
;
105 if (value
!= NULL
&& !primaryKey
) {
106 attrs
[attrList
.count
].tag
= kSecGenericItemAttr
;
107 attrs
[attrList
.count
].length
= (UInt32
) strlen(value
);
108 attrs
[attrList
.count
].data
= (void*)value
;
111 if (comment
!= NULL
&& !primaryKey
) {
112 attrs
[attrList
.count
].tag
= kSecCommentItemAttr
;
113 attrs
[attrList
.count
].length
= (UInt32
) strlen(comment
);
114 attrs
[attrList
.count
].data
= (void*)comment
;
117 if (label
!= NULL
&& !primaryKey
) {
118 attrs
[attrList
.count
].tag
= kSecLabelItemAttr
;
119 attrs
[attrList
.count
].length
= (UInt32
) strlen(label
);
120 attrs
[attrList
.count
].data
= (void*)label
;
123 if (serviceName
!= NULL
) {
124 attrs
[attrList
.count
].tag
= kSecServiceItemAttr
;
125 attrs
[attrList
.count
].length
= (UInt32
) strlen(serviceName
);
126 attrs
[attrList
.count
].data
= (void*)serviceName
;
129 if (accountName
!= NULL
) {
130 attrs
[attrList
.count
].tag
= kSecAccountItemAttr
;
131 attrs
[attrList
.count
].length
= (UInt32
) strlen(accountName
);
132 attrs
[attrList
.count
].data
= (void*)accountName
;
136 status
= SecKeychainSearchCreateFromAttributes(keychainOrArray
, kSecGenericPasswordItemClass
, &attrList
, &searchRef
);
138 sec_perror("SecKeychainSearchCreateFromAttributes", status
);
141 // we're only interested in the first match, if there is a match at all
142 status
= SecKeychainSearchCopyNext(searchRef
, &itemRef
);
149 CFRelease(searchRef
);
154 // find_first_internet_password
156 // Returns a SecKeychainItemRef for the first item
157 // which matches the specified attributes. Caller is
158 // responsible for releasing the item (with CFRelease).
161 find_first_internet_password(CFTypeRef keychainOrArray
,
162 FourCharCode itemCreator
,
163 FourCharCode itemType
,
167 const char *serverName
,
168 const char *securityDomain
,
169 const char *accountName
,
172 SecProtocolType protocol
,
173 SecAuthenticationType authenticationType
)
175 OSStatus status
= noErr
;
176 SecKeychainSearchRef searchRef
= NULL
;
177 SecKeychainItemRef itemRef
= NULL
;
179 SecKeychainAttribute attrs
[12]; // maximum number of searchable attributes
180 SecKeychainAttributeList attrList
= { 0, attrs
};
182 // the primary key for an internet password item (i.e. the combination of
183 // attributes which determine whether the item is unique) consists of:
184 // { kSecAccountItemAttr, kSecSecurityDomainItemAttr, kSecServerItemAttr,
185 // kSecProtocolItemAttr, kSecAuthenticationTypeItemAttr,
186 // kSecPortItemAttr, kSecPathItemAttr }
188 // if we have a primary key, we don't need to search on other attributes.
189 // (and we don't want to, if non-primary attributes are being updated)
190 Boolean primaryKey
= (accountName
&& securityDomain
&& serverName
&&
191 protocol
&& authenticationType
&& port
&& path
);
193 // build the attribute list for searching
194 if ((UInt32
)itemCreator
!= 0 && !primaryKey
) {
195 attrs
[attrList
.count
].tag
= kSecCreatorItemAttr
;
196 attrs
[attrList
.count
].length
= sizeof(FourCharCode
);
197 attrs
[attrList
.count
].data
= (FourCharCode
*)&itemCreator
;
200 if ((UInt32
)itemType
!= 0 && !primaryKey
) {
201 attrs
[attrList
.count
].tag
= kSecTypeItemAttr
;
202 attrs
[attrList
.count
].length
= sizeof(FourCharCode
);
203 attrs
[attrList
.count
].data
= (FourCharCode
*)&itemType
;
206 if (kind
!= NULL
&& !primaryKey
) {
207 attrs
[attrList
.count
].tag
= kSecDescriptionItemAttr
;
208 attrs
[attrList
.count
].length
= (UInt32
) strlen(kind
);
209 attrs
[attrList
.count
].data
= (void*)kind
;
212 if (comment
!= NULL
&& !primaryKey
) {
213 attrs
[attrList
.count
].tag
= kSecCommentItemAttr
;
214 attrs
[attrList
.count
].length
= (UInt32
) strlen(comment
);
215 attrs
[attrList
.count
].data
= (void*)comment
;
218 if (label
!= NULL
&& !primaryKey
) {
219 attrs
[attrList
.count
].tag
= kSecLabelItemAttr
;
220 attrs
[attrList
.count
].length
= (UInt32
) strlen(label
);
221 attrs
[attrList
.count
].data
= (void*)label
;
224 if (serverName
!= NULL
) {
225 attrs
[attrList
.count
].tag
= kSecServerItemAttr
;
226 attrs
[attrList
.count
].length
= (UInt32
) strlen(serverName
);
227 attrs
[attrList
.count
].data
= (void*)serverName
;
230 if (securityDomain
!= NULL
) {
231 attrs
[attrList
.count
].tag
= kSecSecurityDomainItemAttr
;
232 attrs
[attrList
.count
].length
= (UInt32
) strlen(securityDomain
);
233 attrs
[attrList
.count
].data
= (void *)securityDomain
;
236 if (accountName
!= NULL
) {
237 attrs
[attrList
.count
].tag
= kSecAccountItemAttr
;
238 attrs
[attrList
.count
].length
= (UInt32
) strlen(accountName
);
239 attrs
[attrList
.count
].data
= (void *)accountName
;
243 attrs
[attrList
.count
].tag
= kSecPathItemAttr
;
244 attrs
[attrList
.count
].length
= (UInt32
) strlen(path
);
245 attrs
[attrList
.count
].data
= (void *)path
;
249 attrs
[attrList
.count
].tag
= kSecPortItemAttr
;
250 attrs
[attrList
.count
].length
= sizeof(UInt16
);
251 attrs
[attrList
.count
].data
= (UInt16
*)&port
;
254 if ((UInt32
)protocol
!= 0) {
255 attrs
[attrList
.count
].tag
= kSecProtocolItemAttr
;
256 attrs
[attrList
.count
].length
= sizeof(SecProtocolType
);
257 attrs
[attrList
.count
].data
= (SecProtocolType
*)&protocol
;
260 if ((UInt32
)authenticationType
!= 0) {
261 attrs
[attrList
.count
].tag
= kSecAuthenticationTypeItemAttr
;
262 attrs
[attrList
.count
].length
= sizeof(SecAuthenticationType
);
263 attrs
[attrList
.count
].data
= (SecAuthenticationType
*)&authenticationType
;
267 status
= SecKeychainSearchCreateFromAttributes(keychainOrArray
, kSecInternetPasswordItemClass
, &attrList
, &searchRef
);
269 sec_perror("SecKeychainSearchCreateFromAttributes", status
);
272 // we're only interested in the first match, if there is a match at all
273 status
= SecKeychainSearchCopyNext(searchRef
, &itemRef
);
280 CFRelease(searchRef
);
285 // find_unique_certificate
287 // Returns a SecKeychainItemRef for the certificate
288 // in the specified keychain (or keychain list)
289 // which is a unique match for either the specified name
290 // or SHA-1/SHA-2 hash. If more than one match exists, the
291 // certificate is not unique and none are returned. Caller is
292 // responsible for releasing the item (with CFRelease).
295 find_unique_certificate(CFTypeRef keychainOrArray
,
299 OSStatus status
= noErr
;
300 SecKeychainSearchRef searchRef
= NULL
;
301 SecKeychainItemRef uniqueItemRef
= NULL
;
303 status
= SecKeychainSearchCreateFromAttributes(keychainOrArray
, kSecCertificateItemClass
, NULL
, &searchRef
);
305 return uniqueItemRef
;
308 // check input hash string and convert to data
309 CFDataRef hashData
= NULL
;
310 CFIndex hashLength
= 0;
312 CSSM_DATA hashCssmData
= { 0, NULL
};
313 hashCssmData
.Length
= (CSSM_SIZE
)strlen(hash
)/2;
314 hashCssmData
.Data
= (uint8
*)malloc(hashCssmData
.Length
);
315 fromHex(hash
, &hashCssmData
);
316 hashLength
= (CFIndex
)hashCssmData
.Length
;
317 hashData
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)hashCssmData
.Data
, hashLength
);
318 free(hashCssmData
.Data
);
321 // filter candidates against the hash (or the name, if no hash provided)
322 CFStringRef matchRef
= (name
) ? CFStringCreateWithCString(NULL
, name
, kCFStringEncodingUTF8
) : NULL
;
323 Boolean exactMatch
= FALSE
;
324 SecKeychainItemRef candidate
= NULL
;
326 while (SecKeychainSearchCopyNext(searchRef
, &candidate
) == noErr
) {
327 SecCertificateRef cert
= (SecCertificateRef
)candidate
;
329 CFDataRef certHash
= NULL
;
330 if (hashLength
== CC_SHA1_DIGEST_LENGTH
) {
331 certHash
= SecCertificateGetSHA1Digest(cert
);
332 if (certHash
) { CFRetain(certHash
); }
333 } else if (hashLength
== CC_SHA256_DIGEST_LENGTH
) {
334 certHash
= SecCertificateCopySHA256Digest(cert
);
337 safe_CFRelease(&candidate
);
338 continue; // no hash, so no match is possible
339 } else if (CFEqual(certHash
, hashData
)) {
342 safe_CFRelease(&certHash
);
344 uniqueItemRef
= candidate
; // currently retained
345 break; // we're done - can't get more exact than this
348 // copy certificate name
349 CFStringRef nameRef
= NULL
;
350 if ((SecCertificateCopyCommonName(cert
, &nameRef
) != noErr
) || nameRef
== NULL
) {
351 safe_CFRelease(&candidate
);
352 continue; // no name, so no match is possible
354 CFIndex nameLen
= CFStringGetLength(nameRef
);
355 CFIndex bufLen
= 1 + CFStringGetMaximumSizeForEncoding(nameLen
, kCFStringEncodingUTF8
);
356 char *nameBuf
= (char *)malloc(bufLen
);
357 if (!CFStringGetCString(nameRef
, nameBuf
, bufLen
-1, kCFStringEncodingUTF8
))
360 CFRange find
= { kCFNotFound
, 0 };
361 if (nameRef
&& matchRef
)
362 find
= CFStringFind(nameRef
, matchRef
, kCFCompareCaseInsensitive
| kCFCompareNonliteral
);
363 Boolean isExact
= (find
.location
== 0 && find
.length
== nameLen
);
364 if (find
.location
== kCFNotFound
) {
366 safe_CFRelease(&nameRef
);
367 safe_CFRelease(&candidate
);
368 continue; // no match
370 if (uniqueItemRef
) { // got two matches
371 if (exactMatch
&& !isExact
) { // prior is better; ignore this one
373 safe_CFRelease(&nameRef
);
374 safe_CFRelease(&candidate
);
377 if (exactMatch
== isExact
) { // same class of match
378 if (CFEqual(uniqueItemRef
, candidate
)) { // same certificate
380 safe_CFRelease(&nameRef
);
381 safe_CFRelease(&candidate
);
384 // ambiguity - must fail
385 sec_error("\"%s\" is ambiguous, matches more than one certificate", name
);
387 safe_CFRelease(&nameRef
);
388 safe_CFRelease(&candidate
);
389 safe_CFRelease(&uniqueItemRef
);
392 safe_CFRelease(&uniqueItemRef
); // about to replace with this one
394 uniqueItemRef
= candidate
; // currently retained
395 exactMatch
= isExact
;
397 safe_CFRelease(&nameRef
);
401 safe_CFRelease(&searchRef
);
402 safe_CFRelease(&matchRef
);
403 safe_CFRelease(&hashData
);
405 return uniqueItemRef
;
409 do_password_item_printing(SecKeychainItemRef itemRef
,
410 Boolean get_password
,
411 Boolean password_stdout
)
413 OSStatus result
= noErr
;
414 void *passwordData
= NULL
;
415 UInt32 passwordLength
= 0;
418 result
= SecKeychainItemCopyContent(itemRef
, NULL
, NULL
, &passwordLength
, &passwordData
);
419 if(result
!= noErr
) return result
;
421 if(!password_stdout
) {
422 print_keychain_item_attributes(stdout
, itemRef
, FALSE
, FALSE
, FALSE
, FALSE
);
424 fputs("password: ", stderr
);
425 print_buffer(stderr
, passwordLength
, passwordData
);
429 uint8_t *password
= (uint8_t *) passwordData
;
431 for(uint32_t i
=0; i
<passwordLength
; i
++) if(!isprint(password
[i
])) doHex
= 1;
433 for(uint32_t i
=0; i
<passwordLength
; i
++) printf("%02x", password
[i
]);
435 for(uint32_t i
=0; i
<passwordLength
; i
++) putchar(password
[i
]);
440 if (passwordData
) SecKeychainItemFreeContent(NULL
, passwordData
);
446 do_keychain_find_generic_password(CFTypeRef keychainOrArray
,
447 FourCharCode itemCreator
,
448 FourCharCode itemType
,
453 const char *serviceName
,
454 const char *accountName
,
455 Boolean get_password
,
456 Boolean password_stdout
)
458 OSStatus result
= noErr
;
459 SecKeychainItemRef itemRef
= NULL
;
461 itemRef
= find_first_generic_password(keychainOrArray
,
472 result
= do_password_item_printing(itemRef
, get_password
, password_stdout
);
474 result
= errSecItemNotFound
;
475 sec_perror("SecKeychainSearchCopyNext", result
);
478 if (itemRef
) CFRelease(itemRef
);
484 do_keychain_delete_generic_password(CFTypeRef keychainOrArray
,
485 FourCharCode itemCreator
,
486 FourCharCode itemType
,
491 const char *serviceName
,
492 const char *accountName
)
494 OSStatus result
= noErr
;
495 SecKeychainItemRef itemRef
= NULL
;
496 void *passwordData
= NULL
;
498 if (!itemCreator
&& !itemType
&& !kind
&& !value
&& !comment
&& !label
&& !serviceName
&& !accountName
) {
499 return SHOW_USAGE_MESSAGE
;
502 itemRef
= find_first_generic_password(keychainOrArray
,
512 result
= errSecItemNotFound
;
513 sec_perror("SecKeychainSearchCopyNext", result
);
517 print_keychain_item_attributes(stdout
, itemRef
, FALSE
, FALSE
, FALSE
, FALSE
);
519 result
= SecKeychainItemDelete(itemRef
);
521 fputs("password has been deleted.\n", stderr
);
525 SecKeychainItemFreeContent(NULL
, passwordData
);
533 do_keychain_find_internet_password(CFTypeRef keychainOrArray
,
534 FourCharCode itemCreator
,
535 FourCharCode itemType
,
539 const char *serverName
,
540 const char *securityDomain
,
541 const char *accountName
,
544 SecProtocolType protocol
,
545 SecAuthenticationType authenticationType
,
546 Boolean get_password
,
547 Boolean password_stdout
)
549 OSStatus result
= noErr
;
550 SecKeychainItemRef itemRef
= NULL
;
552 itemRef
= find_first_internet_password(keychainOrArray
,
566 result
= do_password_item_printing(itemRef
, get_password
, password_stdout
);
568 result
= errSecItemNotFound
;
569 sec_perror("SecKeychainSearchCopyNext", result
);
576 do_keychain_delete_internet_password(CFTypeRef keychainOrArray
,
577 FourCharCode itemCreator
,
578 FourCharCode itemType
,
582 const char *serverName
,
583 const char *securityDomain
,
584 const char *accountName
,
587 SecProtocolType protocol
,
588 SecAuthenticationType authenticationType
)
590 OSStatus result
= noErr
;
591 SecKeychainItemRef itemRef
= NULL
;
592 void *passwordData
= NULL
;
594 if (!itemCreator
&& !itemType
&& !kind
&& !comment
&& !label
&& !serverName
&& !securityDomain
&& !accountName
&& !path
&& !port
&& !protocol
&& !authenticationType
) {
595 return SHOW_USAGE_MESSAGE
;
598 itemRef
= find_first_internet_password(keychainOrArray
,
612 result
= errSecItemNotFound
;
613 sec_perror("SecKeychainSearchCopyNext", result
);
617 print_keychain_item_attributes(stdout
, itemRef
, FALSE
, FALSE
, FALSE
, FALSE
);
619 result
= SecKeychainItemDelete(itemRef
);
621 fputs("password has been deleted.\n", stderr
);
625 SecKeychainItemFreeContent(NULL
, passwordData
);
633 do_keychain_find_certificate(CFTypeRef keychainOrArray
,
635 const char *emailAddress
,
641 OSStatus result
= noErr
;
642 SecCertificateRef certificateRef
= NULL
;
643 SecKeychainSearchRef searchRef
= NULL
;
644 CFStringRef matchRef
= (name
) ? CFStringCreateWithCString(NULL
, name
, kCFStringEncodingUTF8
) : NULL
;
646 if (find_all
&& emailAddress
) {
647 result
= SecKeychainSearchCreateForCertificateByEmail(keychainOrArray
, emailAddress
, &searchRef
);
649 sec_perror("SecKeychainSearchCreateForCertificateByEmail", result
);
653 result
= SecKeychainSearchCreateFromAttributes(keychainOrArray
, kSecCertificateItemClass
, NULL
, &searchRef
);
655 sec_perror("SecKeychainSearchCreateFromAttributes", result
);
663 SecKeychainItemRef itemRef
= NULL
;
664 result
= SecKeychainSearchCopyNext(searchRef
, &itemRef
);
665 if (result
== errSecItemNotFound
) {
670 sec_perror("SecKeychainSearchCopyNext", result
);
674 if (!emailAddress
&& name
) {
675 // match name in common name
676 CFStringRef nameRef
= NULL
;
677 if (SecCertificateCopyCommonName((SecCertificateRef
)itemRef
, &nameRef
) != noErr
) {
678 safe_CFRelease(&itemRef
);
679 continue; // no name, so no match is possible
681 CFRange find
= { kCFNotFound
, 0 };
682 if (nameRef
&& matchRef
)
683 find
= CFStringFind(nameRef
, matchRef
, kCFCompareCaseInsensitive
| kCFCompareNonliteral
);
684 if (find
.location
== kCFNotFound
) {
685 safe_CFRelease(&nameRef
);
686 safe_CFRelease(&itemRef
);
687 continue; // no match
689 safe_CFRelease(&nameRef
);
691 safe_CFRelease(&certificateRef
);
692 certificateRef
= (SecCertificateRef
) itemRef
;
694 else { // only want the first match
696 result
= SecCertificateFindByEmail(keychainOrArray
, emailAddress
, &certificateRef
);
698 sec_perror("SecCertificateFindByEmail", result
);
702 SecKeychainItemRef itemRef
= NULL
;
703 while ((result
= SecKeychainSearchCopyNext(searchRef
, &itemRef
)) != errSecItemNotFound
) {
705 // match name in common name
706 CFStringRef nameRef
= NULL
;
707 if (SecCertificateCopyCommonName((SecCertificateRef
)itemRef
, &nameRef
) != noErr
) {
708 safe_CFRelease(&itemRef
);
709 continue; // no name, so no match is possible
711 CFRange find
= { kCFNotFound
, 0 };
712 if (nameRef
&& matchRef
)
713 find
= CFStringFind(nameRef
, matchRef
, kCFCompareCaseInsensitive
| kCFCompareNonliteral
);
714 if (find
.location
== kCFNotFound
) {
715 safe_CFRelease(&nameRef
);
716 safe_CFRelease(&itemRef
);
717 continue; // no match
719 safe_CFRelease(&nameRef
);
721 break; // we have a match!
723 if (result
== errSecItemNotFound
) {
724 sec_perror("SecKeychainSearchCopyNext", result
);
727 certificateRef
= (SecCertificateRef
) itemRef
;
731 // process the found certificate
736 CFDataRef sha256Digest
= SecCertificateCopySHA256Digest(certificateRef
);
737 if (sha256Digest
!= NULL
&&
738 (count
= (CFIndex
)CFDataGetLength(sha256Digest
)) == CC_SHA256_DIGEST_LENGTH
&&
739 (p
= (unsigned char *)CFDataGetBytePtr(sha256Digest
)) != NULL
) {
740 // print SHA-256 hash value
741 fprintf(stdout
, "SHA-256 hash: ");
742 for (i
=0; i
<count
; i
++) { fprintf(stdout
, "%02X", p
[i
]); }
743 fprintf(stdout
, "\n");
745 safe_CFRelease(&sha256Digest
);
746 CFDataRef sha1Digest
= SecCertificateGetSHA1Digest(certificateRef
);
747 if (sha1Digest
!= NULL
&&
748 (count
= (CFIndex
)CFDataGetLength(sha1Digest
)) == CC_SHA1_DIGEST_LENGTH
&&
749 (p
= (unsigned char *)CFDataGetBytePtr(sha1Digest
)) != NULL
) {
750 // print SHA-1 hash value for compatibility
751 fprintf(stdout
, "SHA-1 hash: ");
752 for (i
=0; i
<count
; i
++) { fprintf(stdout
, "%02X", p
[i
]); }
753 fprintf(stdout
, "\n");
759 CFArrayRef emailAddresses
= NULL
;
761 result
= SecCertificateCopyEmailAddresses(certificateRef
, &emailAddresses
);
764 sec_perror("SecCertificateCopyEmailAddresses", result
);
768 count
= CFArrayGetCount(emailAddresses
);
769 fputs("email addresses: ", stdout
);
770 for (ix
= 0; ix
< count
; ++ix
)
772 CFStringRef emailAddress
= (CFStringRef
)CFArrayGetValueAtIndex(emailAddresses
, ix
);
779 addr
= CFStringGetCStringPtr(emailAddress
, kCFStringEncodingUTF8
);
782 if (CFStringGetCString(emailAddress
, buffer
, sizeof(buffer
), kCFStringEncodingUTF8
))
786 fprintf(stdout
, "%s", addr
);
790 CFRelease(emailAddresses
);
795 CSSM_DATA certData
= {};
796 result
= SecCertificateGetData(certificateRef
, &certData
);
799 sec_perror("SecCertificateGetData", result
);
803 print_buffer_pem(stdout
, "CERTIFICATE", certData
.Length
, certData
.Data
);
807 print_keychain_item_attributes(stdout
, (SecKeychainItemRef
)certificateRef
, FALSE
, FALSE
, FALSE
, FALSE
);
812 safe_CFRelease(&searchRef
);
813 safe_CFRelease(&certificateRef
);
814 safe_CFRelease(&matchRef
);
820 keychain_delete_internet_password(int argc
, char * const *argv
)
822 char *serverName
= NULL
, *securityDomain
= NULL
, *accountName
= NULL
, *path
= NULL
;
823 char *kind
= NULL
, *label
= NULL
, *comment
= NULL
;
824 FourCharCode itemCreator
= 0, itemType
= 0;
826 SecProtocolType protocol
= 0;
827 SecAuthenticationType authenticationType
= 0;
828 CFTypeRef keychainOrArray
= NULL
;
832 * " -a Match \"account\" string\n"
833 * " -c Match \"creator\" (four-character code)\n"
834 * " -C Match \"type\" (four-character code)\n"
835 * " -d Match \"securityDomain\" string\n"
836 * " -D Match \"kind\" string\n"
837 * " -j Match \"comment\" string\n"
838 * " -l Match \"label\" string\n"
839 * " -p Match \"path\" string\n"
840 * " -P Match port number\n"
841 * " -r Match \"protocol\" (four-character code)\n"
842 * " -s Match \"server\" string\n"
843 * " -t Match \"authenticationType\" (four-character code)\n"
846 while ((ch
= getopt(argc
, argv
, "ha:c:C:d:D:hgj:l:p:P:r:s:t:")) != -1)
851 accountName
= optarg
;
854 result
= parse_fourcharcode(optarg
, &itemCreator
);
855 if (result
) goto cleanup
;
858 result
= parse_fourcharcode(optarg
, &itemType
);
859 if (result
) goto cleanup
;
862 securityDomain
= optarg
;
880 result
= parse_fourcharcode(optarg
, &protocol
);
881 if (result
) goto cleanup
;
887 result
= parse_fourcharcode(optarg
, &authenticationType
);
888 if (result
) goto cleanup
;
892 result
= 2; /* @@@ Return 2 triggers usage message. */
900 keychainOrArray
= keychain_create_array(argc
, argv
);
902 result
= do_keychain_delete_internet_password(keychainOrArray
,
917 CFRelease(keychainOrArray
);
923 keychain_find_internet_password(int argc
, char * const *argv
)
925 char *serverName
= NULL
, *securityDomain
= NULL
, *accountName
= NULL
, *path
= NULL
;
926 char *kind
= NULL
, *label
= NULL
, *comment
= NULL
;
927 FourCharCode itemCreator
= 0, itemType
= 0;
929 SecProtocolType protocol
= 0;
930 SecAuthenticationType authenticationType
= 0;
931 CFTypeRef keychainOrArray
= NULL
;
933 Boolean get_password
= FALSE
;
934 Boolean password_stdout
= FALSE
;
937 * " -a Match \"account\" string\n"
938 * " -c Match \"creator\" (four-character code)\n"
939 * " -C Match \"type\" (four-character code)\n"
940 * " -d Match \"securityDomain\" string\n"
941 * " -D Match \"kind\" string\n"
942 * " -j Match \"comment\" string\n"
943 * " -l Match \"label\" string\n"
944 * " -p Match \"path\" string\n"
945 * " -P Match port number\n"
946 * " -r Match \"protocol\" (four-character code)\n"
947 * " -s Match \"server\" string\n"
948 * " -t Match \"authenticationType\" (four-character code)\n"
949 * " -g Display the password for the item found\n"
950 * " -w Display the password(only) for the item(s) found\n"
953 while ((ch
= getopt(argc
, argv
, "ha:c:C:d:D:hgj:l:p:P:r:s:wt:")) != -1)
958 accountName
= optarg
;
961 result
= parse_fourcharcode(optarg
, &itemCreator
);
962 if (result
) goto cleanup
;
965 result
= parse_fourcharcode(optarg
, &itemType
);
966 if (result
) goto cleanup
;
969 securityDomain
= optarg
;
990 result
= parse_fourcharcode(optarg
, &protocol
);
991 if (result
) goto cleanup
;
998 password_stdout
= TRUE
;
1001 result
= parse_fourcharcode(optarg
, &authenticationType
);
1002 if (result
) goto cleanup
;
1003 /* auth type attribute is special */
1004 authenticationType
= OSSwapHostToBigInt32(authenticationType
);
1008 result
= 2; /* @@@ Return 2 triggers usage message. */
1016 keychainOrArray
= keychain_create_array(argc
, argv
);
1018 result
= do_keychain_find_internet_password(keychainOrArray
,
1034 if (keychainOrArray
)
1035 CFRelease(keychainOrArray
);
1041 keychain_delete_generic_password(int argc
, char * const *argv
)
1043 char *serviceName
= NULL
, *accountName
= NULL
;
1044 char *kind
= NULL
, *label
= NULL
, *value
= NULL
, *comment
= NULL
;
1045 FourCharCode itemCreator
= 0, itemType
= 0;
1046 CFTypeRef keychainOrArray
= nil
;
1050 * " -a Match \"account\" string\n"
1051 * " -c Match \"creator\" (four-character code)\n"
1052 * " -C Match \"type\" (four-character code)\n"
1053 * " -D Match \"kind\" string\n"
1054 * " -G Match \"value\" string (generic attribute)\n"
1055 * " -j Match \"comment\" string\n"
1056 * " -l Match \"label\" string\n"
1057 * " -s Match \"service\" string\n"
1060 while ((ch
= getopt(argc
, argv
, "ha:c:C:D:G:j:l:s:g")) != -1)
1065 accountName
= optarg
;
1068 result
= parse_fourcharcode(optarg
, &itemCreator
);
1069 if (result
) goto cleanup
;
1072 result
= parse_fourcharcode(optarg
, &itemType
);
1073 if (result
) goto cleanup
;
1088 serviceName
= optarg
;
1092 result
= 2; /* @@@ Return 2 triggers usage message. */
1100 keychainOrArray
= keychain_create_array(argc
, argv
);
1102 result
= do_keychain_delete_generic_password(keychainOrArray
,
1112 if (keychainOrArray
)
1113 CFRelease(keychainOrArray
);
1119 keychain_find_generic_password(int argc
, char * const *argv
)
1121 char *serviceName
= NULL
, *accountName
= NULL
;
1122 char *kind
= NULL
, *label
= NULL
, *value
= NULL
, *comment
= NULL
;
1123 FourCharCode itemCreator
= 0, itemType
= 0;
1124 CFTypeRef keychainOrArray
= nil
;
1126 Boolean get_password
= FALSE
;
1127 Boolean password_stdout
= FALSE
;
1130 * " -a Match \"account\" string\n"
1131 * " -c Match \"creator\" (four-character code)\n"
1132 * " -C Match \"type\" (four-character code)\n"
1133 * " -D Match \"kind\" string\n"
1134 * " -G Match \"value\" string (generic attribute)\n"
1135 * " -j Match \"comment\" string\n"
1136 * " -l Match \"label\" string\n"
1137 * " -s Match \"service\" string\n"
1138 * " -g Display the password for the item(s) found\n"
1139 * " -w Display the password(only) for the item(s) found\n"
1142 while ((ch
= getopt(argc
, argv
, "ha:c:C:D:G:j:l:s:wg")) != -1)
1147 accountName
= optarg
;
1150 result
= parse_fourcharcode(optarg
, &itemCreator
);
1151 if (result
) goto cleanup
;
1154 result
= parse_fourcharcode(optarg
, &itemType
);
1155 if (result
) goto cleanup
;
1170 serviceName
= optarg
;
1173 password_stdout
= TRUE
;
1174 get_password
= TRUE
;
1177 get_password
= TRUE
;
1181 result
= 2; /* @@@ Return 2 triggers usage message. */
1189 keychainOrArray
= keychain_create_array(argc
, argv
);
1191 result
= do_keychain_find_generic_password(keychainOrArray
,
1203 if (keychainOrArray
)
1204 CFRelease(keychainOrArray
);
1209 #define SetKeyToString(dict, key, arg) \
1211 CFStringRef str = CFStringCreateWithCStringNoCopy(NULL, arg, kCFStringEncodingUTF8, kCFAllocatorNull); \
1212 CFDictionarySetValue(dict, key, str); \
1213 CFReleaseNull(str); \
1217 keychain_find_key(int argc
, char * const *argv
) {
1219 * " -a Match \"application label\" string\n"
1220 * " -c Match \"creator\" (four-character code)\n"
1221 * " -d Match keys that can decrypt\n"
1222 * " -D Match \"description\" string\n"
1223 * " -e Match keys that can encrypt\n"
1224 * " -j Match \"comment\" string\n"
1225 * " -l Match \"label\" string\n"
1226 * " -r Match keys that can derive\n"
1227 * " -s Match keys that can sign\n"
1228 * " -t Type of key to find: one of \"symmetric\", \"public\", or \"private\"\n"
1229 * " -u Match keys that can unwrap\n"
1230 * " -v Match keys that can verify\n"
1231 * " -w Match keys that can wrap\n"
1234 CFMutableDictionaryRef query
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1235 CFDictionarySetValue(query
, kSecClass
, kSecClassKey
);
1236 CFDictionarySetValue(query
, kSecMatchLimit
, kSecMatchLimitAll
);
1238 CFTypeRef results
= NULL
;
1241 while ((ch
= getopt(argc
, argv
, "a:c:dD:ej:l:rst:uvw")) != -1)
1246 SetKeyToString(query
, kSecAttrApplicationLabel
, optarg
);
1249 SetKeyToString(query
, kSecAttrCreator
, optarg
);
1252 CFDictionarySetValue(query
, kSecAttrCanDecrypt
, kCFBooleanTrue
);
1255 SetKeyToString(query
, kSecAttrDescription
, optarg
);
1258 CFDictionarySetValue(query
, kSecAttrCanEncrypt
, kCFBooleanTrue
);
1261 SetKeyToString(query
, kSecAttrComment
, optarg
);
1264 SetKeyToString(query
, kSecAttrLabel
, optarg
);
1267 CFDictionarySetValue(query
, kSecAttrCanDerive
, kCFBooleanTrue
);
1270 CFDictionarySetValue(query
, kSecAttrCanSign
, kCFBooleanTrue
);
1273 if(strcmp(optarg
, "symmetric") == 0) {
1274 CFDictionarySetValue(query
, kSecAttrKeyClass
, kSecAttrKeyClassSymmetric
);
1275 } else if(strcmp(optarg
, "public") == 0) {
1276 CFDictionarySetValue(query
, kSecAttrKeyClass
, kSecAttrKeyClassPublic
);
1277 } else if(strcmp(optarg
, "private") == 0) {
1278 CFDictionarySetValue(query
, kSecAttrKeyClass
, kSecAttrKeyClassPrivate
);
1285 CFDictionarySetValue(query
, kSecAttrCanUnwrap
, kCFBooleanTrue
);
1288 CFDictionarySetValue(query
, kSecAttrCanVerify
, kCFBooleanTrue
);
1291 CFDictionarySetValue(query
, kSecAttrCanWrap
, kCFBooleanTrue
);
1303 CFTypeRef keychainOrArray
= keychain_create_array(argc
, argv
);
1305 if(keychainOrArray
&& CFGetTypeID(keychainOrArray
) == CFArrayGetTypeID()) {
1306 CFDictionarySetValue(query
, kSecMatchSearchList
, keychainOrArray
);
1307 } else if(keychainOrArray
) {
1308 // if it's not an array (but is something), it's a keychain. Put it in an array.
1309 CFMutableArrayRef searchList
= (CFMutableArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 1, &kCFTypeArrayCallBacks
);
1310 CFArrayAppendValue((CFMutableArrayRef
)searchList
, keychainOrArray
);
1311 CFDictionarySetValue(query
, kSecMatchSearchList
, searchList
);
1312 CFRelease(searchList
);
1314 CFReleaseNull(keychainOrArray
);
1316 OSStatus status
= SecItemCopyMatching(query
, &results
);
1318 sec_perror("SecItemCopyMatching", status
);
1323 if (CFGetTypeID(results
) == CFArrayGetTypeID()) {
1324 for(int i
= 0; i
< CFArrayGetCount(results
); i
++) {
1325 SecKeychainItemRef item
= (SecKeychainItemRef
) CFArrayGetValueAtIndex(results
, i
);
1327 print_keychain_item_attributes(stdout
, item
, FALSE
, FALSE
, FALSE
, FALSE
);
1332 safe_CFRelease(&results
);
1333 safe_CFRelease(&query
);
1337 // Declare here to use later.
1338 int keychain_set_partition_list(SecKeychainRef kc
, CFDictionaryRef query
, CFStringRef password
, CFStringRef partitionlist
);
1339 int keychain_parse_args_and_set_partition_list(int argc
, char * const *argv
, CFMutableDictionaryRef query
, CFStringRef partitionidsinput
, CFStringRef password
);
1341 int keychain_set_internet_password_partition_list(int argc
, char * const *argv
) {
1343 * " -a Match \"account\" string\n"
1344 * " -c Match \"creator\" (four-character code)\n"
1345 * " -C Match \"type\" (four-character code)\n"
1346 * " -d Match \"securityDomain\" string\n"
1347 * " -D Match \"kind\" string\n"
1348 * " -j Match \"comment\" string\n"
1349 * " -l Match \"label\" string\n"
1350 * " -p Match \"path\" string\n"
1351 * " -P Match port number\n"
1352 * " -r Match \"protocol\" (four-character code)\n"
1353 * " -s Match \"server\" string\n"
1354 * " -t Match \"authenticationType\" (four-character code)\n"
1355 * " -S Comma-separated list of allowed partition IDs"
1356 * " -k password for keychain"
1359 CFMutableDictionaryRef query
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1360 CFDictionarySetValue(query
, kSecClass
, kSecClassInternetPassword
);
1361 CFDictionarySetValue(query
, kSecMatchLimit
, kSecMatchLimitAll
);
1363 CFStringRef partitionidsinput
= NULL
;
1364 CFStringRef password
= NULL
;
1367 while ((ch
= getopt(argc
, argv
, "a:c:C:d:D:j:l:p:P:r:s:S:t:k:")) != -1)
1372 SetKeyToString(query
, kSecAttrAccount
, optarg
);
1375 SetKeyToString(query
, kSecAttrCreator
, optarg
);
1378 SetKeyToString(query
, kSecAttrType
, optarg
);
1381 SetKeyToString(query
, kSecAttrSecurityDomain
, optarg
);
1384 SetKeyToString(query
, kSecAttrDescription
, optarg
);
1387 SetKeyToString(query
, kSecAttrComment
, optarg
);
1390 SetKeyToString(query
, kSecAttrLabel
, optarg
);
1393 SetKeyToString(query
, kSecAttrPath
, optarg
);
1396 SetKeyToString(query
, kSecAttrPort
, optarg
);
1399 SetKeyToString(query
, kSecAttrProtocol
, optarg
);
1402 SetKeyToString(query
, kSecAttrServer
, optarg
);
1405 SetKeyToString(query
, kSecAttrAuthenticationType
, optarg
);
1408 CFReleaseNull(partitionidsinput
);
1409 partitionidsinput
= CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1412 CFReleaseNull(password
);
1413 password
= CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1425 result
= keychain_parse_args_and_set_partition_list(argc
, argv
, query
, partitionidsinput
, password
);
1428 safe_CFRelease(&password
);
1429 safe_CFRelease(&partitionidsinput
);
1430 safe_CFRelease(&query
);
1435 keychain_set_generic_password_partition_list(int argc
, char * const *argv
) {
1436 CFMutableDictionaryRef query
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1438 // -a Match \"account\" string
1439 // -c Match \"creator\" (four-character code)
1440 // -C Match \"type\" (four-character code)
1441 // -D Match \"kind\" string
1442 // -G Match \"value\" string (generic attribute)
1443 // -j Match \"comment\" string
1444 // -l Match \"label\" string
1445 // -s Match \"service\" string
1446 // -S Comma-separated list of allowed partition IDs
1447 // -k password for keychain
1449 CFDictionarySetValue(query
, kSecClass
, kSecClassGenericPassword
);
1450 CFDictionarySetValue(query
, kSecMatchLimit
, kSecMatchLimitAll
);
1452 CFStringRef partitionidsinput
= NULL
;
1453 CFStringRef password
= NULL
;
1456 while ((ch
= getopt(argc
, argv
, ":a:c:C:D:G:j:l:s:S:k:")) != -1)
1461 SetKeyToString(query
, kSecAttrAccount
, optarg
);
1464 SetKeyToString(query
, kSecAttrCreator
, optarg
);
1467 SetKeyToString(query
, kSecAttrType
, optarg
);
1470 SetKeyToString(query
, kSecAttrDescription
, optarg
);
1473 SetKeyToString(query
, kSecAttrGeneric
, optarg
);
1476 SetKeyToString(query
, kSecAttrComment
, optarg
);
1479 SetKeyToString(query
, kSecAttrLabel
, optarg
);
1482 SetKeyToString(query
, kSecAttrService
, optarg
);
1485 CFReleaseNull(partitionidsinput
);
1486 partitionidsinput
= CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1489 CFReleaseNull(password
);
1490 password
= CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1494 // They supplied the -k but with no data
1495 // Leaving it null will cause prompt below
1496 if (optopt
== 'k') {
1500 goto cleanup
; /* @@@ Return 2 triggers usage message. */
1510 result
= keychain_parse_args_and_set_partition_list(argc
, argv
, query
, partitionidsinput
, password
);
1513 safe_CFRelease(&password
);
1514 safe_CFRelease(&partitionidsinput
);
1515 safe_CFRelease(&query
);
1520 keychain_set_key_partition_list(int argc
, char * const *argv
) {
1522 * " -a Match \"application label\" string\n"
1523 * " -c Match \"creator\" (four-character code)\n"
1524 * " -d Match keys that can decrypt\n"
1525 * " -D Match \"description\" string\n"
1526 * " -e Match keys that can encrypt\n"
1527 * " -j Match \"comment\" string\n"
1528 * " -l Match \"label\" string\n"
1529 * " -r Match keys that can derive\n"
1530 * " -s Match keys that can sign\n"
1531 * " -t Type of key to find: one of \"symmetric\", \"public\", or \"private\"\n"
1532 * " -u Match keys that can unwrap\n"
1533 * " -v Match keys that can verify\n"
1534 * " -w Match keys that can wrap\n"
1535 * " -S Comma-separated list of allowed partition IDs
1536 * " -k password for keychain (required)
1539 CFMutableDictionaryRef query
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1540 CFDictionarySetValue(query
, kSecClass
, kSecClassKey
);
1541 CFDictionarySetValue(query
, kSecMatchLimit
, kSecMatchLimitAll
);
1543 CFStringRef partitionidsinput
= NULL
;
1544 CFStringRef password
= NULL
;
1547 while ((ch
= getopt(argc
, argv
, ":a:c:dD:ej:k:l:rsS:t:uvw")) != -1)
1552 SetKeyToString(query
, kSecAttrApplicationLabel
, optarg
);
1555 SetKeyToString(query
, kSecAttrCreator
, optarg
);
1558 SetKeyToString(query
, kSecAttrCanDecrypt
, optarg
);
1559 CFDictionarySetValue(query
, kSecAttrCanDecrypt
, kCFBooleanTrue
);
1562 SetKeyToString(query
, kSecAttrDescription
, optarg
);
1565 CFDictionarySetValue(query
, kSecAttrCanEncrypt
, kCFBooleanTrue
);
1568 SetKeyToString(query
, kSecAttrComment
, optarg
);
1571 SetKeyToString(query
, kSecAttrLabel
, optarg
);
1574 CFDictionarySetValue(query
, kSecAttrCanDerive
, kCFBooleanTrue
);
1576 CFDictionarySetValue(query
, kSecAttrCanSign
, kCFBooleanTrue
);
1579 if(strcmp(optarg
, "symmetric") == 0) {
1580 CFDictionarySetValue(query
, kSecAttrKeyClass
, kSecAttrKeyClassSymmetric
);
1581 } else if(strcmp(optarg
, "public") == 0) {
1582 CFDictionarySetValue(query
, kSecAttrKeyClass
, kSecAttrKeyClassPublic
);
1583 } else if(strcmp(optarg
, "private") == 0) {
1584 CFDictionarySetValue(query
, kSecAttrKeyClass
, kSecAttrKeyClassPrivate
);
1591 CFDictionarySetValue(query
, kSecAttrCanUnwrap
, kCFBooleanTrue
);
1594 CFDictionarySetValue(query
, kSecAttrCanVerify
, kCFBooleanTrue
);
1597 CFDictionarySetValue(query
, kSecAttrCanWrap
, kCFBooleanTrue
);
1600 CFReleaseNull(partitionidsinput
);
1601 partitionidsinput
= CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1604 CFReleaseNull(password
);
1605 password
= CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1609 // They supplied the -k but with no data
1610 // Leaving it null will cause prompt below
1611 if (optopt
== 'k') {
1615 goto cleanup
; /* @@@ Return 2 triggers usage message. */
1625 result
= keychain_parse_args_and_set_partition_list(argc
, argv
, query
, partitionidsinput
, password
);
1628 CFReleaseNull(partitionidsinput
);
1629 CFReleaseNull(password
);
1630 safe_CFRelease(&query
);
1635 int keychain_parse_args_and_set_partition_list(int argc
, char * const *argv
, CFMutableDictionaryRef query
, CFStringRef partitionidsinput
, CFStringRef password
) {
1637 const char *keychainName
= NULL
;
1638 SecKeychainRef kc
= NULL
;
1639 CFStringRef localPassword
= NULL
;
1641 // if we were given a keychain, use it
1644 keychainName
= argv
[0];
1645 if (*keychainName
== '\0')
1651 kc
= keychain_open(keychainName
);
1653 sec_error("couldn't open \"%s\"", keychainName
);
1658 CFMutableArrayRef searchList
= (CFMutableArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 1, &kCFTypeArrayCallBacks
);
1659 CFArrayAppendValue((CFMutableArrayRef
)searchList
, kc
);
1660 CFDictionarySetValue(query
, kSecMatchSearchList
, searchList
);
1661 } else if (argc
!= 0) {
1666 if(!partitionidsinput
) {
1672 char* cpassword
= prompt_password(keychainName
);
1677 localPassword
= CFStringCreateWithCString(NULL
, cpassword
, kCFStringEncodingUTF8
);
1678 password
= localPassword
;
1682 result
= keychain_set_partition_list(kc
, query
, password
, partitionidsinput
);
1685 CFReleaseNull(localPassword
);
1690 int keychain_set_partition_list(SecKeychainRef kc
, CFDictionaryRef query
, CFStringRef password
, CFStringRef partitionlist
) {
1693 char *passwordBuf
= NULL
;
1695 GetCStringFromCFString(password
, &passwordBuf
, &passwordLen
);
1698 CFTypeRef results
= NULL
;
1700 // Unlock the keychain with the given password, since we'll be fetching ACLs
1701 status
= SecKeychainUnlock(kc
, (UInt32
) passwordLen
, passwordBuf
, true);
1703 sec_perror("SecKeychainUnlock", status
);
1708 status
= SecItemCopyMatching(query
, &results
);
1710 sec_perror("SecItemCopyMatching", status
);
1720 if (CFGetTypeID(results
) == CFArrayGetTypeID()) {
1721 for(int i
= 0; i
< CFArrayGetCount(results
); i
++) {
1722 SecKeychainItemRef item
= (SecKeychainItemRef
) CFArrayGetValueAtIndex(results
, i
);
1723 SecAccessRef access
= NULL
;
1725 do_password_item_printing(item
, false, false);
1727 status
= SecKeychainItemCopyAccess(item
, &access
);
1728 if (status
== errSecNoAccessForItem
) {
1732 sec_perror("SecKeychainItemCopyAccess", status
);
1737 CFArrayRef aclList
= NULL
;
1738 status
= SecAccessCopyACLList(access
, &aclList
);
1741 sec_perror("SecAccessCopyACLList", status
);
1746 CFIndex size
= CFArrayGetCount(aclList
);
1747 for(CFIndex i
= 0; i
< size
; i
++) {
1748 SecACLRef acl
= (SecACLRef
) CFArrayGetValueAtIndex(aclList
, i
);
1749 CSSM_ACL_AUTHORIZATION_TAG tags
[64]; // Pick some upper limit
1750 uint32 tagix
, tagCount
= sizeof(tags
) / sizeof(*tags
);
1751 status
= SecACLGetAuthorizations(acl
, tags
, &tagCount
);
1755 sec_perror("SecACLGetAuthorizations", status
);
1760 CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector
= {};
1762 for (tagix
= 0; tagix
< tagCount
; ++tagix
)
1764 CSSM_ACL_AUTHORIZATION_TAG tag
= tags
[tagix
];
1765 if(tag
== CSSM_ACL_AUTHORIZATION_PARTITION_ID
) {
1767 CFArrayRef applicationList
;
1768 CFStringRef promptDescription
;
1770 status
= SecACLCopySimpleContents(acl
, &applicationList
, &promptDescription
, &promptSelector
);
1772 sec_perror("SecACLCopySimpleContents", status
);
1777 CFArrayRef partitionIDs
= CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault
, partitionlist
, CFSTR(","));
1778 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1779 CFDictionarySetValue(dict
, CFSTR("Partitions"), partitionIDs
);
1780 CFDataRef xml
= CFPropertyListCreateXMLData(NULL
, dict
);
1781 CFStringRef xmlstr
= cfToHex(xml
);
1783 SecACLSetSimpleContents(acl
, applicationList
, xmlstr
, &promptSelector
);
1785 safe_CFRelease(&xmlstr
);
1786 safe_CFRelease(&xml
);
1787 safe_CFRelease(&dict
);
1788 safe_CFRelease(&partitionIDs
);
1793 status
= SecKeychainItemSetAccessWithPassword(item
, access
, (UInt32
) passwordLen
, passwordBuf
);
1795 sec_perror("SecKeychainItemSetAccessWithPassword", status
);
1808 safe_CFRelease(&results
);
1816 keychain_find_certificate(int argc
, char * const *argv
)
1818 char *emailAddress
= NULL
;
1821 CFTypeRef keychainOrArray
= nil
;
1822 Boolean output_pem
= FALSE
;
1823 Boolean find_all
= FALSE
;
1824 Boolean print_hash
= FALSE
;
1825 Boolean print_email
= FALSE
;
1827 while ((ch
= getopt(argc
, argv
, "hac:e:mpZ")) != -1)
1838 emailAddress
= optarg
;
1851 result
= 2; /* @@@ Return 2 triggers usage message. */
1859 keychainOrArray
= keychain_create_array(argc
, argv
);
1861 result
= do_keychain_find_certificate(keychainOrArray
, name
, emailAddress
, print_hash
, output_pem
, find_all
, print_email
);
1864 if (keychainOrArray
)
1865 CFRelease(keychainOrArray
);
1872 do_keychain_dump_class(FILE *stream
, CFTypeRef keychainOrArray
, SecItemClass itemClass
, Boolean show_data
, Boolean show_raw_data
, Boolean show_acl
, Boolean interactive
)
1874 SecKeychainItemRef item
;
1875 SecKeychainSearchRef search
= NULL
;
1879 status
= SecKeychainSearchCreateFromAttributes(keychainOrArray
, itemClass
, NULL
, &search
);
1882 sec_perror("SecKeychainSearchCreateFromAttributes", status
);
1887 while ((status
= SecKeychainSearchCopyNext(search
, &item
)) == 0)
1889 print_keychain_item_attributes(stream
, item
, show_data
, show_raw_data
, show_acl
, interactive
);
1893 if (status
!= errSecItemNotFound
)
1895 sec_perror("SecKeychainSearchCopyNext", status
);
1908 do_keychain_dump(FILE *stream
, CFTypeRef keychainOrArray
, Boolean show_data
, Boolean show_raw_data
, Boolean show_acl
, Boolean interactive
)
1910 return do_keychain_dump_class(stream
, keychainOrArray
, CSSM_DL_DB_RECORD_ANY
, show_data
, show_raw_data
, show_acl
, interactive
);
1914 keychain_dump(int argc
, char * const *argv
)
1917 Boolean show_data
= FALSE
, show_raw_data
= FALSE
, show_acl
= FALSE
, interactive
= FALSE
;
1918 CFTypeRef keychainOrArray
= NULL
;
1919 const char *outputFilename
= NULL
;
1922 while ((ch
= getopt(argc
, argv
, "adhiro:")) != -1)
1937 show_raw_data
= TRUE
;
1940 outputFilename
= optarg
;
1944 return SHOW_USAGE_MESSAGE
;
1951 keychainOrArray
= keychain_create_array(argc
, argv
);
1954 output
= fopen(outputFilename
, "w");
1958 result
= do_keychain_dump(output
, keychainOrArray
, show_data
, show_raw_data
, show_acl
, interactive
);
1963 if (keychainOrArray
)
1964 CFRelease(keychainOrArray
);