]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/clAppUtils/keyPicker.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / SecurityTests / clxutils / clAppUtils / keyPicker.cpp
1 /*
2 * Copyright (c) 2004-2006 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * keyPicker.cpp - select a key pair from a keychain
26 */
27
28 #include "keyPicker.h"
29 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
30 #include <Security/Security.h>
31 #include <stdexcept>
32 #include <ctype.h>
33 #include <clAppUtils/identPicker.h> /* for kcFileName() */
34 #include <vector>
35
36 /*
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.
39 */
40 OSStatus getKcItemAttr(
41 SecKeychainItemRef kcItem,
42 WhichAttr whichAttr,
43 CFDataRef *rtnAttr) /* RETURNED */
44 {
45 /* main job is to figure out which attrType to ask for, and from what Sec item */
46 SecKeychainItemRef attrFromThis;
47 SecKeychainAttrType attrType = 0;
48 OSStatus ortn;
49 bool releaseKcItem = false;
50
51 CFTypeID cfId = CFGetTypeID(kcItem);
52 if(cfId == SecIdentityGetTypeID()) {
53 /* switch over to cert */
54 ortn = SecIdentityCopyCertificate((SecIdentityRef)kcItem,
55 (SecCertificateRef *)&attrFromThis);
56 if(ortn)
57 cssmPerror("SecIdentityCopyCertificate", ortn);
58 return ortn;
59 kcItem = attrFromThis;
60 releaseKcItem = true;
61 cfId = SecCertificateGetTypeID();
62 }
63
64 if(cfId == SecCertificateGetTypeID()) {
65 switch(whichAttr) {
66 case WA_Hash:
67 attrType = kSecPublicKeyHashItemAttr;
68 break;
69 case WA_PrintName:
70 attrType = kSecLabelItemAttr;
71 break;
72 default:
73 printf("getKcItemAttr: WhichAttr\n");
74 return paramErr;
75 }
76 }
77 else if(cfId == SecKeyGetTypeID()) {
78 switch(whichAttr) {
79 case WA_Hash:
80 attrType = kSecKeyLabel;
81 break;
82 case WA_PrintName:
83 attrType = kSecKeyPrintName;
84 break;
85 default:
86 printf("getKcItemAttr: WhichAttr\n");
87 return paramErr;
88 }
89 }
90
91 SecKeychainAttributeInfo attrInfo;
92 attrInfo.count = 1;
93 attrInfo.tag = &attrType;
94 attrInfo.format = NULL; // ???
95 SecKeychainAttributeList *attrList = NULL;
96
97 ortn = SecKeychainItemCopyAttributesAndData(
98 kcItem,
99 &attrInfo,
100 NULL, // itemClass
101 &attrList,
102 NULL, // don't need the data
103 NULL);
104 if(releaseKcItem) {
105 CFRelease(kcItem);
106 }
107 if(ortn) {
108 cssmPerror("SecKeychainItemCopyAttributesAndData", ortn);
109 return paramErr;
110 }
111 SecKeychainAttribute *attr = attrList->attr;
112 *rtnAttr = CFDataCreate(NULL, (UInt8 *)attr->data, attr->length);
113 SecKeychainItemFreeAttributesAndData(attrList, NULL);
114 return noErr;
115 }
116
117 /*
118 * Class representing one key in the keychain.
119 */
120 class PickerKey
121 {
122 public:
123 PickerKey(SecKeyRef keyRef);
124 ~PickerKey();
125
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; }
132
133 PickerKey *partnerKey() { return mPartner; }
134 void partnerKey(PickerKey *pk) { mPartner = pk; }
135 char *kcFile() { return mKcFile; }
136
137 private:
138 SecKeyRef mKeyRef;
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
145 };
146
147 PickerKey::PickerKey(SecKeyRef keyRef)
148 : mKeyRef(NULL),
149 mPrintName(NULL),
150 mPubKeyHash(NULL),
151 mIsPrivate(false),
152 mIsUsed(false),
153 mPartner(NULL),
154 mKcFile(NULL)
155 {
156 if(CFGetTypeID(keyRef) != SecKeyGetTypeID()) {
157 throw std::invalid_argument("not a key");
158 }
159
160 OSStatus ortn = getKcItemAttr((SecKeychainItemRef)keyRef, WA_Hash, &mPubKeyHash);
161 if(ortn) {
162 throw std::invalid_argument("pub key hash not available");
163 }
164 ortn = getKcItemAttr((SecKeychainItemRef)keyRef, WA_PrintName, &mPrintName);
165 if(ortn) {
166 throw std::invalid_argument("pub key hash not available");
167 }
168
169 const CSSM_KEY *cssmKey;
170 ortn = SecKeyGetCSSMKey(keyRef, &cssmKey);
171 if(ortn) {
172 /* should never happen */
173 cssmPerror("SecKeyGetCSSMKey", ortn);
174 throw std::invalid_argument("SecKeyGetCSSMKey error");
175 }
176 if(cssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY) {
177 mIsPrivate = true;
178 }
179
180 /* stash name of the keychain this lives on */
181 SecKeychainRef kcRef;
182 ortn = SecKeychainItemCopyKeychain((SecKeychainItemRef)keyRef, &kcRef);
183 if(ortn) {
184 cssmPerror("SecKeychainItemCopyKeychain", ortn);
185 mKcFile = strdup("Unnamed keychain");
186 }
187 else {
188 mKcFile = kcFileName(kcRef);
189 }
190
191 mKeyRef = keyRef;
192 CFRetain(mKeyRef);
193 }
194
195 PickerKey::~PickerKey()
196 {
197 if(mKeyRef) {
198 CFRelease(mKeyRef);
199 }
200 if(mPubKeyHash) {
201 CFRelease(mPubKeyHash);
202 }
203 if(mPrintName) {
204 CFRelease(mPrintName);
205 }
206 if(mKcFile) {
207 free(mKcFile);
208 }
209 }
210
211 typedef std::vector<PickerKey *> KeyVector;
212
213 /*
214 * add PickerKey objects of specified type to a KeyVector.
215 */
216 static void getPickerKeys(
217 SecKeychainRef kcRef,
218 SecItemClass itemClass, // actually CSSM_DL_DB_RECORD_{PRIVATE,PRIVATE}_KEY for now
219 KeyVector &keyVector)
220 {
221 SecKeychainSearchRef srchRef = NULL;
222 SecKeychainItemRef kcItem;
223
224 OSStatus ortn = SecKeychainSearchCreateFromAttributes(kcRef,
225 itemClass,
226 NULL, // any attrs
227 &srchRef);
228 if(ortn) {
229 cssmPerror("SecKeychainSearchCreateFromAttributes", ortn);
230 return;
231 }
232 do {
233 ortn = SecKeychainSearchCopyNext(srchRef, &kcItem);
234 if(ortn) {
235 break;
236 }
237 try {
238 PickerKey *pickerKey = new PickerKey((SecKeyRef)kcItem);
239 keyVector.push_back(pickerKey);
240 }
241 catch(...) {
242 printf("**** key item that failed PickerKey construct ***\n");
243 /* but keep going */
244 }
245 } while(ortn == noErr);
246 CFRelease(srchRef);
247 }
248
249 /*
250 * Print contents of a CFData assuming it's printable
251 */
252 static void printCfData(CFDataRef cfd)
253 {
254 CFIndex len = CFDataGetLength(cfd);
255 const UInt8 *cp = CFDataGetBytePtr(cfd);
256 for(CFIndex dex=0; dex<len; dex++) {
257 char c = cp[dex];
258 if(isprint(c)) {
259 putchar(c);
260 }
261 else {
262 printf(".%02X.", c);
263 }
264 }
265 }
266
267 OSStatus keyPicker(
268 SecKeychainRef kcRef, // NULL means the default list
269 SecKeyRef *pubKey, // RETURNED
270 SecKeyRef *privKey) // RETURNED
271 {
272
273 /* First create a arrays of all of the keys, parsed and ready for use */
274
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);
279
280 /* now interate thru private keys, looking for a partner for each one */
281 int numPairs = 0;
282 unsigned numPrivKeys = privKeys.size();
283 unsigned numPubKeys = pubKeys.size();
284
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 */
292 continue;
293 }
294 if(!CFEqual(privHash, pubPk->getPubKeyHash())) {
295 /* public key hashes don't match */
296 continue;
297 }
298
299 /* got a match */
300 pubPk->partnerKey(privPk);
301 privPk->partnerKey(pubPk);
302 pubPk->isUsed(true);
303 privPk->isUsed(true);
304
305 /* display */
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());
309
310 numPairs++;
311 }
312 }
313
314 if(numPairs == 0) {
315 printf("*** keyPicker: no key pairs found.\n");
316 return paramErr;
317 }
318
319 OSStatus ortn = noErr;
320 int ires;
321 while(1) {
322 fpurge(stdin);
323 printf("\nEnter key pair number or CR to quit : ");
324 fflush(stdout);
325 char resp[64];
326 getString(resp, sizeof(resp));
327 if(resp[0] == '\0') {
328 ortn = CSSMERR_CSSM_USER_CANCELED;
329 break;
330 }
331 ires = atoi(resp);
332 if((ires < 0) || (ires >= numPairs)) {
333 printf("***Invalid entry. Type a number between 0 and %d\n", numPairs-1);
334 continue;
335 }
336 break;
337 }
338
339 if(ortn == noErr) {
340 /* find the ires'th partnered private key */
341 int goodOnes = 0;
342 for(unsigned privDex=0; privDex<numPrivKeys; privDex++) {
343 PickerKey *privPk = privKeys[privDex];
344 if(!privPk->isUsed()) {
345 continue;
346 }
347 if(goodOnes == ires) {
348 /* this is it */
349 *privKey = privPk->keyRef();
350 *pubKey = privPk->partnerKey()->keyRef();
351 }
352 goodOnes++;
353 }
354 }
355
356 /* clean out PickerKey arrays */
357 for(unsigned privDex=0; privDex<numPrivKeys; privDex++) {
358 delete privKeys[privDex];
359 }
360 for(unsigned pubDex=0; pubDex<numPubKeys; pubDex++) {
361 delete pubKeys[pubDex];
362 }
363 return ortn;
364 }
365