1/* 2 * Copyright (c) 2004 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 26// 27// C++ gate to "Muscle" smartcard interface layer 28// 29#include "muscle++.h" 30#include <security_utilities/debugging.h> 31 32 33namespace Security { 34namespace Muscle { 35 36 37// 38// PCSC domain errors 39// 40Error::Error(MSC_RV err) : error(err) 41{ 42 SECURITY_EXCEPTION_THROW_OTHER(this, err, (char *)"muscle"); 43} 44 45 46const char *Error::what() const throw () 47{ 48 return msc_error(error); 49} 50 51 52void Error::throwMe(MSC_RV err) 53{ 54 throw Error(err); 55} 56 57 58OSStatus Error::osStatus() const 59{ 60 return -1; //@@@ preliminary 61} 62 63int Error::unixError() const 64{ 65 return EINVAL; //@@@ preliminary 66} 67 68 69// 70// Open a connection with PCSC layer information. 71// The ReaderState fields required are the slot name and the ATR. 72// 73Connection::Connection() 74 : mIsOpen(false), mCurrentTransaction(NULL) 75{ 76} 77 78Connection::~Connection() 79{ 80 assert(!mCurrentTransaction); 81 close(); 82} 83 84void Connection::open(const PCSC::ReaderState &reader, unsigned share) 85{ 86 // fill in the minimum needed to identify the card 87 MSCTokenInfo info; 88 89 // set slot name in info 90 strncpy(info.slotName, reader.name(), MAX_READERNAME); 91 92 // set ATR in info 93 assert(reader.length() <= MAX_ATR_SIZE); 94 memcpy(info.tokenId, reader.data(), reader.length()); 95 info.tokenIdLength = (MSCULong32)reader.length(); 96 97 // establish Muscle-level connection to card 98 Error::check(::MSCEstablishConnection(&info, share, NULL, 0, this)); 99 mIsOpen = true; 100 secdebug("muscle", "%p opened %s", this, info.slotName); 101 102 // pull initial status 103 updateStatus(); 104} 105 106void Connection::close() 107{ 108 if (mIsOpen) { 109 secdebug("muscle", "%p closing", this); 110 Error::check(::MSCReleaseConnection(this, SCARD_LEAVE_CARD)); 111 mIsOpen = false; 112 } 113} 114 115 116void Connection::begin(Transaction *trans) 117{ 118 assert(!mCurrentTransaction); 119 Error::check(::MSCBeginTransaction(this)); 120 secdebug("muscle", "%p start transaction %p", this, trans); 121 mCurrentTransaction = trans; 122} 123 124void Connection::end(Transaction *trans) 125{ 126 assert(trans == mCurrentTransaction); 127 secdebug("muscle", "%p end transaction %p", this, trans); 128 Error::check(::MSCEndTransaction(this, SCARD_LEAVE_CARD)); 129 mCurrentTransaction = NULL; 130} 131 132 133// 134// Update card status (cached in the Connection object) 135// 136void Connection::updateStatus() 137{ 138 Error::check(::MSCGetStatus(this, this)); 139} 140 141 142// 143// Get all items off the card 144// 145template <class Info, class Item, MSC_RV (*list)(MSCTokenConnection *, MSCUChar8, Info *)> 146static void get(Connection *conn, Connection::ItemSet &items) 147{ 148 Info info; 149 MSCUChar8 seq = MSC_SEQUENCE_RESET; 150 for (;;) { 151 switch (MSC_RV rc = list(conn, seq, &info)) { 152 case MSC_SEQUENCE_END: 153 return; 154 case MSC_SUCCESS: 155 items.insert(new Item(info)); 156 seq = MSC_SEQUENCE_NEXT; 157 break; 158 default: 159 Error::throwMe(rc); 160 } 161 } 162} 163 164void Connection::getItems(ItemSet &result, bool getKeys, bool getOthers) 165{ 166 ItemSet items; 167 if (getKeys) 168 get<MSCKeyInfo, Key, MSCListKeys>(this, items); 169 if (getOthers) 170 get<MSCObjectInfo, Object, MSCListObjects>(this, items); 171 items.swap(result); 172} 173 174 175// 176// Transaction monitors 177// 178Transaction::Transaction(Connection &con) 179 : connection(con) 180{ 181 connection.begin(this); 182} 183 184Transaction::~Transaction() 185{ 186 connection.end(this); 187} 188 189 190// 191// ACLs (Muscle style) 192// 193static void aclForm(string &s, MSCUShort16 acl, int offset, char c) 194{ 195 for (int n = 0; n < 5; n++) { 196 char p = '-'; 197 switch (acl) { 198 case MSC_AUT_ALL: p = c; break; 199 case MSC_AUT_NONE: break; 200 default: if (acl & (MSC_AUT_PIN_0 << n)) p = c; break; 201 } 202 s[3 * n + offset] = p; 203 } 204} 205 206string ACL::form(char ue) const 207{ 208 string r = "---------------"; 209 aclForm(r, mRead, 0, 'r'); 210 aclForm(r, mWrite, 1, 'w'); 211 aclForm(r, mErase, 2, ue); 212 return r; 213} 214 215 216// 217// Keys and objects 218// 219CardItem::~CardItem() 220{ /* virtual */ } 221 222 223Key::Key(const MSCKeyInfo &info) 224 : MSCKeyInfo(info) 225{ 226 snprintf(mKeyName, sizeof(mKeyName), "K%d", id()); 227} 228 229 230const ACL &Key::acl() const { return reinterpret_cast<const ACL &>(keyACL); } 231ACL &Key::acl() { return reinterpret_cast<ACL &>(keyACL); } 232 233const char *Key::name() const { return mKeyName; } 234unsigned Key::size() const { return keySize; } 235 236void Key::debugDump() 237{ 238 printf("Key %d type %d size %d mode=0x%x dir=0x%x ACL %s\n", 239 keyNum, keyType, keySize, mode(), operations(), acl().form('u').c_str()); 240} 241 242const char *Object::name() const { return objectID; } 243unsigned Object::size() const { return objectSize; } 244 245const ACL &Object::acl() const { return reinterpret_cast<const ACL &>(objectACL); } 246ACL &Object::acl() { return reinterpret_cast<ACL &>(objectACL); } 247 248void Object::debugDump() 249{ 250 printf("Object %s size %d ACL %s\n", 251 objectID, objectSize, acl().form('e').c_str()); 252} 253 254 255} // namespace Muscle 256} // namespace Security 257