Browse Source

Add better FCP reading, hopeful osx support and stop scanning default af by default.

Thomas Kerber 2 years ago
parent
commit
864907ecef
5 changed files with 57 additions and 47 deletions
  1. 2
    1
      README.md
  2. 3
    19
      src/fs/mod.rs
  3. 5
    3
      src/fs/path.rs
  4. 41
    23
      src/pcsc.rs
  5. 6
    1
      src/scan.rs

+ 2
- 1
README.md View File

@@ -21,7 +21,8 @@ a while. For a list of options, run `troll help scan`. In particular, the
21 21
 `--pin` option for logging in (this is more important during the extraction
22 22
 phase however), and `--af` for supplying the AF names on the card. Troll can
23 23
 also attempt to extract available AFs from EF.DIR, however many proprietary
24
-cards do not supply this.
24
+cards do not supply this. If not `--af` flag is supplied, troll will scan the
25
+default af only.
25 26
 
26 27
 It may happen that troll encounters some recursive directory structures. Use
27 28
 the `--filter` flag to apply basic filtering rules to attempt to catch these.

+ 3
- 19
src/fs/mod.rs View File

@@ -414,20 +414,11 @@ impl Capabilities {
414 414
         if test_result(&try!(handle.send_apdu(cla, 0xb2, 0x01, 0x14, &[], 0x00))[..]) {
415 415
             ret.add(Capability::ReadRecordShortEF);
416 416
         }
417
-        if test_result(&try!(handle.send_apdu(cla, 0xca, 0x00, 0x00, &[], 0x00))[..]) {
417
+        let res = try!(handle.send_apdu(cla, 0xca, 0x00, 0x00, &[], 0x00));
418
+        if &res[..] == &[0x6a, 0x86] || test_result(&res[..]) {
418 419
             ret.add(Capability::ReadData);
419 420
         }
420
-        // Filter out ReturnFCP and ReturnFMD that lie.
421
-        if ret.has(Capability::SelectMF) {
422
-            let res = try!(handle.send_apdu(cla, 0xa4, 0x00, 0x04, &[0x3f, 0x00], 0x00));
423
-            if res.len() != 2 || res[0] != 0x61 {
424
-                ret.rm(Capability::ReturnFCP);
425
-            }
426
-            let res = try!(handle.send_apdu(cla, 0xa4, 0x00, 0x08, &[0x3f, 0x00], 0x00));
427
-            if res.len() != 2 || res[0] != 0x61 {
428
-                ret.rm(Capability::ReturnFMD);
429
-            }
430
-        }
421
+        info!("Card capabilities: {:?}", ret.list());
431 422
         Ok(ret)
432 423
     }
433 424
 
@@ -436,13 +427,6 @@ impl Capabilities {
436 427
         self
437 428
     }
438 429
 
439
-    pub fn rm(&mut self, c: Capability) -> &mut Self {
440
-        if self.has(c) {
441
-            self.0 -= c.raw();
442
-        }
443
-        self
444
-    }
445
-
446 430
     pub fn has(&self, c: Capability) -> bool {
447 431
         (self.0 & c.raw()) != 0
448 432
     }

+ 5
- 3
src/fs/path.rs View File

@@ -45,13 +45,15 @@ impl<'a, 'b: 'a> FileSystemHandle for PathHandle<'a, 'b> {
45 45
                 }
46 46
                 data[l-2] = i as u8;
47 47
                 data[l-1] = j as u8;
48
-                let res = try!(self.send_apdu(0xa4, 0x08, 0x04, &data[..], 0x00));
48
+                let res = try!(self.send_apdu(0xa4, 0x08, 0x04, &data[..], 0x100));
49 49
                 if &res[res.len()-2..] == &[0x6a, 0x82] {
50 50
                     continue;
51 51
                 }
52 52
                 try!(try_sw(&res[..]));
