Struct pcsc::Transaction

source ·
pub struct Transaction<'tx> { /* private fields */ }
Expand description

An exclusive transaction with a card.

A transaction ensures uninterrupted access to the card for its duration. All other operations performed on the same underlying card (even from other processes) will block until the transaction is finished.

Implementations§

source§

impl<'tx> Transaction<'tx>

source

pub fn end( self, disposition: Disposition ) -> Result<(), (Transaction<'tx>, Error)>

End the transaction.

In case of error, ownership of the transaction is returned to the caller.

This function wraps SCardEndTransaction (pcsclite, MSDN).

Note

Transaction implements Drop which automatically ends the transaction using Disposition::LeaveCard; you only need to call this function if you want to handle errors or use a different disposition method.

Examples found in repository?
examples/connect-owned.rs (line 67)
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
fn main() {
    // Get a context.
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    // List connected readers.
    let readers = ctx.list_readers_owned().expect("failed to list readers");
    println!("Readers: {:?}", readers);

    if readers.is_empty() {
        return;
    }

    {
        // Try to connect to a card in the first reader.
        let mut card = ctx
            .connect(&readers[0], ShareMode::Shared, Protocols::ANY)
            .expect("failed to connect to card");

        {
            // Start an exclusive transaction (not required -- can work on card directly).
            let tx = card.transaction().expect("failed to begin card transaction");

            // Get the card status.
            let status = tx.status2_owned().expect("failed to get card status");
            println!("Reader names from status: {:?}", status.reader_names());
            if let Some(protocol) = status.protocol2() {
                println!("Protocol from status: {:?}", protocol);
            } else {
                println!("Protocol from status: directly connected");
            }
            println!("ATR from status: {:?}", status.atr());

            // Send some harmless APDU to the card.
            if let Some(_) = status.protocol2() {
                let apdu = b"\x00\xa4\x04\x00\x08\x31\x54\x49\x43\x2e\x49\x43\x41";
                let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
                let rapdu = tx
                    .transmit(apdu, &mut rapdu_buf)
                    .expect("failed to transmit APDU to card");
                println!("RAPDU: {:?}", rapdu);
            }

            // Get the card's ATR.
            let atr = tx
                .get_attribute_owned(Attribute::AtrString)
                .expect("failed to get ATR attribute");
            println!("ATR from attribute: {:?}", atr);

            // Get some attribute.
            let ifd_version = tx
                .get_attribute_owned(Attribute::VendorIfdVersion)
                .expect("failed to get vendor IFD version attribute");
            println!("Vendor IFD version: {:?}", ifd_version);

            // Get some other attribute.
            let vendor_name = tx
                .get_attribute_owned(Attribute::VendorName)
                .expect("failed to get vendor name attribute");
            println!("Vendor name: {}", String::from_utf8(vendor_name).unwrap());

            // Can either end explicity, which allows error handling,
            // and setting the disposition method, or leave it to drop, which
            // swallows any error and hardcodes LeaveCard.
            tx.end(Disposition::LeaveCard)
                .map_err(|(_, err)| err)
                .expect("failed to end transaction");
        }

        // Can either disconnect explicity, which allows error handling,
        // and setting the disposition method, or leave it to drop, which
        // swallows any error and hardcodes ResetCard.
        card.disconnect(Disposition::ResetCard)
            .map_err(|(_, err)| err)
            .expect("failed to disconnect from card");
    }

    // Can either release explicity, which allows error handling,
    // or leave it to drop, which swallows any error.
    // The function fails if there are any live clones.
    ctx.release()
        .map_err(|(_, err)| err)
        .expect("failed to release context");
}
More examples
Hide additional examples
examples/connect.rs (line 86)
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
fn main() {
    // Get a context.
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    // List connected readers.
    let mut readers_buf = [0; 2048];
    let readers = ctx
        .list_readers(&mut readers_buf)
        .expect("failed to list readers")
        .collect::<Vec<_>>();
    println!("Readers: {:?}", readers);

    if readers.is_empty() {
        return;
    }

    {
        // Try to connect to a card in the first reader.
        let mut card = ctx
            .connect(readers[0], ShareMode::Shared, Protocols::ANY)
            .expect("failed to connect to card");

        {
            // Start an exclusive transaction (not required -- can work on card directly).
            let tx = card.transaction().expect("failed to begin card transaction");

            // Get the card status.
            let (names_len, _atr_len) = tx.status2_len().expect("failed to get the status length");
            let mut names_buf = vec![0; names_len];
            let mut atr_buf = [0; MAX_ATR_SIZE];
            let status = tx
                .status2(&mut names_buf, &mut atr_buf)
                .expect("failed to get card status");
            println!("Status from status: {:?}", status.status());
            println!(
                "Reader names from status: {:?}",
                status.reader_names().collect::<Vec<_>>()
            );
            if let Some(protocol) = status.protocol2() {
                println!("Protocol from status: {:?}", protocol);
            } else {
                println!("Protocol from status: directly connected");
            }
            println!("ATR from status: {:?}", status.atr());

            // Send some harmless APDU to the card.
            if let Some(_) = status.protocol2() {
                let apdu = b"\x00\xa4\x04\x00\x08\x31\x54\x49\x43\x2e\x49\x43\x41";
                let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
                let rapdu = tx
                    .transmit(apdu, &mut rapdu_buf)
                    .expect("failed to transmit APDU to card");
                println!("RAPDU: {:?}", rapdu);
            }

            // Get the card's ATR.
            let mut atr_buf = [0; MAX_ATR_SIZE];
            let atr = tx
                .get_attribute(Attribute::AtrString, &mut atr_buf)
                .expect("failed to get ATR attribute");
            println!("ATR from attribute: {:?}", atr);

            // Get some attribute.
            let mut ifd_version_buf = [0; 4];
            let ifd_version = tx
                .get_attribute(Attribute::VendorIfdVersion, &mut ifd_version_buf)
                .expect("failed to get vendor IFD version attribute");
            println!("Vendor IFD version: {:?}", ifd_version);

            // Get some other attribute.
            // This time we allocate a buffer of the needed length.
            let vendor_name_len = tx
                .get_attribute_len(Attribute::VendorName)
                .expect("failed to get the vendor name attribute length");
            let mut vendor_name_buf = vec![0; vendor_name_len];
            let vendor_name = tx
                .get_attribute(Attribute::VendorName, &mut vendor_name_buf)
                .expect("failed to get vendor name attribute");
            println!("Vendor name: {}", std::str::from_utf8(vendor_name).unwrap());

            // Can either end explicity, which allows error handling,
            // and setting the disposition method, or leave it to drop, which
            // swallows any error and hardcodes LeaveCard.
            tx.end(Disposition::LeaveCard)
                .map_err(|(_, err)| err)
                .expect("failed to end transaction");
        }

        // Can either disconnect explicity, which allows error handling,
        // and setting the disposition method, or leave it to drop, which
        // swallows any error and hardcodes ResetCard.
        card.disconnect(Disposition::ResetCard)
            .map_err(|(_, err)| err)
            .expect("failed to disconnect from card");
    }

    // Can either release explicity, which allows error handling,
    // or leave it to drop, which swallows any error.
    // The function fails if there are any live clones.
    ctx.release()
        .map_err(|(_, err)| err)
        .expect("failed to release context");
}

Methods from Deref<Target = Card>§

source

pub fn status(&self) -> Result<(Status, Protocol), Error>

👎Deprecated since 2.3.0: Use status2() or status2_owned() instead.

Get current info on the card.

This function wraps SCardStatus (pcsclite, MSDN).

Deprecated

The reader names and ATR return values are missing.

When there is no active protocol (as when connecting to the reader directly), this function panics.

Use status2() or status2_owned() instead.

source

pub fn status2<'names_buf, 'atr_buf>( &self, names_buffer: &'names_buf mut [u8], atr_buffer: &'atr_buf mut [u8] ) -> Result<CardStatus<'names_buf, 'atr_buf>, Error>

Get current info on the card.

names_buffer is a buffer that should be large enough to hold all of the reader names.

atr_buffer is a buffer that should be large enough to hold the ATR. The recommended size is MAX_ATR_SIZE, which should be always sufficent.

The function status2_len can be used to find the exact required lengths.

If the buffers are not large enough to hold all of the names or the ATR, Error::InsufficientBuffer is returned.

This function wraps SCardStatus (pcsclite, MSDN).

Examples found in repository?
examples/connect.rs (line 34)
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
fn main() {
    // Get a context.
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    // List connected readers.
    let mut readers_buf = [0; 2048];
    let readers = ctx
        .list_readers(&mut readers_buf)
        .expect("failed to list readers")
        .collect::<Vec<_>>();
    println!("Readers: {:?}", readers);

    if readers.is_empty() {
        return;
    }

    {
        // Try to connect to a card in the first reader.
        let mut card = ctx
            .connect(readers[0], ShareMode::Shared, Protocols::ANY)
            .expect("failed to connect to card");

        {
            // Start an exclusive transaction (not required -- can work on card directly).
            let tx = card.transaction().expect("failed to begin card transaction");

            // Get the card status.
            let (names_len, _atr_len) = tx.status2_len().expect("failed to get the status length");
            let mut names_buf = vec![0; names_len];
            let mut atr_buf = [0; MAX_ATR_SIZE];
            let status = tx
                .status2(&mut names_buf, &mut atr_buf)
                .expect("failed to get card status");
            println!("Status from status: {:?}", status.status());
            println!(
                "Reader names from status: {:?}",
                status.reader_names().collect::<Vec<_>>()
            );
            if let Some(protocol) = status.protocol2() {
                println!("Protocol from status: {:?}", protocol);
            } else {
                println!("Protocol from status: directly connected");
            }
            println!("ATR from status: {:?}", status.atr());

            // Send some harmless APDU to the card.
            if let Some(_) = status.protocol2() {
                let apdu = b"\x00\xa4\x04\x00\x08\x31\x54\x49\x43\x2e\x49\x43\x41";
                let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
                let rapdu = tx
                    .transmit(apdu, &mut rapdu_buf)
                    .expect("failed to transmit APDU to card");
                println!("RAPDU: {:?}", rapdu);
            }

            // Get the card's ATR.
            let mut atr_buf = [0; MAX_ATR_SIZE];
            let atr = tx
                .get_attribute(Attribute::AtrString, &mut atr_buf)
                .expect("failed to get ATR attribute");
            println!("ATR from attribute: {:?}", atr);

            // Get some attribute.
            let mut ifd_version_buf = [0; 4];
            let ifd_version = tx
                .get_attribute(Attribute::VendorIfdVersion, &mut ifd_version_buf)
                .expect("failed to get vendor IFD version attribute");
            println!("Vendor IFD version: {:?}", ifd_version);

            // Get some other attribute.
            // This time we allocate a buffer of the needed length.
            let vendor_name_len = tx
                .get_attribute_len(Attribute::VendorName)
                .expect("failed to get the vendor name attribute length");
            let mut vendor_name_buf = vec![0; vendor_name_len];
            let vendor_name = tx
                .get_attribute(Attribute::VendorName, &mut vendor_name_buf)
                .expect("failed to get vendor name attribute");
            println!("Vendor name: {}", std::str::from_utf8(vendor_name).unwrap());

            // Can either end explicity, which allows error handling,
            // and setting the disposition method, or leave it to drop, which
            // swallows any error and hardcodes LeaveCard.
            tx.end(Disposition::LeaveCard)
                .map_err(|(_, err)| err)
                .expect("failed to end transaction");
        }

        // Can either disconnect explicity, which allows error handling,
        // and setting the disposition method, or leave it to drop, which
        // swallows any error and hardcodes ResetCard.
        card.disconnect(Disposition::ResetCard)
            .map_err(|(_, err)| err)
            .expect("failed to disconnect from card");
    }

    // Can either release explicity, which allows error handling,
    // or leave it to drop, which swallows any error.
    // The function fails if there are any live clones.
    ctx.release()
        .map_err(|(_, err)| err)
        .expect("failed to release context");
}
source

pub fn status2_len(&self) -> Result<(usize, usize), Error>

Get the needed length of the names buffer (first result) and ATR buffer (second result) to be passed to status2.

This function wraps SCardStatus (pcsclite, MSDN).

Examples found in repository?
examples/connect.rs (line 30)
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
fn main() {
    // Get a context.
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    // List connected readers.
    let mut readers_buf = [0; 2048];
    let readers = ctx
        .list_readers(&mut readers_buf)
        .expect("failed to list readers")
        .collect::<Vec<_>>();
    println!("Readers: {:?}", readers);

    if readers.is_empty() {
        return;
    }

    {
        // Try to connect to a card in the first reader.
        let mut card = ctx
            .connect(readers[0], ShareMode::Shared, Protocols::ANY)
            .expect("failed to connect to card");

        {
            // Start an exclusive transaction (not required -- can work on card directly).
            let tx = card.transaction().expect("failed to begin card transaction");

            // Get the card status.
            let (names_len, _atr_len) = tx.status2_len().expect("failed to get the status length");
            let mut names_buf = vec![0; names_len];
            let mut atr_buf = [0; MAX_ATR_SIZE];
            let status = tx
                .status2(&mut names_buf, &mut atr_buf)
                .expect("failed to get card status");
            println!("Status from status: {:?}", status.status());
            println!(
                "Reader names from status: {:?}",
                status.reader_names().collect::<Vec<_>>()
            );
            if let Some(protocol) = status.protocol2() {
                println!("Protocol from status: {:?}", protocol);
            } else {
                println!("Protocol from status: directly connected");
            }
            println!("ATR from status: {:?}", status.atr());

            // Send some harmless APDU to the card.
            if let Some(_) = status.protocol2() {
                let apdu = b"\x00\xa4\x04\x00\x08\x31\x54\x49\x43\x2e\x49\x43\x41";
                let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
                let rapdu = tx
                    .transmit(apdu, &mut rapdu_buf)
                    .expect("failed to transmit APDU to card");
                println!("RAPDU: {:?}", rapdu);
            }

            // Get the card's ATR.
            let mut atr_buf = [0; MAX_ATR_SIZE];
            let atr = tx
                .get_attribute(Attribute::AtrString, &mut atr_buf)
                .expect("failed to get ATR attribute");
            println!("ATR from attribute: {:?}", atr);

            // Get some attribute.
            let mut ifd_version_buf = [0; 4];
            let ifd_version = tx
                .get_attribute(Attribute::VendorIfdVersion, &mut ifd_version_buf)
                .expect("failed to get vendor IFD version attribute");
            println!("Vendor IFD version: {:?}", ifd_version);

            // Get some other attribute.
            // This time we allocate a buffer of the needed length.
            let vendor_name_len = tx
                .get_attribute_len(Attribute::VendorName)
                .expect("failed to get the vendor name attribute length");
            let mut vendor_name_buf = vec![0; vendor_name_len];
            let vendor_name = tx
                .get_attribute(Attribute::VendorName, &mut vendor_name_buf)
                .expect("failed to get vendor name attribute");
            println!("Vendor name: {}", std::str::from_utf8(vendor_name).unwrap());

            // Can either end explicity, which allows error handling,
            // and setting the disposition method, or leave it to drop, which
            // swallows any error and hardcodes LeaveCard.
            tx.end(Disposition::LeaveCard)
                .map_err(|(_, err)| err)
                .expect("failed to end transaction");
        }

        // Can either disconnect explicity, which allows error handling,
        // and setting the disposition method, or leave it to drop, which
        // swallows any error and hardcodes ResetCard.
        card.disconnect(Disposition::ResetCard)
            .map_err(|(_, err)| err)
            .expect("failed to disconnect from card");
    }

    // Can either release explicity, which allows error handling,
    // or leave it to drop, which swallows any error.
    // The function fails if there are any live clones.
    ctx.release()
        .map_err(|(_, err)| err)
        .expect("failed to release context");
}
source

pub fn status2_owned(&self) -> Result<CardStatusOwned, Error>

Get current info on the card, allocating buffers of the required size.

This function wraps SCardStatus (pcsclite, MSDN). It is an owned version of status2, calling status2_len to determine the required buffer sizes.

Examples found in repository?
examples/connect-owned.rs (line 27)
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
fn main() {
    // Get a context.
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    // List connected readers.
    let readers = ctx.list_readers_owned().expect("failed to list readers");
    println!("Readers: {:?}", readers);

    if readers.is_empty() {
        return;
    }

    {
        // Try to connect to a card in the first reader.
        let mut card = ctx
            .connect(&readers[0], ShareMode::Shared, Protocols::ANY)
            .expect("failed to connect to card");

        {
            // Start an exclusive transaction (not required -- can work on card directly).
            let tx = card.transaction().expect("failed to begin card transaction");

            // Get the card status.
            let status = tx.status2_owned().expect("failed to get card status");
            println!("Reader names from status: {:?}", status.reader_names());
            if let Some(protocol) = status.protocol2() {
                println!("Protocol from status: {:?}", protocol);
            } else {
                println!("Protocol from status: directly connected");
            }
            println!("ATR from status: {:?}", status.atr());

            // Send some harmless APDU to the card.
            if let Some(_) = status.protocol2() {
                let apdu = b"\x00\xa4\x04\x00\x08\x31\x54\x49\x43\x2e\x49\x43\x41";
                let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
                let rapdu = tx
                    .transmit(apdu, &mut rapdu_buf)
                    .expect("failed to transmit APDU to card");
                println!("RAPDU: {:?}", rapdu);
            }

            // Get the card's ATR.
            let atr = tx
                .get_attribute_owned(Attribute::AtrString)
                .expect("failed to get ATR attribute");
            println!("ATR from attribute: {:?}", atr);

            // Get some attribute.
            let ifd_version = tx
                .get_attribute_owned(Attribute::VendorIfdVersion)
                .expect("failed to get vendor IFD version attribute");
            println!("Vendor IFD version: {:?}", ifd_version);

            // Get some other attribute.
            let vendor_name = tx
                .get_attribute_owned(Attribute::VendorName)
                .expect("failed to get vendor name attribute");
            println!("Vendor name: {}", String::from_utf8(vendor_name).unwrap());

            // Can either end explicity, which allows error handling,
            // and setting the disposition method, or leave it to drop, which
            // swallows any error and hardcodes LeaveCard.
            tx.end(Disposition::LeaveCard)
                .map_err(|(_, err)| err)
                .expect("failed to end transaction");
        }

        // Can either disconnect explicity, which allows error handling,
        // and setting the disposition method, or leave it to drop, which
        // swallows any error and hardcodes ResetCard.
        card.disconnect(Disposition::ResetCard)
            .map_err(|(_, err)| err)
            .expect("failed to disconnect from card");
    }

    // Can either release explicity, which allows error handling,
    // or leave it to drop, which swallows any error.
    // The function fails if there are any live clones.
    ctx.release()
        .map_err(|(_, err)| err)
        .expect("failed to release context");
}
source

pub fn get_attribute<'buf>( &self, attribute: Attribute, buffer: &'buf mut [u8] ) -> Result<&'buf [u8], Error>

