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