2 * Copyright (c) 2003-2010,2012-2014 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 <CoreFoundation/CFString.h>
46 #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 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 CSSM_DATA hashData
= { 0, NULL
};
311 CSSM_SIZE len
= strlen(hash
)/2;
312 hashData
.Length
= len
;
313 hashData
.Data
= (uint8
*)malloc(hashData
.Length
);
314 fromHex(hash
, &hashData
);
317 // filter candidates against the hash (or the name, if no hash provided)
318 CFStringRef matchRef
= (name
) ? CFStringCreateWithCString(NULL
, name
, kCFStringEncodingUTF8
) : NULL
;
319 Boolean exactMatch
= FALSE
;
321 CSSM_DATA certData
= { 0, NULL
};
322 SecKeychainItemRef candidate
= NULL
;
324 while (SecKeychainSearchCopyNext(searchRef
, &candidate
) == noErr
) {
325 SecCertificateRef cert
= (SecCertificateRef
)candidate
;
326 if (SecCertificateGetData(cert
, &certData
) != noErr
) {
327 safe_CFRelease(&candidate
);
331 uint8 candidate_sha1_hash
[20];
333 digest
.Length
= sizeof(candidate_sha1_hash
);
334 digest
.Data
= candidate_sha1_hash
;
335 if ((SecDigestGetData(CSSM_ALGID_SHA1
, &digest
, &certData
) == CSSM_OK
) &&
336 (hashData
.Length
== digest
.Length
) &&
337 (!memcmp(hashData
.Data
, digest
.Data
, digest
.Length
))) {
339 uniqueItemRef
= candidate
; // currently retained
340 break; // we're done - can't get more exact than this
343 // copy certificate name
344 CFStringRef nameRef
= NULL
;
345 if ((SecCertificateCopyCommonName(cert
, &nameRef
) != noErr
) || nameRef
== NULL
) {
346 safe_CFRelease(&candidate
);
347 continue; // no name, so no match is possible
349 CFIndex nameLen
= CFStringGetLength(nameRef
);
350 CFIndex bufLen
= 1 + CFStringGetMaximumSizeForEncoding(nameLen
, kCFStringEncodingUTF8
);
351 char *nameBuf
= (char *)malloc(bufLen
);
352 if (!CFStringGetCString(nameRef
, nameBuf
, bufLen
-1, kCFStringEncodingUTF8
))
355 CFRange find
= { kCFNotFound
, 0 };
356 if (nameRef
&& matchRef
)
357 find
= CFStringFind(nameRef
, matchRef
, kCFCompareCaseInsensitive
| kCFCompareNonliteral
);
358 Boolean isExact
= (find
.location
== 0 && find
.length
== nameLen
);
359 if (find
.location
== kCFNotFound
) {
361 safe_CFRelease(&nameRef
);
362 safe_CFRelease(&candidate
);
363 continue; // no match
365 if (uniqueItemRef
) { // got two matches
366 if (exactMatch
&& !isExact
) { // prior is better; ignore this one
368 safe_CFRelease(&nameRef
);
369 safe_CFRelease(&candidate
);
372 if (exactMatch
== isExact
) { // same class of match
373 if (CFEqual(uniqueItemRef
, candidate
)) { // same certificate
375 safe_CFRelease(&nameRef
);
376 safe_CFRelease(&candidate
);
379 // ambiguity - must fail
380 sec_error("\"%s\" is ambiguous, matches more than one certificate", name
);
382 safe_CFRelease(&nameRef
);
383 safe_CFRelease(&candidate
);
384 safe_CFRelease(&uniqueItemRef
);
387 safe_CFRelease(&uniqueItemRef
); // about to replace with this one
389 uniqueItemRef
= candidate
; // currently retained
390 exactMatch
= isExact
;
392 safe_CFRelease(&nameRef
);
396 safe_CFRelease(&searchRef
);
397 safe_CFRelease(&matchRef
);
402 return uniqueItemRef
;
406 do_password_item_printing( SecKeychainItemRef itemRef
,
407 Boolean get_password
,
408 Boolean password_stdout
)
410 OSStatus result
= noErr
;
411 void *passwordData
= NULL
;
412 UInt32 passwordLength
= 0;
415 result
= SecKeychainItemCopyContent(itemRef
, NULL
, NULL
, &passwordLength
, &passwordData
);
416 if(result
!= noErr
) return result
;
418 if(!password_stdout
) {
419 print_keychain_item_attributes(stdout
, itemRef
, FALSE
, FALSE
, FALSE
, FALSE
);
421 fputs("password: ", stderr
);
422 print_buffer(stderr
, passwordLength
, passwordData
);
426 char *password
= (char *) passwordData
;
428 for(uint32_t i
=0; i
<passwordLength
; i
++) if(!isprint(password
[i
])) doHex
= 1;
430 for(uint32_t i
=0; i
<passwordLength
; i
++) printf("%02x", password
[i
]);
432 for(uint32_t i
=0; i
<passwordLength
; i
++) putchar(password
[i
]);
437 if (passwordData
) SecKeychainItemFreeContent(NULL
, passwordData
);
443 do_keychain_find_generic_password(CFTypeRef keychainOrArray
,
444 FourCharCode itemCreator
,
445 FourCharCode itemType
,
450 const char *serviceName
,
451 const char *accountName
,
452 Boolean get_password
,
453 Boolean password_stdout
)
455 OSStatus result
= noErr
;
456 SecKeychainItemRef itemRef
= NULL
;
458 itemRef
= find_first_generic_password(keychainOrArray
,
469 result
= do_password_item_printing(itemRef
, get_password
, password_stdout
);
471 result
= errSecItemNotFound
;
472 sec_perror("SecKeychainSearchCopyNext", result
);
475 if (itemRef
) CFRelease(itemRef
);
481 do_keychain_delete_generic_password(CFTypeRef keychainOrArray
,
482 FourCharCode itemCreator
,
483 FourCharCode itemType
,
488 const char *serviceName
,
489 const char *accountName
)
491 OSStatus result
= noErr
;
492 SecKeychainItemRef itemRef
= NULL
;
493 void *passwordData
= NULL
;
495 if (!itemCreator
&& !itemType
&& !kind
&& !value
&& !comment
&& !label
&& !serviceName
&& !accountName
) {
496 return SHOW_USAGE_MESSAGE
;
499 itemRef
= find_first_generic_password(keychainOrArray
,
509 result
= errSecItemNotFound
;
510 sec_perror("SecKeychainSearchCopyNext", result
);
514 print_keychain_item_attributes(stdout
, itemRef
, FALSE
, FALSE
, FALSE
, FALSE
);
516 result
= SecKeychainItemDelete(itemRef
);
518 fputs("password has been deleted.\n", stderr
);
522 SecKeychainItemFreeContent(NULL
, passwordData
);
530 do_keychain_find_internet_password(CFTypeRef keychainOrArray
,
531 FourCharCode itemCreator
,
532 FourCharCode itemType
,
536 const char *serverName
,
537 const char *securityDomain
,
538 const char *accountName
,
541 SecProtocolType protocol
,
542 SecAuthenticationType authenticationType
,
543 Boolean get_password
,
544 Boolean password_stdout
)
546 OSStatus result
= noErr
;
547 SecKeychainItemRef itemRef
= NULL
;
549 itemRef
= find_first_internet_password(keychainOrArray
,
563 result
= do_password_item_printing(itemRef
, get_password
, password_stdout
);
565 result
= errSecItemNotFound
;
566 sec_perror("SecKeychainSearchCopyNext", result
);
573 do_keychain_delete_internet_password(CFTypeRef keychainOrArray
,
574 FourCharCode itemCreator
,
575 FourCharCode itemType
,
579 const char *serverName
,
580 const char *securityDomain
,
581 const char *accountName
,
584 SecProtocolType protocol
,
585 SecAuthenticationType authenticationType
)
587 OSStatus result
= noErr
;
588 SecKeychainItemRef itemRef
= NULL
;
589 void *passwordData
= NULL
;
591 if (!itemCreator
&& !itemType
&& !kind
&& !comment
&& !label
&& !serverName
&& !securityDomain
&& !accountName
&& !path
&& !port
&& !protocol
&& !authenticationType
) {
592 return SHOW_USAGE_MESSAGE
;
595 itemRef
= find_first_internet_password(keychainOrArray
,
609 result
= errSecItemNotFound
;
610 sec_perror("SecKeychainSearchCopyNext", result
);
614 print_keychain_item_attributes(stdout
, itemRef
, FALSE
, FALSE
, FALSE
, FALSE
);
616 result
= SecKeychainItemDelete(itemRef
);
618 fputs("password has been deleted.\n", stderr
);
622 SecKeychainItemFreeContent(NULL
, passwordData
);
630 do_keychain_find_certificate(CFTypeRef keychainOrArray
,
632 const char *emailAddress
,
638 OSStatus result
= noErr
;
639 SecCertificateRef certificateRef
= NULL
;
640 SecKeychainSearchRef searchRef
= NULL
;
641 CFStringRef matchRef
= (name
) ? CFStringCreateWithCString(NULL
, name
, kCFStringEncodingUTF8
) : NULL
;
643 if (find_all
&& emailAddress
) {
644 result
= SecKeychainSearchCreateForCertificateByEmail(keychainOrArray
, emailAddress
, &searchRef
);
646 sec_perror("SecKeychainSearchCreateForCertificateByEmail", result
);
650 result
= SecKeychainSearchCreateFromAttributes(keychainOrArray
, kSecCertificateItemClass
, NULL
, &searchRef
);
652 sec_perror("SecKeychainSearchCreateFromAttributes", result
);
660 SecKeychainItemRef itemRef
= NULL
;
661 result
= SecKeychainSearchCopyNext(searchRef
, &itemRef
);
662 if (result
== errSecItemNotFound
) {
667 sec_perror("SecKeychainSearchCopyNext", result
);
671 if (!emailAddress
&& name
) {
672 // match name in common name
673 CFStringRef nameRef
= NULL
;
674 if (SecCertificateCopyCommonName((SecCertificateRef
)itemRef
, &nameRef
) != noErr
) {
675 safe_CFRelease(&itemRef
);
676 continue; // no name, so no match is possible
678 CFRange find
= { kCFNotFound
, 0 };
679 if (nameRef
&& matchRef
)
680 find
= CFStringFind(nameRef
, matchRef
, kCFCompareCaseInsensitive
| kCFCompareNonliteral
);
681 if (find
.location
== kCFNotFound
) {
682 safe_CFRelease(&nameRef
);
683 safe_CFRelease(&itemRef
);
684 continue; // no match
686 safe_CFRelease(&nameRef
);
688 safe_CFRelease(&certificateRef
);
689 certificateRef
= (SecCertificateRef
) itemRef
;
691 else { // only want the first match
693 result
= SecCertificateFindByEmail(keychainOrArray
, emailAddress
, &certificateRef
);
695 sec_perror("SecCertificateFindByEmail", result
);
699 SecKeychainItemRef itemRef
= NULL
;
700 while ((result
= SecKeychainSearchCopyNext(searchRef
, &itemRef
)) != errSecItemNotFound
) {
702 // match name in common name
703 CFStringRef nameRef
= NULL
;
704 if (SecCertificateCopyCommonName((SecCertificateRef
)itemRef
, &nameRef
) != noErr
) {
705 safe_CFRelease(&itemRef
);
706 continue; // no name, so no match is possible
708 CFRange find
= { kCFNotFound
, 0 };
709 if (nameRef
&& matchRef
)
710 find
= CFStringFind(nameRef
, matchRef
, kCFCompareCaseInsensitive
| kCFCompareNonliteral
);
711 if (find
.location
== kCFNotFound
) {
712 safe_CFRelease(&nameRef
);
713 safe_CFRelease(&itemRef
);
714 continue; // no match
716 safe_CFRelease(&nameRef
);
718 break; // we have a match!
720 if (result
== errSecItemNotFound
) {
721 sec_perror("SecKeychainSearchCopyNext", result
);
724 certificateRef
= (SecCertificateRef
) itemRef
;
728 // process the found certificate
734 digest
.Length
= sizeof(sha1_hash
);
735 digest
.Data
= sha1_hash
;
736 if ((SecCertificateGetData(certificateRef
, &data
) == noErr
) &&
737 (SecDigestGetData(CSSM_ALGID_SHA1
, &digest
, &data
) == CSSM_OK
)) {
739 size_t len
= digest
.Length
;
740 uint8
*cp
= digest
.Data
;
741 fprintf(stdout
, "SHA-1 hash: ");
742 for(i
=0; i
<len
; i
++) {
743 fprintf(stdout
, "%02X", ((unsigned char *)cp
)[i
]);
745 fprintf(stdout
, "\n");
751 CFArrayRef emailAddresses
= NULL
;
753 result
= SecCertificateCopyEmailAddresses(certificateRef
, &emailAddresses
);
756 sec_perror("SecCertificateCopyEmailAddresses", result
);
760 count
= CFArrayGetCount(emailAddresses
);
761 fputs("email addresses: ", stdout
);
762 for (ix
= 0; ix
< count
; ++ix
)
764 CFStringRef emailAddress
= (CFStringRef
)CFArrayGetValueAtIndex(emailAddresses
, ix
);
771 addr
= CFStringGetCStringPtr(emailAddress
, kCFStringEncodingUTF8
);
774 if (CFStringGetCString(emailAddress
, buffer
, sizeof(buffer
), kCFStringEncodingUTF8
))
778 fprintf(stdout
, "%s", addr
);
782 CFRelease(emailAddresses
);
787 CSSM_DATA certData
= {};
788 result
= SecCertificateGetData(certificateRef
, &certData
);
791 sec_perror("SecCertificateGetData", result
);
795 print_buffer_pem(stdout
, "CERTIFICATE", certData
.Length
, certData
.Data
);
799 print_keychain_item_attributes(stdout
, (SecKeychainItemRef
)certificateRef
, FALSE
, FALSE
, FALSE
, FALSE
);
804 safe_CFRelease(&searchRef
);
805 safe_CFRelease(&certificateRef
);
806 safe_CFRelease(&matchRef
);
812 keychain_delete_internet_password(int argc
, char * const *argv
)
814 char *serverName
= NULL
, *securityDomain
= NULL
, *accountName
= NULL
, *path
= NULL
;
815 char *kind
= NULL
, *label
= NULL
, *comment
= NULL
;
816 FourCharCode itemCreator
= 0, itemType
= 0;
818 SecProtocolType protocol
= 0;
819 SecAuthenticationType authenticationType
= 0;
820 CFTypeRef keychainOrArray
= NULL
;
824 * " -a Match \"account\" string\n"
825 * " -c Match \"creator\" (four-character code)\n"
826 * " -C Match \"type\" (four-character code)\n"
827 * " -d Match \"securityDomain\" string\n"
828 * " -D Match \"kind\" string\n"
829 * " -j Match \"comment\" string\n"
830 * " -l Match \"label\" string\n"
831 * " -p Match \"path\" string\n"
832 * " -P Match port number\n"
833 * " -r Match \"protocol\" (four-character code)\n"
834 * " -s Match \"server\" string\n"
835 * " -t Match \"authenticationType\" (four-character code)\n"
838 while ((ch
= getopt(argc
, argv
, "ha:c:C:d:D:hgj:l:p:P:r:s:t:")) != -1)
843 accountName
= optarg
;
846 result
= parse_fourcharcode(optarg
, &itemCreator
);
847 if (result
) goto cleanup
;
850 result
= parse_fourcharcode(optarg
, &itemType
);
851 if (result
) goto cleanup
;
854 securityDomain
= optarg
;
872 result
= parse_fourcharcode(optarg
, &protocol
);
873 if (result
) goto cleanup
;
879 result
= parse_fourcharcode(optarg
, &authenticationType
);
880 if (result
) goto cleanup
;
884 result
= 2; /* @@@ Return 2 triggers usage message. */
892 keychainOrArray
= keychain_create_array(argc
, argv
);
894 result
= do_keychain_delete_internet_password(keychainOrArray
,
909 CFRelease(keychainOrArray
);
915 keychain_find_internet_password(int argc
, char * const *argv
)
917 char *serverName
= NULL
, *securityDomain
= NULL
, *accountName
= NULL
, *path
= NULL
;
918 char *kind
= NULL
, *label
= NULL
, *comment
= NULL
;
919 FourCharCode itemCreator
= 0, itemType
= 0;
921 SecProtocolType protocol
= 0;
922 SecAuthenticationType authenticationType
= 0;
923 CFTypeRef keychainOrArray
= NULL
;
925 Boolean get_password
= FALSE
;
926 Boolean password_stdout
= FALSE
;
929 * " -a Match \"account\" string\n"
930 * " -c Match \"creator\" (four-character code)\n"
931 * " -C Match \"type\" (four-character code)\n"
932 * " -d Match \"securityDomain\" string\n"
933 * " -D Match \"kind\" string\n"
934 * " -j Match \"comment\" string\n"
935 * " -l Match \"label\" string\n"
936 * " -p Match \"path\" string\n"
937 * " -P Match port number\n"
938 * " -r Match \"protocol\" (four-character code)\n"
939 * " -s Match \"server\" string\n"
940 * " -t Match \"authenticationType\" (four-character code)\n"
941 * " -g Display the password for the item found\n"
942 * " -w Display the password(only) for the item(s) found\n"
945 while ((ch
= getopt(argc
, argv
, "ha:c:C:d:D:hgj:l:p:P:r:s:wt:")) != -1)
950 accountName
= optarg
;
953 result
= parse_fourcharcode(optarg
, &itemCreator
);
954 if (result
) goto cleanup
;
957 result
= parse_fourcharcode(optarg
, &itemType
);
958 if (result
) goto cleanup
;
961 securityDomain
= optarg
;
982 result
= parse_fourcharcode(optarg
, &protocol
);
983 if (result
) goto cleanup
;
990 password_stdout
= TRUE
;
993 result
= parse_fourcharcode(optarg
, &authenticationType
);
994 if (result
) goto cleanup
;
995 /* auth type attribute is special */
996 authenticationType
= OSSwapHostToBigInt32(authenticationType
);
1000 result
= 2; /* @@@ Return 2 triggers usage message. */
1008 keychainOrArray
= keychain_create_array(argc
, argv
);
1010 result
= do_keychain_find_internet_password(keychainOrArray
,
1026 if (keychainOrArray
)
1027 CFRelease(keychainOrArray
);
1033 keychain_delete_generic_password(int argc
, char * const *argv
)
1035 char *serviceName
= NULL
, *accountName
= NULL
;
1036 char *kind
= NULL
, *label
= NULL
, *value
= NULL
, *comment
= NULL
;
1037 FourCharCode itemCreator
= 0, itemType
= 0;
1038 CFTypeRef keychainOrArray
= nil
;
1042 * " -a Match \"account\" string\n"
1043 * " -c Match \"creator\" (four-character code)\n"
1044 * " -C Match \"type\" (four-character code)\n"
1045 * " -D Match \"kind\" string\n"
1046 * " -G Match \"value\" string (generic attribute)\n"
1047 * " -j Match \"comment\" string\n"
1048 * " -l Match \"label\" string\n"
1049 * " -s Match \"service\" string\n"
1052 while ((ch
= getopt(argc
, argv
, "ha:c:C:D:G:j:l:s:g")) != -1)
1057 accountName
= optarg
;
1060 result
= parse_fourcharcode(optarg
, &itemCreator
);
1061 if (result
) goto cleanup
;
1064 result
= parse_fourcharcode(optarg
, &itemType
);
1065 if (result
) goto cleanup
;
1080 serviceName
= optarg
;
1084 result
= 2; /* @@@ Return 2 triggers usage message. */
1092 keychainOrArray
= keychain_create_array(argc
, argv
);
1094 result
= do_keychain_delete_generic_password(keychainOrArray
,
1104 if (keychainOrArray
)
1105 CFRelease(keychainOrArray
);
1111 keychain_find_generic_password(int argc
, char * const *argv
)
1113 char *serviceName
= NULL
, *accountName
= NULL
;
1114 char *kind
= NULL
, *label
= NULL
, *value
= NULL
, *comment
= NULL
;
1115 FourCharCode itemCreator
= 0, itemType
= 0;
1116 CFTypeRef keychainOrArray
= nil
;
1118 Boolean get_password
= FALSE
;
1119 Boolean password_stdout
= FALSE
;
1122 * " -a Match \"account\" string\n"
1123 * " -c Match \"creator\" (four-character code)\n"
1124 * " -C Match \"type\" (four-character code)\n"
1125 * " -D Match \"kind\" string\n"
1126 * " -G Match \"value\" string (generic attribute)\n"
1127 * " -j Match \"comment\" string\n"
1128 * " -l Match \"label\" string\n"
1129 * " -s Match \"service\" string\n"
1130 * " -g Display the password for the item(s) found\n"
1131 * " -w Display the password(only) for the item(s) found\n"
1134 while ((ch
= getopt(argc
, argv
, "ha:c:C:D:G:j:l:s:wg")) != -1)
1139 accountName
= optarg
;
1142 result
= parse_fourcharcode(optarg
, &itemCreator
);
1143 if (result
) goto cleanup
;
1146 result
= parse_fourcharcode(optarg
, &itemType
);
1147 if (result
) goto cleanup
;
1162 serviceName
= optarg
;
1165 password_stdout
= TRUE
;
1166 get_password
= TRUE
;
1169 get_password
= TRUE
;
1173 result
= 2; /* @@@ Return 2 triggers usage message. */
1181 keychainOrArray
= keychain_create_array(argc
, argv
);
1183 result
= do_keychain_find_generic_password(keychainOrArray
,
1195 if (keychainOrArray
)
1196 CFRelease(keychainOrArray
);
1201 #define SetKeyToString(dict, key, arg) \
1203 CFStringRef str = CFStringCreateWithCStringNoCopy(NULL, arg, kCFStringEncodingUTF8, kCFAllocatorNull); \
1204 CFDictionarySetValue(dict, key, str); \
1205 CFReleaseNull(str); \
1209 keychain_find_key(int argc
, char * const *argv
) {
1211 * " -a Match \"application label\" string\n"
1212 * " -c Match \"creator\" (four-character code)\n"
1213 * " -d Match keys that can decrypt\n"
1214 * " -D Match \"description\" string\n"
1215 * " -e Match keys that can encrypt\n"
1216 * " -j Match \"comment\" string\n"
1217 * " -l Match \"label\" string\n"
1218 * " -r Match keys that can derive\n"
1219 * " -s Match keys that can sign\n"
1220 * " -t Type of key to find: one of \"symmetric\", \"public\", or \"private\"\n"
1221 * " -u Match keys that can unwrap\n"
1222 * " -v Match keys that can verify\n"
1223 * " -w Match keys that can wrap\n"
1226 CFMutableDictionaryRef query
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1227 CFDictionarySetValue(query
, kSecClass
, kSecClassKey
);
1228 CFDictionarySetValue(query
, kSecMatchLimit
, kSecMatchLimitAll
);
1230 CFTypeRef results
= NULL
;
1233 while ((ch
= getopt(argc
, argv
, "a:c:dD:ej:l:rst:uvw")) != -1)
1238 SetKeyToString(query
, kSecAttrApplicationLabel
, optarg
);
1241 SetKeyToString(query
, kSecAttrCreator
, optarg
);
1244 CFDictionarySetValue(query
, kSecAttrCanDecrypt
, kCFBooleanTrue
);
1247 SetKeyToString(query
, kSecAttrDescription
, optarg
);
1250 CFDictionarySetValue(query
, kSecAttrCanEncrypt
, kCFBooleanTrue
);
1253 SetKeyToString(query
, kSecAttrComment
, optarg
);
1256 SetKeyToString(query
, kSecAttrLabel
, optarg
);
1259 CFDictionarySetValue(query
, kSecAttrCanDerive
, kCFBooleanTrue
);
1262 CFDictionarySetValue(query
, kSecAttrCanSign
, kCFBooleanTrue
);
1265 if(strcmp(optarg
, "symmetric") == 0) {
1266 CFDictionarySetValue(query
, kSecAttrKeyClass
, kSecAttrKeyClassSymmetric
);
1267 } else if(strcmp(optarg
, "public") == 0) {
1268 CFDictionarySetValue(query
, kSecAttrKeyClass
, kSecAttrKeyClassPublic
);
1269 } else if(strcmp(optarg
, "private") == 0) {
1270 CFDictionarySetValue(query
, kSecAttrKeyClass
, kSecAttrKeyClassPrivate
);
1277 CFDictionarySetValue(query
, kSecAttrCanUnwrap
, kCFBooleanTrue
);
1280 CFDictionarySetValue(query
, kSecAttrCanVerify
, kCFBooleanTrue
);
1283 CFDictionarySetValue(query
, kSecAttrCanWrap
, kCFBooleanTrue
);
1295 CFTypeRef keychainOrArray
= keychain_create_array(argc
, argv
);
1297 if(keychainOrArray
&& CFGetTypeID(keychainOrArray
) == CFArrayGetTypeID()) {
1298 CFDictionarySetValue(query
, kSecMatchSearchList
, keychainOrArray
);
1299 } else if(keychainOrArray
) {
1300 // if it's not an array (but is something), it's a keychain. Put it in an array.
1301 CFMutableArrayRef searchList
= (CFMutableArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 1, &kCFTypeArrayCallBacks
);
1302 CFArrayAppendValue((CFMutableArrayRef
)searchList
, keychainOrArray
);
1303 CFDictionarySetValue(query
, kSecMatchSearchList
, searchList
);
1304 CFRelease(searchList
);
1306 CFReleaseNull(keychainOrArray
);
1308 OSStatus status
= SecItemCopyMatching(query
, &results
);
1310 sec_perror("SecItemCopyMatching", status
);
1315 if (CFGetTypeID(results
) == CFArrayGetTypeID()) {
1316 for(int i
= 0; i
< CFArrayGetCount(results
); i
++) {
1317 SecKeychainItemRef item
= (SecKeychainItemRef
) CFArrayGetValueAtIndex(results
, i
);
1319 print_keychain_item_attributes(stdout
, item
, FALSE
, FALSE
, FALSE
, FALSE
);
1324 safe_CFRelease(&results
);
1325 safe_CFRelease(&query
);
1329 // Declare here to use later.
1330 int keychain_set_partition_list(SecKeychainRef kc
, CFDictionaryRef query
, CFStringRef password
, CFStringRef partitionlist
);
1331 int keychain_parse_args_and_set_partition_list(int argc
, char * const *argv
, CFMutableDictionaryRef query
, CFStringRef partitionidsinput
, CFStringRef password
);
1333 int keychain_set_internet_password_partition_list(int argc
, char * const *argv
) {
1335 * " -a Match \"account\" string\n"
1336 * " -c Match \"creator\" (four-character code)\n"
1337 * " -C Match \"type\" (four-character code)\n"
1338 * " -d Match \"securityDomain\" string\n"
1339 * " -D Match \"kind\" string\n"
1340 * " -j Match \"comment\" string\n"
1341 * " -l Match \"label\" string\n"
1342 * " -p Match \"path\" string\n"
1343 * " -P Match port number\n"
1344 * " -r Match \"protocol\" (four-character code)\n"
1345 * " -s Match \"server\" string\n"
1346 * " -t Match \"authenticationType\" (four-character code)\n"
1347 * " -S Comma-separated list of allowed partition IDs"
1348 * " -k password for keychain"
1351 CFMutableDictionaryRef query
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1352 CFDictionarySetValue(query
, kSecClass
, kSecClassInternetPassword
);
1353 CFDictionarySetValue(query
, kSecMatchLimit
, kSecMatchLimitAll
);
1355 CFStringRef partitionidsinput
= NULL
;
1356 CFStringRef password
= NULL
;
1359 while ((ch
= getopt(argc
, argv
, "a:c:C:d:D:j:l:p:P:r:s:S:t:k:")) != -1)
1364 SetKeyToString(query
, kSecAttrAccount
, optarg
);
1367 SetKeyToString(query
, kSecAttrCreator
, optarg
);
1370 SetKeyToString(query
, kSecAttrType
, optarg
);
1373 SetKeyToString(query
, kSecAttrSecurityDomain
, optarg
);
1376 SetKeyToString(query
, kSecAttrDescription
, optarg
);
1379 SetKeyToString(query
, kSecAttrComment
, optarg
);
1382 SetKeyToString(query
, kSecAttrLabel
, optarg
);
1385 SetKeyToString(query
, kSecAttrPath
, optarg
);
1388 SetKeyToString(query
, kSecAttrPort
, optarg
);
1391 SetKeyToString(query
, kSecAttrProtocol
, optarg
);
1394 SetKeyToString(query
, kSecAttrServer
, optarg
);
1397 SetKeyToString(query
, kSecAttrAuthenticationType
, optarg
);
1400 CFReleaseNull(partitionidsinput
);
1401 partitionidsinput
= CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1404 CFReleaseNull(password
);
1405 password
= CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1417 result
= keychain_parse_args_and_set_partition_list(argc
, argv
, query
, partitionidsinput
, password
);
1420 safe_CFRelease(&password
);
1421 safe_CFRelease(&partitionidsinput
);
1422 safe_CFRelease(&query
);
1427 keychain_set_generic_password_partition_list(int argc
, char * const *argv
) {
1428 CFMutableDictionaryRef query
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1430 // -a Match \"account\" string
1431 // -c Match \"creator\" (four-character code)
1432 // -C Match \"type\" (four-character code)
1433 // -D Match \"kind\" string
1434 // -G Match \"value\" string (generic attribute)
1435 // -j Match \"comment\" string
1436 // -l Match \"label\" string
1437 // -s Match \"service\" string
1438 // -S Comma-separated list of allowed partition IDs
1439 // -k password for keychain
1441 CFDictionarySetValue(query
, kSecClass
, kSecClassGenericPassword
);
1442 CFDictionarySetValue(query
, kSecMatchLimit
, kSecMatchLimitAll
);
1444 CFStringRef partitionidsinput
= NULL
;
1445 CFStringRef password
= NULL
;
1448 while ((ch
= getopt(argc
, argv
, ":a:c:C:D:G:j:l:s:S:k:")) != -1)
1453 SetKeyToString(query
, kSecAttrAccount
, optarg
);
1456 SetKeyToString(query
, kSecAttrCreator
, optarg
);
1459 SetKeyToString(query
, kSecAttrType
, optarg
);
1462 SetKeyToString(query
, kSecAttrDescription
, optarg
);
1465 SetKeyToString(query
, kSecAttrGeneric
, optarg
);
1468 SetKeyToString(query
, kSecAttrComment
, optarg
);
1471 SetKeyToString(query
, kSecAttrLabel
, optarg
);
1474 SetKeyToString(query
, kSecAttrService
, optarg
);
1477 CFReleaseNull(partitionidsinput
);
1478 partitionidsinput
= CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1481 CFReleaseNull(password
);
1482 password
= CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1486 // They supplied the -k but with no data
1487 // Leaving it null will cause prompt below
1488 if (optopt
== 'k') {
1492 goto cleanup
; /* @@@ Return 2 triggers usage message. */
1502 result
= keychain_parse_args_and_set_partition_list(argc
, argv
, query
, partitionidsinput
, password
);
1505 safe_CFRelease(&password
);
1506 safe_CFRelease(&partitionidsinput
);
1507 safe_CFRelease(&query
);
1512 keychain_set_key_partition_list(int argc
, char * const *argv
) {
1514 * " -a Match \"application label\" string\n"
1515 * " -c Match \"creator\" (four-character code)\n"
1516 * " -d Match keys that can decrypt\n"
1517 * " -D Match \"description\" string\n"
1518 * " -e Match keys that can encrypt\n"
1519 * " -j Match \"comment\" string\n"
1520 * " -l Match \"label\" string\n"
1521 * " -r Match keys that can derive\n"
1522 * " -s Match keys that can sign\n"
1523 * " -t Type of key to find: one of \"symmetric\", \"public\", or \"private\"\n"
1524 * " -u Match keys that can unwrap\n"
1525 * " -v Match keys that can verify\n"
1526 * " -w Match keys that can wrap\n"
1527 * " -S Comma-separated list of allowed partition IDs
1528 * " -k password for keychain (required)
1531 CFMutableDictionaryRef query
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1532 CFDictionarySetValue(query
, kSecClass
, kSecClassKey
);
1533 CFDictionarySetValue(query
, kSecMatchLimit
, kSecMatchLimitAll
);
1535 CFStringRef partitionidsinput
= NULL
;
1536 CFStringRef password
= NULL
;
1539 while ((ch
= getopt(argc
, argv
, ":a:c:dD:ej:k:l:rsS:t:uvw")) != -1)
1544 SetKeyToString(query
, kSecAttrApplicationLabel
, optarg
);
1547 SetKeyToString(query
, kSecAttrCreator
, optarg
);
1550 SetKeyToString(query
, kSecAttrCanDecrypt
, optarg
);
1551 CFDictionarySetValue(query
, kSecAttrCanDecrypt
, kCFBooleanTrue
);
1554 SetKeyToString(query
, kSecAttrDescription
, optarg
);
1557 CFDictionarySetValue(query
, kSecAttrCanEncrypt
, kCFBooleanTrue
);
1560 SetKeyToString(query
, kSecAttrComment
, optarg
);
1563 SetKeyToString(query
, kSecAttrLabel
, optarg
);
1566 CFDictionarySetValue(query
, kSecAttrCanDerive
, kCFBooleanTrue
);
1568 CFDictionarySetValue(query
, kSecAttrCanSign
, kCFBooleanTrue
);
1571 if(strcmp(optarg
, "symmetric") == 0) {
1572 CFDictionarySetValue(query
, kSecAttrKeyClass
, kSecAttrKeyClassSymmetric
);
1573 } else if(strcmp(optarg
, "public") == 0) {
1574 CFDictionarySetValue(query
, kSecAttrKeyClass
, kSecAttrKeyClassPublic
);
1575 } else if(strcmp(optarg
, "private") == 0) {
1576 CFDictionarySetValue(query
, kSecAttrKeyClass
, kSecAttrKeyClassPrivate
);
1583 CFDictionarySetValue(query
, kSecAttrCanUnwrap
, kCFBooleanTrue
);
1586 CFDictionarySetValue(query
, kSecAttrCanVerify
, kCFBooleanTrue
);
1589 CFDictionarySetValue(query
, kSecAttrCanWrap
, kCFBooleanTrue
);
1592 CFReleaseNull(partitionidsinput
);
1593 partitionidsinput
= CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1596 CFReleaseNull(password
);
1597 password
= CFStringCreateWithCStringNoCopy(NULL
, optarg
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1601 // They supplied the -k but with no data
1602 // Leaving it null will cause prompt below
1603 if (optopt
== 'k') {
1607 goto cleanup
; /* @@@ Return 2 triggers usage message. */
1617 result
= keychain_parse_args_and_set_partition_list(argc
, argv
, query
, partitionidsinput
, password
);
1620 CFReleaseNull(partitionidsinput
);
1621 CFReleaseNull(password
);
1622 safe_CFRelease(&query
);
1627 int keychain_parse_args_and_set_partition_list(int argc
, char * const *argv
, CFMutableDictionaryRef query
, CFStringRef partitionidsinput
, CFStringRef password
) {
1629 const char *keychainName
= NULL
;
1630 SecKeychainRef kc
= NULL
;
1631 CFStringRef localPassword
= NULL
;
1633 // if we were given a keychain, use it
1636 keychainName
= argv
[0];
1637 if (*keychainName
== '\0')
1643 kc
= keychain_open(keychainName
);
1645 sec_error("couldn't open \"%s\"", keychainName
);
1650 CFMutableArrayRef searchList
= (CFMutableArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 1, &kCFTypeArrayCallBacks
);
1651 CFArrayAppendValue((CFMutableArrayRef
)searchList
, kc
);
1652 CFDictionarySetValue(query
, kSecMatchSearchList
, searchList
);
1653 } else if (argc
!= 0) {
1658 if(!partitionidsinput
) {
1664 char* cpassword
= prompt_password(keychainName
);
1669 localPassword
= CFStringCreateWithCString(NULL
, cpassword
, kCFStringEncodingUTF8
);
1670 password
= localPassword
;
1674 result
= keychain_set_partition_list(kc
, query
, password
, partitionidsinput
);
1677 CFReleaseNull(localPassword
);
1682 int keychain_set_partition_list(SecKeychainRef kc
, CFDictionaryRef query
, CFStringRef password
, CFStringRef partitionlist
) {
1685 char *passwordBuf
= NULL
;
1687 GetCStringFromCFString(password
, &passwordBuf
, &passwordLen
);
1690 CFTypeRef results
= NULL
;
1692 // Unlock the keychain with the given password, since we'll be fetching ACLs
1693 status
= SecKeychainUnlock(kc
, (UInt32
) passwordLen
, passwordBuf
, true);
1695 sec_perror("SecKeychainUnlock", status
);
1700 status
= SecItemCopyMatching(query
, &results
);
1702 sec_perror("SecItemCopyMatching", status
);
1712 if (CFGetTypeID(results
) == CFArrayGetTypeID()) {
1713 for(int i
= 0; i
< CFArrayGetCount(results
); i
++) {
1714 SecKeychainItemRef item
= (SecKeychainItemRef
) CFArrayGetValueAtIndex(results
, i
);
1715 SecAccessRef access
= NULL
;
1717 do_password_item_printing(item
, false, false);
1719 status
= SecKeychainItemCopyAccess(item
, &access
);
1720 if (status
== errSecNoAccessForItem
) {
1724 sec_perror("SecKeychainItemCopyAccess", status
);
1729 CFArrayRef aclList
= NULL
;
1730 status
= SecAccessCopyACLList(access
, &aclList
);
1733 sec_perror("SecAccessCopyACLList", status
);
1738 CFIndex size
= CFArrayGetCount(aclList
);
1739 for(CFIndex i
= 0; i
< size
; i
++) {
1740 SecACLRef acl
= (SecACLRef
) CFArrayGetValueAtIndex(aclList
, i
);
1741 CSSM_ACL_AUTHORIZATION_TAG tags
[64]; // Pick some upper limit
1742 uint32 tagix
, tagCount
= sizeof(tags
) / sizeof(*tags
);
1743 status
= SecACLGetAuthorizations(acl
, tags
, &tagCount
);
1747 sec_perror("SecACLGetAuthorizations", status
);
1752 CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector
= {};
1754 for (tagix
= 0; tagix
< tagCount
; ++tagix
)
1756 CSSM_ACL_AUTHORIZATION_TAG tag
= tags
[tagix
];
1757 if(tag
== CSSM_ACL_AUTHORIZATION_PARTITION_ID
) {
1759 CFArrayRef applicationList
;
1760 CFStringRef promptDescription
;
1762 status
= SecACLCopySimpleContents(acl
, &applicationList
, &promptDescription
, &promptSelector
);
1764 sec_perror("SecACLCopySimpleContents", status
);
1769 CFArrayRef partitionIDs
= CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault
, partitionlist
, CFSTR(","));
1770 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1771 CFDictionarySetValue(dict
, CFSTR("Partitions"), partitionIDs
);
1772 CFDataRef xml
= CFPropertyListCreateXMLData(NULL
, dict
);
1773 CFStringRef xmlstr
= cfToHex(xml
);
1775 SecACLSetSimpleContents(acl
, applicationList
, xmlstr
, &promptSelector
);
1777 safe_CFRelease(&xmlstr
);
1778 safe_CFRelease(&xml
);
1779 safe_CFRelease(&dict
);
1780 safe_CFRelease(&partitionIDs
);
1785 status
= SecKeychainItemSetAccessWithPassword(item
, access
, (UInt32
) passwordLen
, passwordBuf
);
1787 sec_perror("SecKeychainItemSetAccessWithPassword", status
);
1800 safe_CFRelease(&results
);
1808 keychain_find_certificate(int argc
, char * const *argv
)
1810 char *emailAddress
= NULL
;
1813 CFTypeRef keychainOrArray
= nil
;
1814 Boolean output_pem
= FALSE
;
1815 Boolean find_all
= FALSE
;
1816 Boolean print_hash
= FALSE
;
1817 Boolean print_email
= FALSE
;
1819 while ((ch
= getopt(argc
, argv
, "hac:e:mpZ")) != -1)
1830 emailAddress
= optarg
;
1843 result
= 2; /* @@@ Return 2 triggers usage message. */
1851 keychainOrArray
= keychain_create_array(argc
, argv
);
1853 result
= do_keychain_find_certificate(keychainOrArray
, name
, emailAddress
, print_hash
, output_pem
, find_all
, print_email
);
1856 if (keychainOrArray
)
1857 CFRelease(keychainOrArray
);
1864 do_keychain_dump_class(FILE *stream
, CFTypeRef keychainOrArray
, SecItemClass itemClass
, Boolean show_data
, Boolean show_raw_data
, Boolean show_acl
, Boolean interactive
)
1866 SecKeychainItemRef item
;
1867 SecKeychainSearchRef search
= NULL
;
1871 status
= SecKeychainSearchCreateFromAttributes(keychainOrArray
, itemClass
, NULL
, &search
);
1874 sec_perror("SecKeychainSearchCreateFromAttributes", status
);
1879 while ((status
= SecKeychainSearchCopyNext(search
, &item
)) == 0)
1881 print_keychain_item_attributes(stream
, item
, show_data
, show_raw_data
, show_acl
, interactive
);
1885 if (status
!= errSecItemNotFound
)
1887 sec_perror("SecKeychainSearchCopyNext", status
);
1900 do_keychain_dump(FILE *stream
, CFTypeRef keychainOrArray
, Boolean show_data
, Boolean show_raw_data
, Boolean show_acl
, Boolean interactive
)
1902 return do_keychain_dump_class(stream
, keychainOrArray
, CSSM_DL_DB_RECORD_ANY
, show_data
, show_raw_data
, show_acl
, interactive
);
1906 keychain_dump(int argc
, char * const *argv
)
1909 Boolean show_data
= FALSE
, show_raw_data
= FALSE
, show_acl
= FALSE
, interactive
= FALSE
;
1910 CFTypeRef keychainOrArray
= NULL
;
1911 const char *outputFilename
= NULL
;
1914 while ((ch
= getopt(argc
, argv
, "adhiro:")) != -1)
1929 show_raw_data
= TRUE
;
1932 outputFilename
= optarg
;
1936 return SHOW_USAGE_MESSAGE
;
1943 keychainOrArray
= keychain_create_array(argc
, argv
);
1946 output
= fopen(outputFilename
, "w");
1950 result
= do_keychain_dump(output
, keychainOrArray
, show_data
, show_raw_data
, show_acl
, interactive
);
1955 if (keychainOrArray
)
1956 CFRelease(keychainOrArray
);