Get an attribute of the card or card reader.

buffer is a buffer that should be large enough for the attribute data. The function get_attribute_len can be used to find the exact required length.

Returns a slice into buffer containing the attribute data.

If the buffer is not large enough, Error::InsufficientBuffer is returned.

This function wraps SCardGetAttrib (pcsclite, MSDN).

Examples found in repository?
examples/connect.rs (line 61)
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
fn main() {
    // Get a context.
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    // List connected readers.
    let mut readers_buf = [0; 2048];
    let readers = ctx
        .list_readers(&mut readers_buf)
        .expect("failed to list readers")
        .collect::<Vec<_>>();
    println!("Readers: {:?}", readers);

    if readers.is_empty() {
        return;
    }

    {
        // Try to connect to a card in the first reader.
        let mut card = ctx
            .connect(readers[0], ShareMode::Shared, Protocols::ANY)
            .expect("failed to connect to card");

        {
            // Start an exclusive transaction (not required -- can work on card directly).
            let tx = card.transaction().expect("failed to begin card transaction");

            // Get the card status.
            let (names_len, _atr_len) = tx.status2_len().expect("failed to get the status length");
            let mut names_buf = vec![0; names_len];
            let mut atr_buf = [0; MAX_ATR_SIZE];
            let status = tx
                .status2(&mut names_buf, &mut atr_buf)
                .expect("failed to get card status");
            println!("Status from status: {:?}", status.status());
            println!(
                "Reader names from status: {:?}",
                status.reader_names().collect::<Vec<_>>()
            );
            if let Some(protocol) = status.protocol2() {
                println!("Protocol from status: {:?}", protocol);
            } else {
                println!("Protocol from status: directly connected");
            }
            println!("ATR from status: {:?}", status.atr());

            // Send some harmless APDU to the card.
            if let Some(_) = status.protocol2() {
                let apdu = b"\x00\xa4\x04\x00\x08\x31\x54\x49\x43\x2e\x49\x43\x41";
                let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
                let rapdu = tx
                    .transmit(apdu, &mut rapdu_buf)
                    .expect("failed to transmit APDU to card");
                println!("RAPDU: {:?}", rapdu);
            }

            // Get the card's ATR.
            let mut atr_buf = [0; MAX_ATR_SIZE];
            let atr = tx
                .get_attribute(Attribute::AtrString, &mut atr_buf)
                .expect("failed to get ATR attribute");
            println!("ATR from attribute: {:?}", atr);

            // Get some attribute.
            let mut ifd_version_buf = [0; 4];
            let ifd_version = tx
                .get_attribute(Attribute::VendorIfdVersion, &mut ifd_version_buf)
                .expect("failed to get vendor IFD version attribute");
            println!("Vendor IFD version: {:?}", ifd_version);

            // Get some other attribute.
            // This time we allocate a buffer of the needed length.
            let vendor_name_len = tx
                .get_attribute_len(Attribute::VendorName)
                .expect("failed to get the vendor name attribute length");
            let mut vendor_name_buf = vec![0; vendor_name_len];
            let vendor_name = tx
                .get_attribute(Attribute::VendorName, &mut vendor_name_buf)
                .expect("failed to get vendor name attribute");
            println!("Vendor name: {}", std::str::from_utf8(vendor_name).unwrap());

            // Can either end explicity, which allows error handling,
            // and setting the disposition method, or leave it to drop, which
            // swallows any error and hardcodes LeaveCard.
            tx.end(Disposition::LeaveCard)
                .map_err(|(_, err)| err)
                .expect("failed to end transaction");
        }

        // Can either disconnect explicity, which allows error handling,
        // and setting the disposition method, or leave it to drop, which
        // swallows any error and hardcodes ResetCard.
        card.disconnect(Disposition::ResetCard)
            .map_err(|(_, err)| err)
            .expect("failed to disconnect from card");
    }

    // Can either release explicity, which allows error handling,
    // or leave it to drop, which swallows any error.
    // The function fails if there are any live clones.
    ctx.release()
        .map_err(|(_, err)| err)
        .expect("failed to release context");
}
source

