2 * Copyright (c) 2003-2008 Apple Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please
7 * obtain a copy of the License at http://www.apple.com/publicsource and
8 * read it before using this file.
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
12 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
13 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
15 * Please see the License for the specific language governing rights and
16 * limitations under the License.
20 * identPicker.cp - Given a keychain, select from possible multiple
21 * SecIdentityRefs via stdio UI, and cook up a
22 * CFArray containing that identity and all certs needed
23 * for cert verification by an SSL peer. The resulting
24 * CFArrayRef is suitable for passing to SSLSetCertificate().
27 #include "identPicker.h"
28 #include "sslAppUtils.h"
29 #include <sys/param.h>
36 * -- guaranteed no buffer overflow
37 * -- guaranteed NULL-terminated string
38 * -- handles empty string (i.e., response is just CR) properly
48 for(dex
=0; dex
<bufSize
-1; dex
++) {
66 * Obtain the printable name of a SecKeychainItemRef as a C string.
67 * Caller must free() the result.
69 char *kcItemPrintableName(
70 SecKeychainItemRef itemRef
)
74 /* just search for the one attr we want */
75 UInt32 tag
= kSecLabelItemAttr
;
76 SecKeychainAttributeInfo attrInfo
;
79 attrInfo
.format
= NULL
;
80 SecKeychainAttributeList
*attrList
= NULL
;
81 SecKeychainAttribute
*attr
= NULL
;
83 OSStatus ortn
= SecKeychainItemCopyAttributesAndData(
88 NULL
, // length - don't need the data
91 cssmPerror("SecKeychainItemCopyAttributesAndData", ortn
);
92 /* may want to be a bit more robust here, but this should
94 return strdup("Unnamed KeychainItem");
96 /* subsequent errors to errOut: */
98 if((attrList
== NULL
) || (attrList
->count
!= 1)) {
99 printf("***Unexpected result fetching label attr\n");
100 crtn
= strdup("Unnamed KeychainItem");
103 /* We're assuming 8-bit ASCII attribute data here... */
104 attr
= attrList
->attr
;
105 crtn
= (char *)malloc(attr
->length
+ 1);
106 memmove(crtn
, attr
->data
, attr
->length
);
107 crtn
[attr
->length
] = '\0';
110 SecKeychainItemFreeAttributesAndData(attrList
, NULL
);
115 * Get the final term of a keychain's path as a C string. Caller must free()
119 SecKeychainRef kcRef
)
121 char fullPath
[MAXPATHLEN
+ 1];
123 UInt32 pathLen
= MAXPATHLEN
;
125 ortn
= SecKeychainGetPath(kcRef
, &pathLen
, fullPath
);
127 cssmPerror("SecKeychainGetPath", ortn
);
128 return strdup("orphan keychain");
131 /* NULL terminate the path string and search for final '/' */
132 fullPath
[pathLen
] = '\0';
133 char *lastSlash
= NULL
;
134 char *thisSlash
= fullPath
;
136 thisSlash
= strchr(thisSlash
, '/');
137 if(thisSlash
== NULL
) {
142 lastSlash
= thisSlash
;
143 } while(thisSlash
!= NULL
);
144 if(lastSlash
== NULL
) {
145 /* no slashes, odd, but handle it */
146 return strdup(fullPath
);
149 return strdup(lastSlash
);
154 * Obtain the final term of a keychain item's keychain path as a C string.
155 * Caller must free() the result.
156 * May well return NULL indicating the item has no keychain (e.g. az floating cert).
158 char *kcItemKcFileName(SecKeychainItemRef itemRef
)
161 SecKeychainRef kcRef
= NULL
;
163 ortn
= SecKeychainItemCopyKeychain(itemRef
, &kcRef
);
167 char *rtnStr
= kcFileName(kcRef
);
173 * Given an array of SecIdentityRefs:
174 * -- display a printable name of each identity's cert;
175 * -- prompt user to select which one to use;
177 * Returns CFIndex of desired identity. A return of <0 indicates
180 static CFIndex
pickIdent(
183 CFIndex count
= CFArrayGetCount(idArray
);
188 printf("***sslIdentPicker screwup: no identities found\n");
191 for(dex
=0; dex
<count
; dex
++) {
192 SecIdentityRef idRef
= (SecIdentityRef
)CFArrayGetValueAtIndex(idArray
, dex
);
193 SecCertificateRef certRef
;
194 ortn
= SecIdentityCopyCertificate(idRef
, &certRef
);
196 /* should never happen */
197 cssmPerror("SecIdentityCopyCertificate", ortn
);
201 /* get printable name of cert and the keychain it's in */
202 char *certLabel
= kcItemPrintableName((SecKeychainItemRef
)certRef
);
203 SecKeychainRef kcRef
;
205 ortn
= SecKeychainItemCopyKeychain((SecKeychainItemRef
)certRef
, &kcRef
);
207 cssmPerror("SecKeychainItemCopyKeychain", ortn
);
208 kcLabel
= (char *)"Unnamed keychain";
211 kcLabel
= kcFileName(kcRef
);
213 printf("[%ld] keychain : %s\n", dex
, kcLabel
);
214 printf(" cert : %s\n", certLabel
);
224 printf("\nEnter Certificate number or CR to quit : ");
227 getString(resp
, sizeof(resp
));
228 if(resp
[0] == '\0') {
231 int ires
= atoi(resp
);
232 if((ires
>= 0) && (ires
< count
)) {
233 return (CFIndex
)ires
;
235 printf("***Invalid entry. Type a number between 0 and %ld\n",
241 OSStatus
sslSimpleIdentPicker(
242 SecKeychainRef kcRef
, // NULL means use default list
243 SecIdentityRef
*ident
) // RETURNED
246 CFMutableArrayRef idArray
= NULL
; // holds all SecIdentityRefs found
248 /* Search for all identities */
250 SecIdentitySearchRef srchRef
= nil
;
251 ortn
= SecIdentitySearchCreate(kcRef
,
255 cssmPerror("SecIdentitySearchCreate", (CSSM_RETURN
)ortn
);
256 printf("Cannot find signing key in keychain.\n");
260 /* get all identities, stuff them into idArray */
261 SecIdentityRef identity
= nil
;
262 idArray
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
264 ortn
= SecIdentitySearchCopyNext(srchRef
, &identity
);
268 CFArrayAppendValue(idArray
, identity
);
270 /* the array has the retain count we need */
272 } while(ortn
== noErr
);
276 case errSecItemNotFound
:
277 if(CFArrayGetCount(idArray
) == 0) {
278 printf("No signing keys found in keychain.\n");
279 return errSecItemNotFound
;
282 /* found at least one; proceed */
286 cssmPerror("SecIdentitySearchCopyNext", (CSSM_RETURN
)ortn
);
287 printf("Cannot find signing key in keychain.\n");
292 * If there is just one, use it without asking
295 if(CFArrayGetCount(idArray
) == 1) {
299 whichId
= pickIdent(idArray
);
301 return CSSMERR_CSSM_USER_CANCELED
;
305 /* keep this one, free the rest */
306 identity
= (SecIdentityRef
)CFArrayGetValueAtIndex(idArray
, whichId
);
313 OSStatus
sslIdentPicker(
314 SecKeychainRef kcRef
, // NULL means use default list
315 SecCertificateRef trustedAnchor
, // optional additional trusted anchor
316 bool includeRoot
, // true --> root is appended to outArray
317 // false --> root not included
318 const CSSM_OID
*vfyPolicy
, // optional - if NULL, use SSL
319 CFArrayRef
*outArray
) // created and RETURNED
322 SecIdentityRef identity
;
324 ortn
= sslSimpleIdentPicker(kcRef
, &identity
);
328 return sslCompleteCertChain(identity
, trustedAnchor
, includeRoot
,
329 vfyPolicy
, outArray
);