]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_utilities/lib/muscle++.cpp
Security-57337.40.85.tar.gz
[apple/security.git] / OSX / libsecurity_utilities / lib / muscle++.cpp
1 /*
2 * Copyright (c) 2004,2011-2012,2014 Apple 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
33 namespace Security {
34 namespace Muscle {
35
36
37 //
38 // PCSC domain errors
39 //
40 Error::Error(MSC_RV err) : error(err)
41 {
42 SECURITY_EXCEPTION_THROW_OTHER(this, err, (char *)"muscle");
43 }
44
45
46 const char *Error::what() const throw ()
47 {
48 return msc_error(error);
49 }
50
51
52 void Error::throwMe(MSC_RV err)
53 {
54 throw Error(err);
55 }
56
57
58 OSStatus Error::osStatus() const
59 {
60 return -1; //@@@ preliminary
61 }
62
63 int 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 //
73 Connection::Connection()
74 : mIsOpen(false), mCurrentTransaction(NULL)
75 {
76 }
77
78 Connection::~Connection()
79 {
80 assert(!mCurrentTransaction);
81 close();
82 }
83
84 void 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
106 void 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
116 void 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
124 void 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 //
136 void Connection::updateStatus()
137 {
138 Error::check(::MSCGetStatus(this, this));
139 }
140
141
142 //
143 // Get all items off the card
144 //
145 template <class Info, class Item, MSC_RV (*list)(MSCTokenConnection *, MSCUChar8, Info *)>
146 static 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
164 void 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 //
178 Transaction::Transaction(Connection &con)
179 : connection(con)
180 {
181 connection.begin(this);
182 }
183
184 Transaction::~Transaction()
185 {
186 connection.end(this);
187 }
188
189
190 //
191 // ACLs (Muscle style)
192 //
193 static 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
206 string 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 //
219 CardItem::~CardItem()
220 { /* virtual */ }
221
222
223 Key::Key(const MSCKeyInfo &info)
224 : MSCKeyInfo(info)
225 {
226 snprintf(mKeyName, sizeof(mKeyName), "K%d", id());
227 }
228
229
230 const ACL &Key::acl() const { return reinterpret_cast<const ACL &>(keyACL); }
231 ACL &Key::acl() { return reinterpret_cast<ACL &>(keyACL); }
232
233 const char *Key::name() const { return mKeyName; }
234 unsigned Key::size() const { return keySize; }
235
236 void 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
242 const char *Object::name() const { return objectID; }
243 unsigned Object::size() const { return objectSize; }
244
245 const ACL &Object::acl() const { return reinterpret_cast<const ACL &>(objectACL); }
246 ACL &Object::acl() { return reinterpret_cast<ACL &>(objectACL); }
247
248 void 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