pub fn get_attribute_len(&self, attribute: Attribute) -> Result<usize, Error>

Get the needed length of a buffer to be passed to get_attribute.

This function wraps SCardGetAttrib (pcsclite, MSDN).

Examples found in repository?
examples/connect.rs (line 75)
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
fn main() {
    // Get a context.
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    // List connected readers.
    let mut readers_buf = [0; 2048];
    let readers = ctx
        .list_readers(&mut readers_buf)
        .expect("failed to list readers")
        .collect::<Vec<_>>();
    println!("Readers: {:?}", readers);

    if readers.is_empty() {
        return;
    }

    {
        // Try to connect to a card in the first reader.
        let mut card = ctx
            .connect(readers[0], ShareMode::Shared, Protocols::ANY)
            .expect("failed to connect to card");

        {
            // Start an exclusive transaction (not required -- can work on card directly).
            let tx = card.transaction().expect("failed to begin card transaction");

            // Get the card status.
            let (names_len, _atr_len) = tx.status2_len().expect("failed to get the status length");
            let mut names_buf = vec![0; names_len];
            let mut atr_buf = [0; MAX_ATR_SIZE];
            let status = tx
                .status2(&mut names_buf, &mut atr_buf)
                .expect("failed to get card status");
            println!("Status from status: {:?}", status.status());
            println!(
                "Reader names from status: {:?}",
                status.reader_names().collect::<Vec<_>>()
            );
            if let Some(protocol) = status.protocol2() {
                println!("Protocol from status: {:?}", protocol);
            } else {
                println!("Protocol from status: directly connected");
            }
            println!("ATR from status: {:?}", status.atr());

            // Send some harmless APDU to the card.
            if let Some(_) = status.protocol2() {
                let apdu = b"\x00\xa4\x04\x00\x08\x31\x54\x49\x43\x2e\x49\x43\x41";
                let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
                let rapdu = tx
                    .transmit(apdu, &mut rapdu_buf)
                    .expect("failed to transmit APDU to card");
                println!("RAPDU: {:?}", rapdu);
            }

            // Get the card's ATR.
            let mut atr_buf = [0; MAX_ATR_SIZE];
            let atr = tx
                .get_attribute(Attribute::AtrString, &mut atr_buf)
                .expect("failed to get ATR attribute");
            println!("ATR from attribute: {:?}", atr);

            // Get some attribute.
            let mut ifd_version_buf = [0; 4];
            let ifd_version = tx
                .get_attribute(Attribute::VendorIfdVersion, &mut ifd_version_buf)
                .expect("failed to get vendor IFD version attribute");
            println!("Vendor IFD version: {:?}", ifd_version);

            // Get some other attribute.
            // This time we allocate a buffer of the needed length.
            let vendor_name_len = tx
                .get_attribute_len(Attribute::VendorName)
                .expect("failed to get the vendor name attribute length");
            let mut vendor_name_buf = vec![0; vendor_name_len];
            let vendor_name = tx
                .get_attribute(Attribute::VendorName, &mut vendor_name_buf)
                .expect("failed to get vendor name attribute");
            println!("Vendor name: {}", std::str::from_utf8(vendor_name).unwrap());

            // Can either end explicity, which allows error handling,
            // and setting the disposition method, or leave it to drop, which
            // swallows any error and hardcodes LeaveCard.
            tx.end(Disposition::LeaveCard)
                .map_err(|(_, err)| err)
                .expect("failed to end transaction");
        }

        // Can either disconnect explicity, which allows error handling,
        // and setting the disposition method, or leave it to drop, which
        // swallows any error and hardcodes ResetCard.
        card.disconnect(Disposition::ResetCard)
            .map_err(|(_, err)| err)
            .expect("failed to disconnect from card");
    }

    // Can either release explicity, which allows error handling,
    // or leave it to drop, which swallows any error.
    // The function fails if there are any live clones.
    ctx.release()
        .map_err(|(_, err)| err)
        .expect("failed to release context");
}
source

