+++ /dev/null
-/*
- * Copyright (c) 2004,2011-2012,2014 Apple 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@
- */
-
-
-//
-// pcsc++ - PCSC client interface layer in C++
-//
-#include "pcsc++.h"
-#include <security_utilities/debugging.h>
-#include <PCSC/pcsclite.h>
-#include <PCSC/wintypes.h>
-#include <Security/cssmapple.h>
-
-namespace Security {
-namespace PCSC {
-
-
-//
-// Internal utilities
-//
-static void decode(vector<string> &names, const char *buffer, size_t size)
-{
- names.clear();
- for (size_t pos = 0; pos < size - 1; ) {
- size_t len = strlen(buffer + pos);
- names.push_back(string(buffer + pos, len));
- pos += len + 1;
- }
-}
-
-inline void decode(vector<string> &names, const vector<char> &buffer, size_t size)
-{
- decode(names, &buffer[0], size);
-}
-
-
-//
-// PCSC domain errors
-//
-Error::Error(unsigned long err) : error(err)
-{
- SECURITY_EXCEPTION_THROW_PCSC(this, (unsigned int)err);
-}
-
-
-const char *Error::what() const throw ()
-{
- return pcsc_stringify_error((int32_t)error);
-}
-
-
-void Error::throwMe(unsigned long err)
-{
- throw Error(err);
-}
-
-
-OSStatus Error::osStatus() const
-{
- switch (error)
- {
- // @@@ more errors should be mapped here
- case SCARD_W_RESET_CARD:
- return CSSMERR_CSP_DEVICE_RESET;
- default:
- return CSSMERR_CSP_INTERNAL_ERROR;
- }
-}
-
-int Error::unixError() const
-{
- return EINVAL; //@@@ preliminary
-}
-
-
-//
-// PodWrappers
-//
-void ReaderState::set(const char *name, unsigned long known)
-{
- clearPod();
- szReader = name;
- pvUserData = NULL;
- dwCurrentState = (uint32_t)known;
-}
-
-
-void ReaderState::lastKnown(unsigned long s)
-{
- // clear out CHANGED and UNAVAILABLE
- dwCurrentState = (uint32_t)s & ~(SCARD_STATE_CHANGED | SCARD_STATE_UNAVAILABLE);
-}
-
-
-void ReaderState::setATR(const void *atr, size_t size)
-{
- if (size > sizeof(rgbAtr))
- Error::throwMe(SCARD_E_INVALID_ATR);
- memcpy(rgbAtr, atr, size);
- cbAtr = (uint32_t)size;
-}
-
-
-#if defined(DEBUGDUMP)
-
-void ReaderState::dump()
-{
- Debug::dump("reader(%s) state=0x%x events=0x%x",
- szReader ? szReader : "(null)", dwCurrentState, dwEventState);
- Debug::dumpData(" ATR", rgbAtr, cbAtr);
-}
-
-#endif //DEBUGDUMP
-
-
-//
-// Session objects
-//
-Session::Session()
- : mIsOpen(false)
-{
-}
-
-
-Session::~Session()
-{
- close();
-}
-
-
-//
-// (Re)establish PCSC context.
-// Don't fail on SCARD_F_INTERNAL_ERROR (pcscd not running - urgh).
-//
-void Session::open()
-{
- if (!mIsOpen) {
- try {
- Error::check(::SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &mContext));
- mIsOpen = true;
- secdebug("pcsc", "context opened");
- } catch (const Error &err) {
- if (err.error == SCARD_F_INTERNAL_ERROR)
- {
- secdebug("pcsc", "got internal error; assuming pcscd absent; context not ready");
- return;
- }
- }
- }
-}
-
-void Session::close()
-{
- if (mIsOpen) {
- mIsOpen = false;
- try {
- if (mContext)
- Error::check(SCardReleaseContext(mContext));
- secdebug("pcsc", "context closed");
- } catch (const Error &err) {
- if (err.error == SCARD_F_INTERNAL_ERROR)
- {
- secdebug("pcsc", "got internal error; assuming pcscd absent; context not ready");
- return;
- }
- }
- }
-}
-
-bool Session::check(long rc)
-{
- switch (rc) {
- case SCARD_S_SUCCESS:
- return true; // got reader(s), call succeeded
- case SCARD_E_READER_UNAVAILABLE:
- return false; // no readers, but don't treat as error
- default:
- Error::throwMe(rc);
- return false; // placebo
- }
-}
-
-
-void Session::listReaders(vector<string> &readers, const char *groups)
-{
- uint32_t size = 0;
- if (check(::SCardListReaders(mContext, groups, NULL, &size)))
- {
- mReaderBuffer.resize(size);
- if (check(::SCardListReaders(mContext, groups, &mReaderBuffer[0], &size)))
- {
- decode(readers, mReaderBuffer, size);
- return;
- }
- }
-
- readers.clear(); // treat as success (returning zero readers)
-}
-
-
-//
-// Reader status check
-//
-void Session::statusChange(ReaderState *readers, unsigned int nReaders, long timeout)
-{
- check(::SCardGetStatusChange(mContext, (uint32_t)timeout, readers, nReaders));
-}
-
-
-//
-// PCSC Card objects
-//
-Card::Card()
- : mConnectedState(kInitial)
-{
-}
-
-Card::~Card()
-{
-}
-
-void Card::setIOType(unsigned long activeProtocol)
-{
- switch (activeProtocol)
- {
- case SCARD_PROTOCOL_T0:
- mIOType = SCARD_PCI_T0;
- break;
- case SCARD_PROTOCOL_T1:
- mIOType = SCARD_PCI_T1;
- break;
- default:
- mIOType = SCARD_PCI_RAW;
- break;
- }
-}
-
-void Card::connect(Session &session, const char *reader,
- unsigned long share, unsigned long protocols)
-{
- uint32_t activeProtocol;
- Error::check(::SCardConnect(session.mContext,
- reader, (uint32_t)share, (uint32_t)protocols, &mHandle, &activeProtocol));
- setIOType(activeProtocol);
- mConnectedState = kConnected;
-}
-
-void Card::reconnect(unsigned long share, unsigned long protocols, unsigned long initialization)
-{
- assert(mConnectedState != kInitial);
-
- uint32_t activeProtocol;
- Error::check(::SCardReconnect(mHandle, (uint32_t)share, (uint32_t)protocols,
- (uint32_t)initialization, &activeProtocol));
- setIOType(activeProtocol);
- mConnectedState = kConnected;
-}
-
-void Card::disconnect(unsigned long disposition)
-{
- if (mConnectedState == kConnected)
- {
- if (mTransactionNestLevel > 0)
- {
- secdebug("pcsc", "%p: disconnect, dropping: %d transactions", this, mTransactionNestLevel);
- mTransactionNestLevel = 0;
- }
-
- checkReset(::SCardDisconnect(mHandle, (uint32_t)disposition));
- didDisconnect();
- mConnectedState = kInitial;
- }
-}
-
-void
-Card::checkReset(unsigned int rv)
-{
- if (rv == SCARD_W_RESET_CARD)
- {
- secdebug("pcsc", "%p: card reset during pcsc call, we're disconnected", this);
- didDisconnect();
- }
- Error::check(rv);
-}
-
-void
-Card::didDisconnect()
-{
- mConnectedState = kDisconnected;
- mTransactionNestLevel = 0;
-}
-
-void
-Card::didEnd()
-{
-}
-
-void
-Card::transmit(const unsigned char *pbSendBuffer, size_t cbSendLength,
- unsigned char *pbRecvBuffer, size_t &pcbRecvLength)
-{
- if (mConnectedState == kDisconnected)
- {
- secdebug("pcsc", "%p: transmit after disconnect, reconnecting", this);
- reconnect();
- }
-
- IFDUMPING("pcsc", dump("->", pbSendBuffer, cbSendLength));
-
- uint32_t tmpRecvLength = (uint32_t)pcbRecvLength;
- checkReset(::SCardTransmit(mHandle, mIOType, pbSendBuffer, (uint32_t)cbSendLength,
- NULL, pbRecvBuffer, &tmpRecvLength));
- pcbRecvLength = tmpRecvLength;
-
- IFDUMPING("pcsc", dump("<-", pbRecvBuffer, pcbRecvLength));
-}
-
-void Card::begin()
-{
- // Only the first transaction started is sent to PCSC
- if (mTransactionNestLevel == 0)
- {
- if (mConnectedState == kDisconnected)
- {
- secdebug("pcsc", "%p: begin transaction after disconnect, reconnecting", this);
- reconnect();
- }
-
- checkReset(::SCardBeginTransaction(mHandle));
- }
- mTransactionNestLevel++;
- secdebug("pcsc", "%p begin transaction: %d", this, mTransactionNestLevel);
-}
-
-void Card::end(unsigned long disposition)
-{
- // Only the last transaction ended is sent to PCSC
- secdebug("pcsc", "%p end transaction: %d", this, mTransactionNestLevel);
- if (disposition == SCARD_RESET_CARD)
- {
- if (mConnectedState == kDisconnected)
- {
- secdebug("pcsc", "%p: end transaction after disconnect, reconnecting to reset card", this);
- reconnect();
- }
-
- checkReset(::SCardEndTransaction(mHandle, (uint32_t)disposition));
- didDisconnect();
- }
- else if (mTransactionNestLevel > 0)
- {
- --mTransactionNestLevel;
- if (mTransactionNestLevel == 0)
- {
- if (mConnectedState == kDisconnected)
- secdebug("pcsc", "%p: end transaction while disconnected ignored", this);
- else
- {
- checkReset(::SCardEndTransaction(mHandle, (uint32_t)disposition));
- didEnd();
- }
- }
- }
-}
-
-void Card::cancel()
-{
- end(/*SCARD_RESET_CARD*/);
-}
-
-#if defined(DEBUGDUMP)
-
-void
-Card::dump(const char *direction, const unsigned char *buffer, size_t length)
-{
- Debug::dump("[%02lu]%s:", length, direction);
-
- for (size_t ix = 0; ix < length; ++ix)
- Debug::dump(" %02x", buffer[ix]);
-
- Debug::dump("\n");
-}
-
-#endif
-
-
-void Transaction::commitAction()
-{
- mCarrier.end(mDisposition);
-}
-
-
-} // namespace PCSC
-} // namespace Security