]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2004,2011-2012,2014 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
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()); | |
427c49bc | 95 | info.tokenIdLength = (MSCULong32)reader.length(); |
b1ab9ed8 A |
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 |