pub fn get_attribute_owned( &self, attribute: Attribute ) -> Result<Vec<u8>, Error>

Get an attribute of the card or card reader, allocating a buffer of the required size.

This function wraps SCardGetAttrib (pcsclite, MSDN). It is an owned version of get_attribute, calling get_attribute_len to determine the required buffer size.

Examples found in repository?
examples/connect-owned.rs (line 48)
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
fn main() {
    // Get a context.
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    // List connected readers.
    let readers = ctx.list_readers_owned().expect("failed to list readers");
    println!("Readers: {:?}", readers);

    if readers.is_empty() {
        return;
    }

    {
        // Try to connect to a card in the first reader.
        let mut card = ctx
            .connect(&readers[0], ShareMode::Shared, Protocols::ANY)
            .expect("failed to connect to card");

        {
            // Start an exclusive transaction (not required -- can work on card directly).
            let tx = card.transaction().expect("failed to begin card transaction");

            // Get the card status.
            let status = tx.status2_owned().expect("failed to get card status");
            println!("Reader names from status: {:?}", status.reader_names());
            if let Some(protocol) = status.protocol2() {
                println!("Protocol from status: {:?}", protocol);
            } else {
                println!("Protocol from status: directly connected");
            }
            println!("ATR from status: {:?}", status.atr());

            // Send some harmless APDU to the card.
            if let Some(_) = status.protocol2() {
                let apdu = b"\x00\xa4\x04\x00\x08\x31\x54\x49\x43\x2e\x49\x43\x41";
                let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
                let rapdu = tx
                    .transmit(apdu, &mut rapdu_buf)
                    .expect("failed to transmit APDU to card");
                println!("RAPDU: {:?}", rapdu);
            }

            // Get the card's ATR.
            let atr = tx
                .get_attribute_owned(Attribute::AtrString)
                .expect("failed to get ATR attribute");
            println!("ATR from attribute: {:?}", atr);

            // Get some attribute.
            let ifd_version = tx
                .get_attribute_owned(Attribute::VendorIfdVersion)
                .expect("failed to get vendor IFD version attribute");
            println!("Vendor IFD version: {:?}", ifd_version);

            // Get some other attribute.
            let vendor_name = tx
                .get_attribute_owned(Attribute::VendorName)
                .expect("failed to get vendor name attribute");
            println!("Vendor name: {}", String::from_utf8(vendor_name).unwrap());

            // Can either end explicity, which allows error handling,
            // and setting the disposition method, or leave it to drop, which
            // swallows any error and hardcodes LeaveCard.
            tx.end(Disposition::LeaveCard)
                .map_err(|(_, err)| err)
                .expect("failed to end transaction");
        }

        // Can either disconnect explicity, which allows error handling,
        // and setting the disposition method, or leave it to drop, which
        // swallows any error and hardcodes ResetCard.
        card.disconnect(Disposition::ResetCard)
            .map_err(|(_, err)| err)
            .expect("failed to disconnect from card");
    }

    // Can either release explicity, which allows error handling,
    // or leave it to drop, which swallows any error.
    // The function fails if there are any live clones.
    ctx.release()
        .map_err(|(_, err)| err)
        .expect("failed to release context");
}
source

