/* * Copyright (c) 2004 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@ */ /* * MuscleCardToken.cpp * TokendMuscle */ #include "MuscleCardToken.h" #include "Adornment.h" #include "Adornment.h" #include "AttributeCoder.h" #include "KeyRecord.h" #include "TokenRecord.h" #include "Msc/MscToken.h" #include "Msc/MscTokenConnection.h" #include "Msc/MscWrappers.h" #include "MuscleCardSchema.h" #include #include #include using CssmClient::AclFactory; MuscleCardToken::MuscleCardToken() : mConnection(NULL) { } MuscleCardToken::~MuscleCardToken() { delete mTokenContext; delete mSchema; delete mConnection; } uint32 MuscleCardToken::probe(SecTokendProbeFlags flags, char tokenUid[TOKEND_MAX_UID]) { MscTokenInfo tinfo(*(*startupReaderInfo)()); MscTokenConnection tc(tinfo); tc.connect(); tc.release(); if (flags!=kSecTokendProbeDefault) ; return 50; } void MuscleCardToken::establish(const CSSM_GUID *guid, uint32 subserviceId, SecTokendEstablishFlags flags, const char *cacheDirectory, const char *workDirectory, char mdsDirectory[PATH_MAX], char printName[PATH_MAX]) { MscTokenInfo tinfo(*(*startupReaderInfo)()); mConnection = new MscTokenConnection(tinfo); mConnection->connect(); ::strncpy(printName, mConnection->tokenInfo.tokenName, PATH_MAX); mTokenContext = new MscToken(mConnection); static_cast(mTokenContext)->loadobjects(); mSchema = new MuscleCardSchema(); mSchema->create(); populate(); } // // Authenticate to the token // void MuscleCardToken::authenticate(CSSM_DB_ACCESS_TYPE mode, const AccessCredentials *cred) { if (cred) { if (cred->tag() && !strncmp(cred->tag(), "PIN", 3)) { // tag="PINk"; unlock a PIN if (cred->size() != 1) CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE); // just one, please const TypedList &sample = (*cred)[0]; switch (sample.type()) { case CSSM_SAMPLE_TYPE_PASSWORD: case CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD: { unsigned int slot; sscanf(cred->tag()+3, "%d", &slot); // "PINn" secdebug("muscleacl", "verifying PIN%d", slot); mConnection->verifyPIN(slot, sample[1].toString()); secdebug("muscleacl", "verify successful"); } break; default: secdebug("muscleacl", "sample type %ld not supported", sample.type()); CssmError::throwMe(CSSM_ERRCODE_ACL_SUBJECT_TYPE_NOT_SUPPORTED); } } else secdebug("muscleacl", "authenticate without PIN tag ignored"); } else secdebug("muscleacl", "authenticate(NULL) ignored"); } // // Database-level ACLs // void MuscleCardToken::getOwner(AclOwnerPrototype &owner) { // MUSCLE defines ACLs on card initialization, but doesn't seem to allow // them to be read out after the card has been personalized. // In absence of any meaningful information, blame PIN #0. if (!mAclOwner) { mAclOwner.allocator(Allocator::standard()); mAclOwner = AclFactory::PinSubject(Allocator::standard(), 0); } owner = mAclOwner; } void MuscleCardToken::getAcl(const char *tag, uint32 &count, AclEntryInfo *&acls) { // we don't (yet) support queries by tag if (tag) CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_ENTRY_TAG); Allocator &alloc = Allocator::standard(); // get pin list, then for each pin if (!mAclEntries) { mAclEntries.allocator(alloc); // Anyone can read any record from this db. // We don't support insertion modification or deletion yet. mAclEntries.add(CssmClient::AclFactory::AnySubject(mAclEntries.allocator()), AclAuthorizationSet(CSSM_ACL_AUTHORIZATION_DB_READ, 0)); // for each PIN on the card... unsigned int pins = mConnection->listPins(); for (unsigned n = 0; n < 16; n++) if (pins & (1 << n)) { // add a PIN slot for PASSWORD and PROTECTED_PASSWORD credentials mAclEntries.addPin(AclFactory::PWSubject(alloc), n); mAclEntries.addPin(AclFactory::PromptPWSubject(alloc, CssmData()), n); } } // return the ACL vector count = mAclEntries.size(); acls = mAclEntries.entries(); } #pragma mark ---------------- CAC Specific -------------- void MuscleCardToken::populate() { secdebug("populate", "MuscleCardToken::populate() begin"); Tokend::Relation &certRelation = mSchema->findRelation(CSSM_DL_DB_RECORD_X509_CERTIFICATE); Tokend::Relation &dataRelation = mSchema->findRelation(CSSM_DL_DB_RECORD_GENERIC); Tokend::Relation &privateKeyRelation = mSchema->findRelation(CSSM_DL_DB_RECORD_PRIVATE_KEY); Tokend::Relation &publicKeyRelation = mSchema->findRelation(CSSM_DL_DB_RECORD_PUBLIC_KEY); Tokend::Relation &symmetricKeyRelation = mSchema->findRelation(CSSM_DL_DB_RECORD_SYMMETRIC_KEY); // Map from number to certs. typedef std::map< UInt32, RefPointer > CertificateMap; CertificateMap certificates; typedef std::vector > KeyVector; KeyVector keys; // The first time through, we insert cert and data records. We skip attribute records // so that we can add them as adornments to records that will exist after this pass for (MscToken::ObjIterator it = static_cast(mTokenContext)->begin(); it != static_cast(mTokenContext)->end(); ++it) { MscObject *obj = it->second; std::string objid = obj->objid(); secdebug("populate", "Found object with id: %s", objid.c_str()); switch (objid[0]) { case 'C': // insert in cert relation { RefPointer record(new TokenRecord(objid)); certRelation.insertRecord(record); UInt32 certNum = atoi(objid.c_str() + 1); certificates.insert(std::pair >(certNum, record)); } break; case 'k': // this will become an adornment for key record #if 0 { // @@@ Move this define to a msc header #define CKO_CAC_PRIVATE_KEY 0x03000000 RefPointer keyRecord(new KeyRecord(*obj)); uint32_t cka_class = keyRecord->attributeValueAsUint32(CKA_CLASS); switch (cka_class) { case CKO_PRIVATE_KEY: case CKO_CAC_PRIVATE_KEY: secdebug("populate", "Inserting private key with id: %s CKA_CLASS: %08X", objid.c_str(), cka_class); privateKeyRelation.insertRecord(keyRecord); keys.push_back(keyRecord); break; case CKO_PUBLIC_KEY: case CKO_SECRET_KEY: default: secdebug("populate", "Ignoring key with id: %s CKA_CLASS: %08X", objid.c_str(), cka_class); break; } } break; #endif case 'c': // this might become an adornment for cert record secdebug("populate", "Ignoring object with id: %s", objid.c_str()); break; default: // insert as data record { RefPointer record(new TokenRecord(objid)); dataRelation.insertRecord(record); } break; } } // The first time through, we insert cert and data records. We skip attribute records // so that we can add them as adornments to records that will exist after this pass for (MscToken::ConstKeyIterator it = static_cast(mTokenContext)->kbegin(); it != static_cast(mTokenContext)->kend(); ++it) { MscKey *key = it->second; IFDUMPING("key", key->debugDump()); { RefPointer keyRecord(new KeyRecord(*key)); uint32_t type = key->type(); switch (type) { case MSC_KEY_RSA_PRIVATE: case MSC_KEY_RSA_PRIVATE_CRT: case MSC_KEY_DSA_PRIVATE: secdebug("populate", "Inserting private key with type: %02X", type); privateKeyRelation.insertRecord(keyRecord); keys.push_back(keyRecord); break; case MSC_KEY_RSA_PUBLIC: case MSC_KEY_DSA_PUBLIC: secdebug("populate", "Inserting public key with type: %02X", type); publicKeyRelation.insertRecord(keyRecord); keys.push_back(keyRecord); break; case MSC_KEY_DES: case MSC_KEY_3DES: case MSC_KEY_3DES3: secdebug("populate", "Inserting symmetric key with type: %02X", type); symmetricKeyRelation.insertRecord(keyRecord); keys.push_back(keyRecord); break; default: secdebug("populate", "Ignoring key with type: %02X", type); break; } } } for (KeyVector::const_iterator ks_it = keys.begin(); ks_it != keys.end(); ++ks_it) { UInt32 keyNum = (*ks_it)->key().number(); CertificateMap::const_iterator cs_it = certificates.find(keyNum); if (cs_it == certificates.end()) { secdebug("populate", "No certificate found for key: %lu", keyNum); } else { secdebug("populate", "Linked key: K%lu to certificate C%lu", keyNum, keyNum); (*ks_it)->setAdornment(mSchema->publicKeyHashCoder().certificateKey(), new Tokend::LinkedRecordAdornment(cs_it->second)); } } secdebug("populate", "MuscleCardToken::populate() end"); } /* arch-tag: 2776DBC0-F53B-11D8-99D6-000A9595DEEE */