+++ /dev/null
-/*
- * Copyright (c) 2004-2006 Apple Computer, Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/*
- * keyPicker.cpp - select a key pair from a keychain
- */
-
-#include "keyPicker.h"
-#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
-#include <Security/Security.h>
-#include <stdexcept>
-#include <ctype.h>
-#include <clAppUtils/identPicker.h> /* for kcFileName() */
-#include <vector>
-
-/*
- * Obtain either public key hash or PrintName for a given SecKeychainItem. Works on public keys,
- * private keys, identities, and certs. Caller must release the returned result.
- */
-OSStatus getKcItemAttr(
- SecKeychainItemRef kcItem,
- WhichAttr whichAttr,
- CFDataRef *rtnAttr) /* RETURNED */
-{
- /* main job is to figure out which attrType to ask for, and from what Sec item */
- SecKeychainItemRef attrFromThis;
- SecKeychainAttrType attrType = 0;
- OSStatus ortn;
- bool releaseKcItem = false;
-
- CFTypeID cfId = CFGetTypeID(kcItem);
- if(cfId == SecIdentityGetTypeID()) {
- /* switch over to cert */
- ortn = SecIdentityCopyCertificate((SecIdentityRef)kcItem,
- (SecCertificateRef *)&attrFromThis);
- if(ortn)
- cssmPerror("SecIdentityCopyCertificate", ortn);
- return ortn;
- kcItem = attrFromThis;
- releaseKcItem = true;
- cfId = SecCertificateGetTypeID();
- }
-
- if(cfId == SecCertificateGetTypeID()) {
- switch(whichAttr) {
- case WA_Hash:
- attrType = kSecPublicKeyHashItemAttr;
- break;
- case WA_PrintName:
- attrType = kSecLabelItemAttr;
- break;
- default:
- printf("getKcItemAttr: WhichAttr\n");
- return paramErr;
- }
- }
- else if(cfId == SecKeyGetTypeID()) {
- switch(whichAttr) {
- case WA_Hash:
- attrType = kSecKeyLabel;
- break;
- case WA_PrintName:
- attrType = kSecKeyPrintName;
- break;
- default:
- printf("getKcItemAttr: WhichAttr\n");
- return paramErr;
- }
- }
-
- SecKeychainAttributeInfo attrInfo;
- attrInfo.count = 1;
- attrInfo.tag = &attrType;
- attrInfo.format = NULL; // ???
- SecKeychainAttributeList *attrList = NULL;
-
- ortn = SecKeychainItemCopyAttributesAndData(
- kcItem,
- &attrInfo,
- NULL, // itemClass
- &attrList,
- NULL, // don't need the data
- NULL);
- if(releaseKcItem) {
- CFRelease(kcItem);
- }
- if(ortn) {
- cssmPerror("SecKeychainItemCopyAttributesAndData", ortn);
- return paramErr;
- }
- SecKeychainAttribute *attr = attrList->attr;
- *rtnAttr = CFDataCreate(NULL, (UInt8 *)attr->data, attr->length);
- SecKeychainItemFreeAttributesAndData(attrList, NULL);
- return noErr;
-}
-
-/*
- * Class representing one key in the keychain.
- */
-class PickerKey
-{
-public:
- PickerKey(SecKeyRef keyRef);
- ~PickerKey();
-
- bool isUsed() { return mIsUsed;}
- void isUsed(bool u) { mIsUsed = u; }
- bool isPrivate() { return mIsPrivate; }
- CFDataRef getPrintName() { return mPrintName; }
- CFDataRef getPubKeyHash() { return mPubKeyHash; }
- SecKeyRef keyRef() { return mKeyRef; }
-
- PickerKey *partnerKey() { return mPartner; }
- void partnerKey(PickerKey *pk) { mPartner = pk; }
- char *kcFile() { return mKcFile; }
-
-private:
- SecKeyRef mKeyRef;
- CFDataRef mPrintName;
- CFDataRef mPubKeyHash;
- bool mIsPrivate; // private/public key
- bool mIsUsed; // has been spoken for
- PickerKey *mPartner; // other member of public/private pair
- char *mKcFile; // file name of keychain this lives on
-};
-
-PickerKey::PickerKey(SecKeyRef keyRef)
- : mKeyRef(NULL),
- mPrintName(NULL),
- mPubKeyHash(NULL),
- mIsPrivate(false),
- mIsUsed(false),
- mPartner(NULL),
- mKcFile(NULL)
-{
- if(CFGetTypeID(keyRef) != SecKeyGetTypeID()) {
- throw std::invalid_argument("not a key");
- }
-
- OSStatus ortn = getKcItemAttr((SecKeychainItemRef)keyRef, WA_Hash, &mPubKeyHash);
- if(ortn) {
- throw std::invalid_argument("pub key hash not available");
- }
- ortn = getKcItemAttr((SecKeychainItemRef)keyRef, WA_PrintName, &mPrintName);
- if(ortn) {
- throw std::invalid_argument("pub key hash not available");
- }
-
- const CSSM_KEY *cssmKey;
- ortn = SecKeyGetCSSMKey(keyRef, &cssmKey);
- if(ortn) {
- /* should never happen */
- cssmPerror("SecKeyGetCSSMKey", ortn);
- throw std::invalid_argument("SecKeyGetCSSMKey error");
- }
- if(cssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY) {
- mIsPrivate = true;
- }
-
- /* stash name of the keychain this lives on */
- SecKeychainRef kcRef;
- ortn = SecKeychainItemCopyKeychain((SecKeychainItemRef)keyRef, &kcRef);
- if(ortn) {
- cssmPerror("SecKeychainItemCopyKeychain", ortn);
- mKcFile = strdup("Unnamed keychain");
- }
- else {
- mKcFile = kcFileName(kcRef);
- }
-
- mKeyRef = keyRef;
- CFRetain(mKeyRef);
-}
-
-PickerKey::~PickerKey()
-{
- if(mKeyRef) {
- CFRelease(mKeyRef);
- }
- if(mPubKeyHash) {
- CFRelease(mPubKeyHash);
- }
- if(mPrintName) {
- CFRelease(mPrintName);
- }
- if(mKcFile) {
- free(mKcFile);
- }
-}
-
-typedef std::vector<PickerKey *> KeyVector;
-
-/*
- * add PickerKey objects of specified type to a KeyVector.
- */
-static void getPickerKeys(
- SecKeychainRef kcRef,
- SecItemClass itemClass, // actually CSSM_DL_DB_RECORD_{PRIVATE,PRIVATE}_KEY for now
- KeyVector &keyVector)
-{
- SecKeychainSearchRef srchRef = NULL;
- SecKeychainItemRef kcItem;
-
- OSStatus ortn = SecKeychainSearchCreateFromAttributes(kcRef,
- itemClass,
- NULL, // any attrs
- &srchRef);
- if(ortn) {
- cssmPerror("SecKeychainSearchCreateFromAttributes", ortn);
- return;
- }
- do {
- ortn = SecKeychainSearchCopyNext(srchRef, &kcItem);
- if(ortn) {
- break;
- }
- try {
- PickerKey *pickerKey = new PickerKey((SecKeyRef)kcItem);
- keyVector.push_back(pickerKey);
- }
- catch(...) {
- printf("**** key item that failed PickerKey construct ***\n");
- /* but keep going */
- }
- } while(ortn == noErr);
- CFRelease(srchRef);
-}
-
-/*
- * Print contents of a CFData assuming it's printable
- */
-static void printCfData(CFDataRef cfd)
-{
- CFIndex len = CFDataGetLength(cfd);
- const UInt8 *cp = CFDataGetBytePtr(cfd);
- for(CFIndex dex=0; dex<len; dex++) {
- char c = cp[dex];
- if(isprint(c)) {
- putchar(c);
- }
- else {
- printf(".%02X.", c);
- }
- }
-}
-
-OSStatus keyPicker(
- SecKeychainRef kcRef, // NULL means the default list
- SecKeyRef *pubKey, // RETURNED
- SecKeyRef *privKey) // RETURNED
-{
-
- /* First create a arrays of all of the keys, parsed and ready for use */
-
- std::vector<PickerKey *> privKeys;
- std::vector<PickerKey *> pubKeys;
- getPickerKeys(kcRef, CSSM_DL_DB_RECORD_PRIVATE_KEY, privKeys);
- getPickerKeys(kcRef, CSSM_DL_DB_RECORD_PUBLIC_KEY, pubKeys);
-
- /* now interate thru private keys, looking for a partner for each one */
- int numPairs = 0;
- unsigned numPrivKeys = privKeys.size();
- unsigned numPubKeys = pubKeys.size();
-
- for(unsigned privDex=0; privDex<numPrivKeys; privDex++) {
- PickerKey *privPk = privKeys[privDex];
- CFDataRef privHash = privPk->getPubKeyHash();
- for(unsigned pubDex=0; pubDex<numPubKeys; pubDex++) {
- PickerKey *pubPk = pubKeys[pubDex];
- if(pubPk->isUsed()) {
- /* already spoken for */
- continue;
- }
- if(!CFEqual(privHash, pubPk->getPubKeyHash())) {
- /* public key hashes don't match */
- continue;
- }
-
- /* got a match */
- pubPk->partnerKey(privPk);
- privPk->partnerKey(pubPk);
- pubPk->isUsed(true);
- privPk->isUsed(true);
-
- /* display */
- printf("[%d] privKey : ", numPairs); printCfData(privPk->getPrintName()); printf("\n");
- printf(" pubKey : "); printCfData(pubPk->getPrintName());printf("\n");
- printf(" keychain : %s\n", privPk->kcFile());
-
- numPairs++;
- }
- }
-
- if(numPairs == 0) {
- printf("*** keyPicker: no key pairs found.\n");
- return paramErr;
- }
-
- OSStatus ortn = noErr;
- int ires;
- while(1) {
- fpurge(stdin);
- printf("\nEnter key pair number or CR to quit : ");
- fflush(stdout);
- char resp[64];
- getString(resp, sizeof(resp));
- if(resp[0] == '\0') {
- ortn = CSSMERR_CSSM_USER_CANCELED;
- break;
- }
- ires = atoi(resp);
- if((ires < 0) || (ires >= numPairs)) {
- printf("***Invalid entry. Type a number between 0 and %d\n", numPairs-1);
- continue;
- }
- break;
- }
-
- if(ortn == noErr) {
- /* find the ires'th partnered private key */
- int goodOnes = 0;
- for(unsigned privDex=0; privDex<numPrivKeys; privDex++) {
- PickerKey *privPk = privKeys[privDex];
- if(!privPk->isUsed()) {
- continue;
- }
- if(goodOnes == ires) {
- /* this is it */
- *privKey = privPk->keyRef();
- *pubKey = privPk->partnerKey()->keyRef();
- }
- goodOnes++;
- }
- }
-
- /* clean out PickerKey arrays */
- for(unsigned privDex=0; privDex<numPrivKeys; privDex++) {
- delete privKeys[privDex];
- }
- for(unsigned pubDex=0; pubDex<numPubKeys; pubDex++) {
- delete pubKeys[pubDex];
- }
- return ortn;
-}
-