2 * Copyright (c) 2004-2006 Apple Computer, 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@
25 * keyPicker.cpp - select a key pair from a keychain
28 #include "keyPicker.h"
29 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
30 #include <Security/Security.h>
33 #include <clAppUtils/identPicker.h> /* for kcFileName() */
37 * Obtain either public key hash or PrintName for a given SecKeychainItem. Works on public keys,
38 * private keys, identities, and certs. Caller must release the returned result.
40 OSStatus
getKcItemAttr(
41 SecKeychainItemRef kcItem
,
43 CFDataRef
*rtnAttr
) /* RETURNED */
45 /* main job is to figure out which attrType to ask for, and from what Sec item */
46 SecKeychainItemRef attrFromThis
;
47 SecKeychainAttrType attrType
= 0;
49 bool releaseKcItem
= false;
51 CFTypeID cfId
= CFGetTypeID(kcItem
);
52 if(cfId
== SecIdentityGetTypeID()) {
53 /* switch over to cert */
54 ortn
= SecIdentityCopyCertificate((SecIdentityRef
)kcItem
,
55 (SecCertificateRef
*)&attrFromThis
);
57 cssmPerror("SecIdentityCopyCertificate", ortn
);
59 kcItem
= attrFromThis
;
61 cfId
= SecCertificateGetTypeID();
64 if(cfId
== SecCertificateGetTypeID()) {
67 attrType
= kSecPublicKeyHashItemAttr
;
70 attrType
= kSecLabelItemAttr
;
73 printf("getKcItemAttr: WhichAttr\n");
77 else if(cfId
== SecKeyGetTypeID()) {
80 attrType
= kSecKeyLabel
;
83 attrType
= kSecKeyPrintName
;
86 printf("getKcItemAttr: WhichAttr\n");
91 SecKeychainAttributeInfo attrInfo
;
93 attrInfo
.tag
= &attrType
;
94 attrInfo
.format
= NULL
; // ???
95 SecKeychainAttributeList
*attrList
= NULL
;
97 ortn
= SecKeychainItemCopyAttributesAndData(
102 NULL
, // don't need the data
108 cssmPerror("SecKeychainItemCopyAttributesAndData", ortn
);
111 SecKeychainAttribute
*attr
= attrList
->attr
;
112 *rtnAttr
= CFDataCreate(NULL
, (UInt8
*)attr
->data
, attr
->length
);
113 SecKeychainItemFreeAttributesAndData(attrList
, NULL
);
118 * Class representing one key in the keychain.
123 PickerKey(SecKeyRef keyRef
);
126 bool isUsed() { return mIsUsed
;}
127 void isUsed(bool u
) { mIsUsed
= u
; }
128 bool isPrivate() { return mIsPrivate
; }
129 CFDataRef
getPrintName() { return mPrintName
; }
130 CFDataRef
getPubKeyHash() { return mPubKeyHash
; }
131 SecKeyRef
keyRef() { return mKeyRef
; }
133 PickerKey
*partnerKey() { return mPartner
; }
134 void partnerKey(PickerKey
*pk
) { mPartner
= pk
; }
135 char *kcFile() { return mKcFile
; }
139 CFDataRef mPrintName
;
140 CFDataRef mPubKeyHash
;
141 bool mIsPrivate
; // private/public key
142 bool mIsUsed
; // has been spoken for
143 PickerKey
*mPartner
; // other member of public/private pair
144 char *mKcFile
; // file name of keychain this lives on
147 PickerKey::PickerKey(SecKeyRef keyRef
)
156 if(CFGetTypeID(keyRef
) != SecKeyGetTypeID()) {
157 throw std::invalid_argument("not a key");
160 OSStatus ortn
= getKcItemAttr((SecKeychainItemRef
)keyRef
, WA_Hash
, &mPubKeyHash
);
162 throw std::invalid_argument("pub key hash not available");
164 ortn
= getKcItemAttr((SecKeychainItemRef
)keyRef
, WA_PrintName
, &mPrintName
);
166 throw std::invalid_argument("pub key hash not available");
169 const CSSM_KEY
*cssmKey
;
170 ortn
= SecKeyGetCSSMKey(keyRef
, &cssmKey
);
172 /* should never happen */
173 cssmPerror("SecKeyGetCSSMKey", ortn
);
174 throw std::invalid_argument("SecKeyGetCSSMKey error");
176 if(cssmKey
->KeyHeader
.KeyClass
== CSSM_KEYCLASS_PRIVATE_KEY
) {
180 /* stash name of the keychain this lives on */
181 SecKeychainRef kcRef
;
182 ortn
= SecKeychainItemCopyKeychain((SecKeychainItemRef
)keyRef
, &kcRef
);
184 cssmPerror("SecKeychainItemCopyKeychain", ortn
);
185 mKcFile
= strdup("Unnamed keychain");
188 mKcFile
= kcFileName(kcRef
);
195 PickerKey::~PickerKey()
201 CFRelease(mPubKeyHash
);
204 CFRelease(mPrintName
);
211 typedef std::vector
<PickerKey
*> KeyVector
;
214 * add PickerKey objects of specified type to a KeyVector.
216 static void getPickerKeys(
217 SecKeychainRef kcRef
,
218 SecItemClass itemClass
, // actually CSSM_DL_DB_RECORD_{PRIVATE,PRIVATE}_KEY for now
219 KeyVector
&keyVector
)
221 SecKeychainSearchRef srchRef
= NULL
;
222 SecKeychainItemRef kcItem
;
224 OSStatus ortn
= SecKeychainSearchCreateFromAttributes(kcRef
,
229 cssmPerror("SecKeychainSearchCreateFromAttributes", ortn
);
233 ortn
= SecKeychainSearchCopyNext(srchRef
, &kcItem
);
238 PickerKey
*pickerKey
= new PickerKey((SecKeyRef
)kcItem
);
239 keyVector
.push_back(pickerKey
);
242 printf("**** key item that failed PickerKey construct ***\n");
245 } while(ortn
== noErr
);
250 * Print contents of a CFData assuming it's printable
252 static void printCfData(CFDataRef cfd
)
254 CFIndex len
= CFDataGetLength(cfd
);
255 const UInt8
*cp
= CFDataGetBytePtr(cfd
);
256 for(CFIndex dex
=0; dex
<len
; dex
++) {
268 SecKeychainRef kcRef
, // NULL means the default list
269 SecKeyRef
*pubKey
, // RETURNED
270 SecKeyRef
*privKey
) // RETURNED
273 /* First create a arrays of all of the keys, parsed and ready for use */
275 std::vector
<PickerKey
*> privKeys
;
276 std::vector
<PickerKey
*> pubKeys
;
277 getPickerKeys(kcRef
, CSSM_DL_DB_RECORD_PRIVATE_KEY
, privKeys
);
278 getPickerKeys(kcRef
, CSSM_DL_DB_RECORD_PUBLIC_KEY
, pubKeys
);
280 /* now interate thru private keys, looking for a partner for each one */
282 unsigned numPrivKeys
= privKeys
.size();
283 unsigned numPubKeys
= pubKeys
.size();
285 for(unsigned privDex
=0; privDex
<numPrivKeys
; privDex
++) {
286 PickerKey
*privPk
= privKeys
[privDex
];
287 CFDataRef privHash
= privPk
->getPubKeyHash();
288 for(unsigned pubDex
=0; pubDex
<numPubKeys
; pubDex
++) {
289 PickerKey
*pubPk
= pubKeys
[pubDex
];
290 if(pubPk
->isUsed()) {
291 /* already spoken for */
294 if(!CFEqual(privHash
, pubPk
->getPubKeyHash())) {
295 /* public key hashes don't match */
300 pubPk
->partnerKey(privPk
);
301 privPk
->partnerKey(pubPk
);
303 privPk
->isUsed(true);
306 printf("[%d] privKey : ", numPairs
); printCfData(privPk
->getPrintName()); printf("\n");
307 printf(" pubKey : "); printCfData(pubPk
->getPrintName());printf("\n");
308 printf(" keychain : %s\n", privPk
->kcFile());
315 printf("*** keyPicker: no key pairs found.\n");
319 OSStatus ortn
= noErr
;
323 printf("\nEnter key pair number or CR to quit : ");
326 getString(resp
, sizeof(resp
));
327 if(resp
[0] == '\0') {
328 ortn
= CSSMERR_CSSM_USER_CANCELED
;
332 if((ires
< 0) || (ires
>= numPairs
)) {
333 printf("***Invalid entry. Type a number between 0 and %d\n", numPairs
-1);
340 /* find the ires'th partnered private key */
342 for(unsigned privDex
=0; privDex
<numPrivKeys
; privDex
++) {
343 PickerKey
*privPk
= privKeys
[privDex
];
344 if(!privPk
->isUsed()) {
347 if(goodOnes
== ires
) {
349 *privKey
= privPk
->keyRef();
350 *pubKey
= privPk
->partnerKey()->keyRef();
356 /* clean out PickerKey arrays */
357 for(unsigned privDex
=0; privDex
<numPrivKeys
; privDex
++) {
358 delete privKeys
[privDex
];
360 for(unsigned pubDex
=0; pubDex
<numPubKeys
; pubDex
++) {
361 delete pubKeys
[pubDex
];