pub fn set_attribute( &self, attribute: Attribute, attribute_data: &[u8] ) -> Result<(), Error>

Set an attribute of the card or card reader.

This function wraps SCardSetAttrib (pcsclite, MSDN).

source

pub fn transmit<'buf>( &self, send_buffer: &[u8], receive_buffer: &'buf mut [u8] ) -> Result<&'buf [u8], Error>

Transmit an APDU command to the card.

receive_buffer is a buffer that should be large enough to hold the APDU response.

Returns a slice into receive_buffer containing the APDU response.

If receive_buffer is not large enough to hold the APDU response, Error::InsufficientBuffer is returned.

This function wraps SCardTransmit (pcsclite, MSDN).

Examples found in repository?
examples/readme.rs (line 50)
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
fn main() {
    // Establish a PC/SC context.
    let ctx = match Context::establish(Scope::User) {
        Ok(ctx) => ctx,
        Err(err) => {
            eprintln!("Failed to establish context: {}", err);
            std::process::exit(1);
        }
    };

    // List available readers.
    let mut readers_buf = [0; 2048];
    let mut readers = match ctx.list_readers(&mut readers_buf) {
        Ok(readers) => readers,
        Err(err) => {
            eprintln!("Failed to list readers: {}", err);
            std::process::exit(1);
        }
    };

    // Use the first reader.
    let reader = match readers.next() {
        Some(reader) => reader,
        None => {
            println!("No readers are connected.");
            return;
        }
    };
    println!("Using reader: {:?}", reader);

    // Connect to the card.
    let card = match ctx.connect(reader, ShareMode::Shared, Protocols::ANY) {
        Ok(card) => card,
        Err(Error::NoSmartcard) => {
            println!("A smartcard is not present in the reader.");
            return;
        }
        Err(err) => {
            eprintln!("Failed to connect to card: {}", err);
            std::process::exit(1);
        }
    };

    // Send an APDU command.
    let apdu = b"\x00\xa4\x04\x00\x0A\xA0\x00\x00\x00\x62\x03\x01\x0C\x06\x01";
    println!("Sending APDU: {:?}", apdu);
    let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
    let rapdu = match card.transmit(apdu, &mut rapdu_buf) {
        Ok(rapdu) => rapdu,
        Err(err) => {
            eprintln!("Failed to transmit APDU command to card: {}", err);
            std::process::exit(1);
        }
    };
    println!("APDU response: {:?}", rapdu);
}
More examples
Hide additional examples
examples/connect-owned.rs (line 41)
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
fn main() {
    // Get a context.
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    // List connected readers.
    let readers = ctx.list_readers_owned().expect("failed to list readers");
    println!("Readers: {:?}", readers);

    if readers.is_empty() {
        return;
    }

    {
        // Try to connect to a card in the first reader.
        let mut card = ctx
            .connect(&readers[0], ShareMode::Shared, Protocols::ANY)
            .expect("failed to connect to card");

        {
            // Start an exclusive transaction (not required -- can work on card directly).
            let tx = card.transaction().expect("failed to begin card transaction");

            // Get the card status.
            let status = tx.status2_owned().expect("failed to get card status");
            println!("Reader names from status: {:?}", status.reader_names());
            if let Some(protocol) = status.protocol2() {
                println!("Protocol from status: {:?}", protocol);
            } else {
                println!("Protocol from status: directly connected");
            }
            println!("ATR from status: {:?}", status.atr());

            // Send some harmless APDU to the card.
            if let Some(_) = status.protocol2() {
                let apdu = b"\x00\xa4\x04\x00\x08\x31\x54\x49\x43\x2e\x49\x43\x41";
                let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
                let rapdu = tx
                    .transmit(apdu, &mut rapdu_buf)
                    .expect("failed to transmit APDU to card");
                println!("RAPDU: {:?}", rapdu);
            }

            // Get the card's ATR.
            let atr = tx
                .get_attribute_owned(Attribute::AtrString)
                .expect("failed to get ATR attribute");
            println!("ATR from attribute: {:?}", atr);

            // Get some attribute.
            let ifd_version = tx
                .get_attribute_owned(Attribute::VendorIfdVersion)
                .expect("failed to get vendor IFD version attribute");
            println!("Vendor IFD version: {:?}", ifd_version);

            // Get some other attribute.
            let vendor_name = tx
                .get_attribute_owned(Attribute::VendorName)
                .expect("failed to get vendor name attribute");
            println!("Vendor name: {}", String::from_utf8(vendor_name).unwrap());

            // Can either end explicity, which allows error handling,
            // and setting the disposition method, or leave it to drop, which
            // swallows any error and hardcodes LeaveCard.
            tx.end(Disposition::LeaveCard)
                .map_err(|(_, err)| err)
                .expect("failed to end transaction");
        }

        // Can either disconnect explicity, which allows error handling,
        // and setting the disposition method, or leave it to drop, which
        // swallows any error and hardcodes ResetCard.
        card.disconnect(Disposition::ResetCard)
            .map_err(|(_, err)| err)
            .expect("failed to disconnect from card");
    }

    // Can either release explicity, which allows error handling,
    // or leave it to drop, which swallows any error.
    // The function fails if there are any live clones.
    ctx.release()
        .map_err(|(_, err)| err)
        .expect("failed to release context");
}
examples/connect.rs (line 53)
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
fn main() {
    // Get a context.
    let ctx = Context::establish(Scope::User).expect("failed to establish context");

    // List connected readers.
    let mut readers_buf = [0; 2048];
    let readers = ctx
        .list_readers(&mut readers_buf)
        .expect("failed to list readers")
        .collect::<Vec<_>>();
    println!("Readers: {:?}", readers);

    if readers.is_empty() {
        return;
    }

    {
        // Try to connect to a card in the first reader.
        let mut card = ctx
            .connect(readers[0], ShareMode::Shared, Protocols::ANY)
            .expect("failed to connect to card");

        {
            // Start an exclusive transaction (not required -- can work on card directly).
            let tx = card.transaction().expect("failed to begin card transaction");

            // Get the card status.
            let (names_len, _atr_len) = tx.status2_len().expect("failed to get the status length");
            let mut names_buf = vec![0; names_len];
            let mut atr_buf = [0; MAX_ATR_SIZE];
            let status = tx
                .status2(&mut names_buf, &mut atr_buf)
                .expect("failed to get card status");
            println!("Status from status: {:?}", status.status());
            println!(
                "Reader names from status: {:?}",
                status.reader_names().collect::<Vec<_>>()
            );
            if let Some(protocol) = status.protocol2() {
                println!("Protocol from status: {:?}", protocol);
            } else {
                println!("Protocol from status: directly connected");
            }
            println!("ATR from status: {:?}", status.atr());

            // Send some harmless APDU to the card.
            if let Some(_) = status.protocol2() {
                let apdu = b"\x00\xa4\x04\x00\x08\x31\x54\x49\x43\x2e\x49\x43\x41";
                let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
                let rapdu = tx
                    .transmit(apdu, &mut rapdu_buf)
                    .expect("failed to transmit APDU to card");
                println!("RAPDU: {:?}", rapdu);
            }

            // Get the card's ATR.
            let mut atr_buf = [0; MAX_ATR_SIZE];
            let atr = tx
                .get_attribute(Attribute::AtrString, &mut atr_buf)
                .expect("failed to get ATR attribute");
            println!("ATR from attribute: {:?}", atr);

            // Get some attribute.
            let mut ifd_version_buf = [0; 4];
            let ifd_version = tx
                .get_attribute(Attribute::VendorIfdVersion, &mut ifd_version_buf)
                .expect("failed to get vendor IFD version attribute");
            println!("Vendor IFD version: {:?}", ifd_version);

            // Get some other attribute.
            // This time we allocate a buffer of the needed length.
            let vendor_name_len = tx
                .get_attribute_len(Attribute::VendorName)
                .expect("failed to get the vendor name attribute length");
            let mut vendor_name_buf = vec![0; vendor_name_len];
            let vendor_name = tx
                .get_attribute(Attribute::VendorName, &mut vendor_name_buf)
                .expect("failed to get vendor name attribute");
            println!("Vendor name: {}", std::str::from_utf8(vendor_name).unwrap());

            // Can either end explicity, which allows error handling,
            // and setting the disposition method, or leave it to drop, which
            // swallows any error and hardcodes LeaveCard.
            tx.end(Disposition::LeaveCard)
                .map_err(|(_, err)| err)
                .expect("failed to end transaction");
        }

        // Can either disconnect explicity, which allows error handling,
        // and setting the disposition method, or leave it to drop, which
        // swallows any error and hardcodes ResetCard.
        card.disconnect(Disposition::ResetCard)
            .map_err(|(_, err)| err)
            .expect("failed to disconnect from card");
    }

    // Can either release explicity, which allows error handling,
    // or leave it to drop, which swallows any error.
    // The function fails if there are any live clones.
    ctx.release()
        .map_err(|(_, err)| err)
        .expect("failed to release context");
}
source

