]> git.saurik.com Git - apple/security.git/blobdiff - libsecurity_utilities/lib/muscle++.cpp
Security-55163.44.tar.gz
[apple/security.git] / libsecurity_utilities / lib / muscle++.cpp
diff --git a/libsecurity_utilities/lib/muscle++.cpp b/libsecurity_utilities/lib/muscle++.cpp
new file mode 100644 (file)
index 0000000..b56dd7e
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * 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@
+ *
+ */
+
+
+//
+// C++ gate to "Muscle" smartcard interface layer
+//
+#include "muscle++.h"
+#include <security_utilities/debugging.h>
+
+
+namespace Security {
+namespace Muscle {
+
+
+//
+// PCSC domain errors
+//
+Error::Error(MSC_RV err) : error(err)
+{
+       SECURITY_EXCEPTION_THROW_OTHER(this, err, (char *)"muscle");
+}
+
+
+const char *Error::what() const throw ()
+{
+       return msc_error(error);
+}
+
+
+void Error::throwMe(MSC_RV err)
+{
+       throw Error(err);
+}
+
+
+OSStatus Error::osStatus() const
+{
+       return -1;      //@@@ preliminary
+}
+
+int Error::unixError() const
+{
+       return EINVAL;  //@@@ preliminary
+}
+
+
+//
+// Open a connection with PCSC layer information.
+// The ReaderState fields required are the slot name and the ATR.
+//
+Connection::Connection()
+       : mIsOpen(false), mCurrentTransaction(NULL)
+{
+}
+
+Connection::~Connection()
+{
+       assert(!mCurrentTransaction);
+       close();
+}
+
+void Connection::open(const PCSC::ReaderState &reader, unsigned share)
+{
+       // fill in the minimum needed to identify the card
+       MSCTokenInfo info;
+       
+       // set slot name in info
+       strncpy(info.slotName, reader.name(), MAX_READERNAME);
+       
+       // set ATR in info
+       assert(reader.length() <= MAX_ATR_SIZE);
+       memcpy(info.tokenId, reader.data(), reader.length());
+       info.tokenIdLength = reader.length();
+       
+       // establish Muscle-level connection to card
+       Error::check(::MSCEstablishConnection(&info, share, NULL, 0, this));
+       mIsOpen = true;
+       secdebug("muscle", "%p opened %s", this, info.slotName);
+       
+       // pull initial status
+       updateStatus();
+}
+
+void Connection::close()
+{
+       if (mIsOpen) {
+               secdebug("muscle", "%p closing", this);
+               Error::check(::MSCReleaseConnection(this, SCARD_LEAVE_CARD));
+               mIsOpen = false;
+       }
+}
+
+
+void Connection::begin(Transaction *trans)
+{
+       assert(!mCurrentTransaction);
+       Error::check(::MSCBeginTransaction(this));
+       secdebug("muscle", "%p start transaction %p", this, trans);
+       mCurrentTransaction = trans;
+}
+
+void Connection::end(Transaction *trans)
+{
+       assert(trans == mCurrentTransaction);
+       secdebug("muscle", "%p end transaction %p", this, trans);
+       Error::check(::MSCEndTransaction(this, SCARD_LEAVE_CARD));
+       mCurrentTransaction = NULL;
+}
+
+
+//
+// Update card status (cached in the Connection object)
+//
+void Connection::updateStatus()
+{
+       Error::check(::MSCGetStatus(this, this));
+}
+
+
+//
+// Get all items off the card
+//
+template <class Info, class Item, MSC_RV (*list)(MSCTokenConnection *, MSCUChar8, Info *)>
+static void get(Connection *conn, Connection::ItemSet &items)
+{
+       Info info;
+       MSCUChar8 seq = MSC_SEQUENCE_RESET;
+       for (;;) {
+               switch (MSC_RV rc = list(conn, seq, &info)) {
+               case MSC_SEQUENCE_END:
+                       return;
+               case MSC_SUCCESS:
+                       items.insert(new Item(info));
+                       seq = MSC_SEQUENCE_NEXT;
+                       break;
+               default:
+                       Error::throwMe(rc);
+               }
+       }
+}
+
+void Connection::getItems(ItemSet &result, bool getKeys, bool getOthers)
+{
+       ItemSet items;
+       if (getKeys)
+               get<MSCKeyInfo, Key, MSCListKeys>(this, items);
+       if (getOthers)
+               get<MSCObjectInfo, Object, MSCListObjects>(this, items);
+       items.swap(result);
+}
+
+
+//
+// Transaction monitors
+//
+Transaction::Transaction(Connection &con)
+    : connection(con)
+{
+    connection.begin(this);
+}
+
+Transaction::~Transaction()
+{
+    connection.end(this);
+}
+
+
+//
+// ACLs (Muscle style)
+//
+static void aclForm(string &s, MSCUShort16 acl, int offset, char c)
+{
+       for (int n = 0; n < 5; n++) {
+               char p = '-';
+               switch (acl) {
+               case MSC_AUT_ALL:               p = c; break;
+               case MSC_AUT_NONE:              break;
+               default:                                if (acl & (MSC_AUT_PIN_0 << n)) p = c; break;
+               }
+               s[3 * n + offset] = p;
+       }
+}
+
+string ACL::form(char ue) const
+{
+       string r = "---------------";
+       aclForm(r, mRead, 0, 'r');
+       aclForm(r, mWrite, 1, 'w');
+       aclForm(r, mErase, 2, ue);
+       return r;
+}
+
+
+//
+// Keys and objects
+//
+CardItem::~CardItem()
+{ /* virtual */ }
+
+
+Key::Key(const MSCKeyInfo &info)
+       : MSCKeyInfo(info)
+{
+       snprintf(mKeyName, sizeof(mKeyName), "K%d", id());
+}
+
+
+const ACL &Key::acl() const            { return reinterpret_cast<const ACL &>(keyACL); }
+ACL &Key::acl()                                        { return reinterpret_cast<ACL &>(keyACL); }
+
+const char *Key::name() const  { return mKeyName; }
+unsigned Key::size() const             { return keySize; }
+
+void Key::debugDump()
+{
+       printf("Key %d type %d size %d mode=0x%x dir=0x%x ACL %s\n",
+               keyNum, keyType, keySize, mode(), operations(), acl().form('u').c_str());
+}
+
+const char *Object::name() const { return objectID; }
+unsigned Object::size() const  { return objectSize; }
+
+const ACL &Object::acl() const { return reinterpret_cast<const ACL &>(objectACL); }
+ACL &Object::acl()                             { return reinterpret_cast<ACL &>(objectACL); }
+
+void Object::debugDump()
+{
+       printf("Object %s size %d ACL %s\n",
+               objectID, objectSize, acl().form('e').c_str());
+}
+
+
+}      // namespace Muscle
+}      // namespace Security