]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_utilities/lib/muscle++.cpp
Security-59754.41.1.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 #if TARGET_OS_OSX
33
34 namespace Security {
35 namespace Muscle {
36
37
38 //
39 // PCSC domain errors
40 //
41 Error::Error(MSC_RV err) : error(err)
42 {
43 SECURITY_EXCEPTION_THROW_OTHER(this, err, (char *)"muscle");
44 secnotice("security_exception", "muscle: %d", err);
45 }
46
47
48 const char *Error::what() const _NOEXCEPT
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 if (reader.length() > MAX_ATR_SIZE) {
96 Error::throwMe(MSC_INVALID_PARAMETER);
97 }
98
99 memcpy(info.tokenId, reader.data(), reader.length());
100 info.tokenIdLength = (MSCULong32)reader.length();
101
102 // establish Muscle-level connection to card
103 Error::check(::MSCEstablishConnection(&info, share, NULL, 0, this));
104 mIsOpen = true;
105 secinfo("muscle", "%p opened %s", this, info.slotName);
106
107 // pull initial status
108 updateStatus();
109 }
110
111 void Connection::close()
112 {
113 if (mIsOpen) {
114 secinfo("muscle", "%p closing", this);
115 Error::check(::MSCReleaseConnection(this, SCARD_LEAVE_CARD));
116 mIsOpen = false;
117 }
118 }
119
120
121 void Connection::begin(Transaction *trans)
122 {
123 assert(!mCurrentTransaction);
124 Error::check(::MSCBeginTransaction(this));
125 secinfo("muscle", "%p start transaction %p", this, trans);
126 mCurrentTransaction = trans;
127 }
128
129 void Connection::end(Transaction *trans)
130 {
131 assert(trans == mCurrentTransaction);
132 secinfo("muscle", "%p end transaction %p", this, trans);
133 Error::check(::MSCEndTransaction(this, SCARD_LEAVE_CARD));
134 mCurrentTransaction = NULL;
135 }
136
137
138 //
139 // Update card status (cached in the Connection object)
140 //
141 void Connection::updateStatus()
142 {
143 Error::check(::MSCGetStatus(this, this));
144 }
145
146
147 //
148 // Get all items off the card
149 //
150 template <class Info, class Item, MSC_RV (*list)(MSCTokenConnection *, MSCUChar8, Info *)>
151 static void get(Connection *conn, Connection::ItemSet &items)
152 {
153 Info info;
154 MSCUChar8 seq = MSC_SEQUENCE_RESET;
155 for (;;) {
156 switch (MSC_RV rc = list(conn, seq, &info)) {
157 case MSC_SEQUENCE_END:
158 return;
159 case MSC_SUCCESS:
160 items.insert(new Item(info));
161 seq = MSC_SEQUENCE_NEXT;
162 break;
163 default:
164 Error::throwMe(rc);
165 }
166 }
167 }
168
169 void Connection::getItems(ItemSet &result, bool getKeys, bool getOthers)
170 {
171 ItemSet items;
172 if (getKeys)
173 get<MSCKeyInfo, Key, MSCListKeys>(this, items);
174 if (getOthers)
175 get<MSCObjectInfo, Object, MSCListObjects>(this, items);
176 items.swap(result);
177 }
178
179
180 //
181 // Transaction monitors
182 //
183 Transaction::Transaction(Connection &con)
184 : connection(con)
185 {
186 connection.begin(this);
187 }
188
189 Transaction::~Transaction()
190 {
191 connection.end(this);
192 }
193
194
195 //
196 // ACLs (Muscle style)
197 //
198 static void aclForm(string &s, MSCUShort16 acl, int offset, char c)
199 {
200 for (int n = 0; n < 5; n++) {
201 char p = '-';
202 switch (acl) {
203 case MSC_AUT_ALL: p = c; break;
204 case MSC_AUT_NONE: break;
205 default: if (acl & (MSC_AUT_PIN_0 << n)) p = c; break;
206 }
207 s[3 * n + offset] = p;
208 }
209 }
210
211 string ACL::form(char ue) const
212 {
213 string r = "---------------";
214 aclForm(r, mRead, 0, 'r');
215 aclForm(r, mWrite, 1, 'w');
216 aclForm(r, mErase, 2, ue);
217 return r;
218 }
219
220
221 //
222 // Keys and objects
223 //
224 CardItem::~CardItem()
225 { /* virtual */ }
226
227
228 Key::Key(const MSCKeyInfo &info)
229 : MSCKeyInfo(info)
230 {
231 snprintf(mKeyName, sizeof(mKeyName), "K%d", id());
232 }
233
234
235 const ACL &Key::acl() const { return reinterpret_cast<const ACL &>(keyACL); }
236 ACL &Key::acl() { return reinterpret_cast<ACL &>(keyACL); }
237
238 const char *Key::name() const { return mKeyName; }
239 unsigned Key::size() const { return keySize; }
240
241 void Key::debugDump()
242 {
243 printf("Key %d type %d size %d mode=0x%x dir=0x%x ACL %s\n",
244 keyNum, keyType, keySize, mode(), operations(), acl().form('u').c_str());
245 }
246
247 const char *Object::name() const { return objectID; }
248 unsigned Object::size() const { return objectSize; }
249
250 const ACL &Object::acl() const { return reinterpret_cast<const ACL &>(objectACL); }
251 ACL &Object::acl() { return reinterpret_cast<ACL &>(objectACL); }
252
253 void Object::debugDump()
254 {
255 printf("Object %s size %d ACL %s\n",
256 objectID, objectSize, acl().form('e').c_str());
257 }
258
259
260 } // namespace Muscle
261 } // namespace Security
262
263 #endif //TARGET_OS_OSX