pub fn transmit2<'buf>( &self, send_buffer: &[u8], receive_buffer: &'buf mut [u8] ) -> Result<&'buf [u8], (Error, usize)>

Transmit an APDU command to the card.

This functions works like transmit but the error type is (Error, usize).

receive_buffer is a buffer that should be large enough to hold the APDU response.

Returns a slice into receive_buffer containing the APDU response.

If receive_buffer is not large enough to hold the APDU response, Error::InsufficientBuffer is returned, and the usize value is set to the required size.

usize value of the error has no meaning for other Error values than Error::InsufficientBuffer.

Note that when Error::InsufficientBuffer is returned, the provided command has been already effectively executed by the card. Do not treat this as a generic way to obtain the size of the response as you may end up issuing commands multiple times which can lead to unexpected results. Normally, most operations on standard card let you know the expected size of the response in advance. Be sure to only use this for commands that may be executed multiple times in a row without changing the state of the card.

This function wraps SCardTransmit (pcsclite, MSDN).

source

pub fn control<'buf>( &self, control_code: DWORD, send_buffer: &[u8], receive_buffer: &'buf mut [u8] ) -> Result<&'buf [u8], Error>

Sends a command directly to the reader (driver).

control_code is the reader-specific control code. You may need to pass it through the ctl_code() function, according to the driver documentation.

receive_buffer is a buffer that should be large enough to hold the response.

Returns a slice into receive_buffer containing the response.

If receive_buffer is not large enough to hold the response, Error::InsufficientBuffer is returned.

This function wraps SCardControl (pcsclite, MSDN).

Trait Implementations§

source§

impl<'tx> Deref for Transaction<'tx>

§

type Target = Card

The resulting type after dereferencing.
source§

fn deref(&self) -> &Card

Dereferences the value.
source§

impl<'tx> Drop for Transaction<'tx>

source§

fn drop(&mut self)

Executes the destructor for this type. Read more

Auto Trait Implementations§

§

impl<'tx> RefUnwindSafe for Transaction<'tx>

§

impl<'tx> Send for Transaction<'tx>

§

impl<'tx> Sync for Transaction<'tx>

§

impl<'tx> Unpin for Transaction<'tx>

§

impl<'tx> !UnwindSafe for Transaction<'tx>

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.