53
-                let df = if res[res.len()-2] != 0x61 {
54
-                    warn!("Error termining if {} is DF: {}",
53
+                let df = if res[res.len()-2] == 0x90 {
54
+                    is_df_fcp(&res[..res.len()-2])
55
+                } else if res[res.len()-2] != 0x61 {
56
+                    warn!("Error determining if {} is DF: {}",
55 57
                           data.to_hex(),
56 58
                           Error::unexpected_result("expected response FCP template", res));
57 59
                     true

+ 41
- 23
src/pcsc.rs View File

@@ -3,21 +3,37 @@ use std::ffi::CStr;
3 3
 use std::ptr::{null, null_mut};
4 4
 use std::error::Error as StdError;
5 5
 use std::fmt::{self, Debug, Display, Formatter};
6
-use self::libc::{c_void, c_ulong, c_char, c_long};
6
+use self::libc::{c_void, c_ulong, c_char, c_long, c_uchar};
7 7
 use rustc_serialize::hex::{ToHex};
8 8
 
9 9
 #[repr(C)]
10
-struct SCardIORequest(c_ulong, c_ulong, c_long);
10
+struct SCardIORequest(c_ulong, c_ulong);
11
+
12
+#[cfg(target_os="macos")]
13
+type CDWord = u32;
14
+#[cfg(target_os="macos")]
15
+type CByte = u8;
16
+#[cfg(target_os="macos")]
17
+type CLong = i32;
18
+#[cfg(not(target_os="macos"))]
19
+type CDWord = c_ulong;
20
+#[cfg(not(target_os="macos"))]
21
+type CByte = c_uchar;
22
+#[cfg(not(target_os="macos"))]
23
+type CLong = c_long;
24
+
25
+type CContext = CLong;
26
+type CHandle = CLong;
11 27
 
12 28
 #[link(name="pcsclite")]
13 29
 extern {
14
-    fn SCardEstablishContext(scope: c_ulong, res1: *mut c_void, res2: *mut c_void, context: *mut c_ulong) -> c_long;
15
-    fn SCardReleaseContext(context: c_ulong) -> c_long;
16
-    fn SCardListReaders(context: c_ulong, groups: *const u8, readers: *mut u8, readerslen: *mut c_ulong) -> c_long;
17
-    fn SCardConnect(context: c_ulong, reader: *const u8, share_mode: c_ulong, preferred_protocols: c_ulong, handle: *mut c_ulong, active_procotol: *mut c_ulong) -> c_long;
18
-    fn SCardDisconnect(handle: c_ulong, disposition: c_ulong) -> c_long;
19
-    fn SCardTransmit(handle: c_ulong, sendPci: *const SCardIORequest, sendBuffer: *const u8, sendLength: c_ulong, recvPci: *const SCardIORequest, recvBuffer: *mut u8, recvLength: *mut c_ulong) -> c_long;
20
-    fn pcsc_stringify_error(err: c_long) -> *const c_char;
30
+    fn SCardEstablishContext(scope: CDWord, res1: *mut c_void, res2: *mut c_void, context: *mut CContext) -> CLong;
31
+    fn SCardReleaseContext(context: CContext) -> CLong;
32
+    fn SCardListReaders(context: CContext, groups: *const c_char, readers: *mut c_char, readerslen: *mut CDWord) -> CLong;
33
+    fn SCardConnect(context: CContext, reader: *const c_char, share_mode: CDWord, preferred_protocols: CDWord, handle: *mut CHandle, active_procotol: *mut CDWord) -> CLong;
34
+    fn SCardDisconnect(handle: CHandle, disposition: CDWord) -> CLong;
35
+    fn SCardTransmit(handle: CHandle, sendPci: *const SCardIORequest, sendBuffer: *const CByte, sendLength: CDWord, recvPci: *const SCardIORequest, recvBuffer: *mut CByte, recvLength: *mut CDWord) -> CLong;
36
+    fn pcsc_stringify_error(err: CLong) -> *const c_char;
21 37
     static g_rgSCardT0Pci: SCardIORequest; 
22 38
     static g_rgSCardT1Pci: SCardIORequest; 
23 39
     static g_rgSCardRawPci: SCardIORequest; 
@@ -30,7 +46,7 @@ pub enum ShareMode {
30 46
 }
31 47
 
32 48
 impl ShareMode {
33
-    fn raw(&self) -> c_ulong {
49
+    fn raw(&self) -> CDWord {
34 50
         match self {
35 51
             &ShareMode::Exclusive => 1,
36 52
             &ShareMode::Shared => 2,
@@ -48,7 +64,7 @@ pub enum Protocol {
48 64
 }
49 65
 
50 66
 impl Protocol {
51
-    fn raw(&self) -> c_ulong {
67
+    fn raw(&self) -> CDWord {
52 68
         match self {
53 69
             &Protocol::Undefined => 0,
54 70
             &Protocol::T0 => 1,
@@ -57,7 +73,7 @@ impl Protocol {
57 73
         }
58 74
     }
59 75
 
60
-    fn from_raw(raw: c_ulong) -> Self {
76
+    fn from_raw(raw: CDWord) -> Self {
61 77
         match raw {
62 78
             1 => Protocol::T0,
63 79
             2 => Protocol::T1,
@@ -84,7 +100,7 @@ pub enum Scope {
84 100
 }
85 101
 
86 102
 impl Scope {
87
-    fn raw(self) -> c_ulong {
103
+    fn raw(self) -> CDWord {
88 104
         match self {
89 105
             Scope::User => 0,
90 106
             Scope::Terminal => 1,
@@ -94,7 +110,7 @@ impl Scope {
94 110
     }
95 111
 }
96 112
 
97
-pub struct Error(c_long);
113
+pub struct Error(CLong);
98 114
 
99 115
 impl StdError for Error {
100 116
     fn description(&self) -> &str {
@@ -117,11 +133,11 @@ impl Debug for Error {
117 133
     }
118 134
 }
119 135
 
120
-pub struct Context(c_ulong);
136
+pub struct Context(CContext);
121 137
 
122 138
 impl Context {
123 139
     pub fn new(scope: Scope) -> Result<Self, Error> {
124
-        let mut c: c_ulong = 0;
140
+        let mut c: CContext = 0;
125 141
         let err = unsafe {
126 142
             SCardEstablishContext(scope.raw(), null_mut(), null_mut(), &mut c)
127 143
         };
@@ -142,26 +158,26 @@ impl Drop for Context {
142 158
     }
143 159
 }
144 160
 
145
-pub struct Handle<'a>(c_ulong, &'a Context, Protocol);
161
+pub struct Handle<'a>(CHandle, &'a Context, Protocol);
146 162
 
147 163
 impl<'a> Handle<'a> {
148 164
     pub fn default(context: &'a Context, share_mode: ShareMode, preferred_protocols: &[Protocol]) -> Result<Self, Error> {
149
-        let mut readers_size: c_ulong = 0;
165
+        let mut readers_size: CDWord = 0;
150 166
         let err = unsafe {
151 167
             SCardListReaders(context.0, null(), null_mut(), &mut readers_size)
152 168
         };
153 169
         if err != 0 {
154 170
             return Err(Error(err))
155 171
         }
156
-        let mut readers = vec![0u8; readers_size as usize];
172
+        let mut readers = vec![0i8; readers_size as usize];
157 173
         let err = unsafe {
158 174
             SCardListReaders(context.0, null(), readers.as_mut_ptr(), &mut readers_size)
159 175
         };
160 176
         if err != 0 {
161 177
             return Err(Error(err))
162 178
         }
163
-        let mut handle: c_ulong = 0;
164
-        let mut active_protocol: c_ulong = 0;
179
+        let mut handle: CHandle = 0;
180
+        let mut active_protocol: CDWord = 0;
165 181
         let mut preferred_protocols_raw = 0;
166 182
         for p in preferred_protocols {
167 183
             preferred_protocols_raw |= p.raw();
@@ -178,7 +194,7 @@ impl<'a> Handle<'a> {
178 194
 
179 195
     pub fn send_apdu(&mut self, cla: u8, ins: u8, p1: u8, p2: u8, data: &[u8], retlen: u16) -> Result<Vec<u8>, Error> {
180 196
         let mut res = vec![0u8; retlen as usize + 2];
181
-        let mut reslen = retlen as c_ulong + 2;
197
+        let mut reslen = retlen as CDWord + 2;
182 198
         let mut cmd = Vec::with_capacity(6 + data.len());
183 199
         cmd.push(cla);
184 200
         cmd.push(ins);
@@ -190,6 +206,8 @@ impl<'a> Handle<'a> {
190 206
         cmd.extend(data);
191 207
         if retlen != 0 && retlen < 0x100{
192 208
             cmd.push(retlen as u8);
209
+        } else if retlen == 0x100 {
210
+            cmd.push(0x00);
193 211
         } else if retlen != 0 {
194 212
             cmd.push(0u8);
195 213
             cmd.push((retlen >> 8) as u8);
@@ -197,7 +215,7 @@ impl<'a> Handle<'a> {
197 215
         }
198 216
         debug!("APDU SEND: {}", cmd.to_hex());
199 217
         let err = unsafe {
200
-            SCardTransmit(self.0, self.2.io_request(), cmd.as_ptr(), cmd.len() as c_ulong, null(), res.as_mut_ptr(), &mut reslen)
218
+            SCardTransmit(self.0, self.2.io_request(), cmd.as_ptr(), cmd.len() as CDWord, null(), res.as_mut_ptr(), &mut reslen)
201 219
         };
202 220
         if err == 0 {
203 221
             res.truncate(reslen as usize);

+ 6
- 1
src/scan.rs View File

@@ -115,7 +115,7 @@ pub fn main(args: Vec<String>) {
115 115
             exit(2);
116 116
         }
117 117
     };
118
-    let mut afs = vec![Vec::new()];
118
+    let mut afs = Vec::new();
119 119
     for af in matches.opt_strs("a").iter() {
120 120
         afs.push(match af.from_hex() {
121 121
             Ok(v) => v,
@@ -128,6 +128,11 @@ pub fn main(args: Vec<String>) {
128 128
     if matches.opt_present("ef-dir") {
129 129
         unimplemented!();
130 130
     }
131
+    if afs.len() == 0 {
132
+        afs.push(Vec::new());
133
+    } else {
134
+        afs.sort();
135
+    }
131 136
     let caps = match fs::Capabilities::test_for(&mut handle, cla, true) {
132 137
         Ok(v) => v,
133 138
         Err(e) => {

Loading…
Cancel
Save