aboutsummaryrefslogtreecommitdiffstats
path: root/src/pcsc_server.rb
blob: a57d3f7322ea993d79faac9611c8f61b13b5acf5 (plain)
1
2
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
106
107
108
109
110
#!/usr/bin/env ruby
=begin
This file is part of SAP.

SAP is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

SAP is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with SAP.  If not, see <http://www.gnu.org/licenses/>.

Copyright (C) 2011 Kevin "tsaitgaist" Redon kevredon@mail.tsaitgaist.info
=end
require 'lib/server'
require 'rubygems'
require 'smartcard'
=begin
need to install
sudo aptitude install ruby ruby-dev rubygems
sudo aptitude install libpcsclite1 libpcsclite-dev libruby
sudo gem install smartcard (http://www.rubygems.org/gems/smartcard)
=end

# SAP server using PCSC for the card
class PCSCServer < Server

  # provide the io to listen to
  def initialize(io)
    super(io)
  end

  # connect to card
  # TODO : choose which reader to use
  def connect
    
    # get PCSC context
    context = Smartcard::PCSC::Context.new
    # get all readers
    begin
      readers = context.readers
    rescue Smartcard::PCSC::Exception => e
      puts "no reader available. please connect a card reader"
      begin
        readers = context.readers
      rescue Smartcard::PCSC::Exception => e
        sleep 1
        retry
      end
    end
    # one reader required
    if readers.size==0 then
      puts "no reader available. connect a reader"
      # info client ["StatusChange",["Card not accessible"]]
      status = create_message("STATUS_IND",[[0x08,[0x02]]])
      send(status)
      while readers.size==0 do
        context = Smartcard::PCSC::Context.new
        readers = context.readers
        sleep 1
      end
    end
    # use the first reader
    reader = readers.first
    puts "using reader : #{reader}"

    # connect to the card
    begin
      @card = Smartcard::PCSC::Card.new(context,reader,:exclusive,:t0)
    rescue Smartcard::PCSC::Exception => e
      # wait for a card
      puts "no card available. insert card"
      # info client ["StatusChange",["Card not accessible"]]
      status = create_message("STATUS_IND",[[0x08,[0x02]]])
      send(status)
      begin
        @card = Smartcard::PCSC::Card.new(context,reader,:exclusive,:t0)
      rescue Smartcard::PCSC::Exception => e
        sleep 1
        retry
      end
    end

    # card ready
    # ["StatusChange",["Card reset"]]
    status = create_message("STATUS_IND",[[0x08,[0x01]]])
    send(status)
    puts "connected to card"
    log("server","SIM ready (reset)",3)
  end

  # get ATR
  def atr
    raise "connect to card to get ATR" unless @card
    return @card.info[:atr].unpack("C*")
  end

  # send APDU and get response
  def apdu(request)
    raise "connect to card to send APDU" unless @card
    response = @card.transmit(request.pack('C*')).unpack("C*")
    return response
  end

end