tem_ruby 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +35 -0
- data/LICENSE +21 -0
- data/Manifest +45 -0
- data/README +6 -0
- data/bin/tem_bench +9 -0
- data/bin/tem_ca +13 -0
- data/bin/tem_irb +18 -0
- data/bin/tem_stat +39 -0
- data/dev_ca/ca_cert.cer +0 -0
- data/dev_ca/ca_cert.pem +32 -0
- data/dev_ca/ca_key.pem +27 -0
- data/dev_ca/config.yml +12 -0
- data/lib/scard/java_card.rb +31 -0
- data/lib/scard/jcop_remote_terminal.rb +52 -0
- data/lib/scard/pcsc_terminal.rb +83 -0
- data/lib/tem/_cert.rb +158 -0
- data/lib/tem/abi.rb +55 -0
- data/lib/tem/buffers.rb +98 -0
- data/lib/tem/ca.rb +114 -0
- data/lib/tem/crypto_abi.rb +216 -0
- data/lib/tem/ecert.rb +78 -0
- data/lib/tem/hive.rb +18 -0
- data/lib/tem/keys.rb +60 -0
- data/lib/tem/lifecycle.rb +8 -0
- data/lib/tem/sec_assembler.rb +91 -0
- data/lib/tem/sec_exec_error.rb +45 -0
- data/lib/tem/sec_opcodes.rb +154 -0
- data/lib/tem/seclosures.rb +82 -0
- data/lib/tem/secpack.rb +86 -0
- data/lib/tem/tag.rb +28 -0
- data/lib/tem/tem.rb +47 -0
- data/lib/tem/toolkit.rb +104 -0
- data/lib/tem_ruby.rb +29 -0
- data/tem_ruby.gemspec +53 -0
- data/test/_test_cert.rb +81 -0
- data/test/test_driver.rb +127 -0
- data/test/test_exceptions.rb +55 -0
- data/test/test_tem.rb +542 -0
- data/timings/blank_bound_secpack.rb +20 -0
- data/timings/blank_sec.rb +15 -0
- data/timings/devchip_decrypt.rb +9 -0
- data/timings/post_buffer.rb +10 -0
- data/timings/simple_apdu.rb +5 -0
- data/timings/timings.rb +66 -0
- data/timings/vm_perf.rb +141 -0
- data/timings/vm_perf_bound.rb +142 -0
- metadata +143 -0
data/CHANGELOG
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
v0.9.0. Updated tests and re-implemented buffer stat-ing for fw 1.9(fire).
|
2
|
+
|
3
|
+
v0.8.0. Implemented buffer flushing (fw 1.8) and more timing tests.
|
4
|
+
|
5
|
+
v0.7.2. Implemented "tem_bench" for benchmarking a TEM.
|
6
|
+
|
7
|
+
v0.7.1. Implemented Endorsement Certificates, with rudimentary infrastructure for a CA.
|
8
|
+
|
9
|
+
v0.7.0. Updated names to reflect thesis (SEClosure, SECpack). Persistent store opcodes and tests reflect fw 1.7.
|
10
|
+
|
11
|
+
v0.6.1. Fixed bug in tk_delete_key.
|
12
|
+
|
13
|
+
v0.6.0. Implemented stat-ing TEM keys with test coverage. Updated tem_stat and custom exception.
|
14
|
+
|
15
|
+
v0.5.2. Implemented custom exception for errors in TEM SEC execution.
|
16
|
+
|
17
|
+
v0.5.1. Implemented tem_stat tool.
|
18
|
+
|
19
|
+
v0.5.0. Implemented stat-ing TEM buffers with test coverage.
|
20
|
+
|
21
|
+
v0.4.1. Removed exception dumping when connecting to a PC/SC terminal fails.
|
22
|
+
|
23
|
+
v0.4.0. Support for adaptive buffer chunk sizing.
|
24
|
+
|
25
|
+
v0.3.0. Support for fw 1.3 features (signing). Improved TEM emission.
|
26
|
+
|
27
|
+
v0.2.1. Line debugging information in SECs.
|
28
|
+
|
29
|
+
v0.2.0. Support for all fw 1.2 features. TEM tests have full coverage now.
|
30
|
+
|
31
|
+
v0.1.2. Tag support.
|
32
|
+
|
33
|
+
v0.1.1. Named parameters for more opcodes.
|
34
|
+
|
35
|
+
v0.1. Initial release.
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2007 Massachusetts Institute of Technology
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/Manifest
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
bin/tem_stat
|
2
|
+
bin/tem_ca
|
3
|
+
bin/tem_irb
|
4
|
+
bin/tem_bench
|
5
|
+
Manifest
|
6
|
+
LICENSE
|
7
|
+
test/test_driver.rb
|
8
|
+
test/test_tem.rb
|
9
|
+
test/test_exceptions.rb
|
10
|
+
test/_test_cert.rb
|
11
|
+
timings/vm_perf.rb
|
12
|
+
timings/devchip_decrypt.rb
|
13
|
+
timings/simple_apdu.rb
|
14
|
+
timings/post_buffer.rb
|
15
|
+
timings/blank_bound_secpack.rb
|
16
|
+
timings/vm_perf_bound.rb
|
17
|
+
timings/timings.rb
|
18
|
+
timings/blank_sec.rb
|
19
|
+
lib/scard/java_card.rb
|
20
|
+
lib/scard/jcop_remote_terminal.rb
|
21
|
+
lib/scard/pcsc_terminal.rb
|
22
|
+
lib/tem_ruby.rb
|
23
|
+
lib/tem/tag.rb
|
24
|
+
lib/tem/keys.rb
|
25
|
+
lib/tem/sec_opcodes.rb
|
26
|
+
lib/tem/_cert.rb
|
27
|
+
lib/tem/buffers.rb
|
28
|
+
lib/tem/toolkit.rb
|
29
|
+
lib/tem/tem.rb
|
30
|
+
lib/tem/abi.rb
|
31
|
+
lib/tem/crypto_abi.rb
|
32
|
+
lib/tem/ca.rb
|
33
|
+
lib/tem/secpack.rb
|
34
|
+
lib/tem/sec_exec_error.rb
|
35
|
+
lib/tem/sec_assembler.rb
|
36
|
+
lib/tem/lifecycle.rb
|
37
|
+
lib/tem/ecert.rb
|
38
|
+
lib/tem/hive.rb
|
39
|
+
lib/tem/seclosures.rb
|
40
|
+
README
|
41
|
+
CHANGELOG
|
42
|
+
dev_ca/ca_cert.cer
|
43
|
+
dev_ca/ca_cert.pem
|
44
|
+
dev_ca/ca_key.pem
|
45
|
+
dev_ca/config.yml
|
data/README
ADDED
@@ -0,0 +1,6 @@
|
|
1
|
+
This is the ruby driver for the Trusted Execution Module prototype produced at MIT. The best feature of the
|
2
|
+
ruby driver is the very powerful DSL (domain-specific language) that TEM procedures are compiled from.
|
3
|
+
|
4
|
+
Running coverage tests:
|
5
|
+
gem install rcov
|
6
|
+
rcov -Ilib test/*.rb
|
data/bin/tem_bench
ADDED
data/bin/tem_ca
ADDED
data/bin/tem_irb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# scaffolds an environment suitable for playing inside an irb session
|
4
|
+
require 'rubygems'
|
5
|
+
require 'tem_ruby'
|
6
|
+
|
7
|
+
require 'irb'
|
8
|
+
|
9
|
+
$terminal = Tem::SCard::JCOPRemoteTerminal.new
|
10
|
+
unless $terminal.connect
|
11
|
+
$terminal.disconnect
|
12
|
+
$terminal = Tem::SCard::PCSCTerminal.new
|
13
|
+
$terminal.connect
|
14
|
+
end
|
15
|
+
$javacard = Tem::SCard::JavaCard.new($terminal)
|
16
|
+
$tem = Tem::Session.new($javacard)
|
17
|
+
|
18
|
+
IRB.start __FILE__
|
data/bin/tem_stat
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# spews information about the TEM
|
4
|
+
require 'rubygems'
|
5
|
+
require 'tem_ruby'
|
6
|
+
require 'pp'
|
7
|
+
|
8
|
+
$terminal = Tem::SCard::JCOPRemoteTerminal.new
|
9
|
+
unless $terminal.connect
|
10
|
+
$terminal.disconnect
|
11
|
+
$terminal = Tem::SCard::PCSCTerminal.new
|
12
|
+
$terminal.connect
|
13
|
+
end
|
14
|
+
$javacard = Tem::SCard::JavaCard.new($terminal)
|
15
|
+
$tem = Tem::Session.new($javacard)
|
16
|
+
|
17
|
+
print "Connected to TEM using #{$terminal.to_s}\n"
|
18
|
+
begin
|
19
|
+
fw_ver = $tem.tk_firmware_ver
|
20
|
+
print "TEM firmware version: #{fw_ver[:major]}.#{fw_ver[:minor]}\n"
|
21
|
+
rescue
|
22
|
+
print "Could not read TEM firmware version. Is the TEM emitted?\n"
|
23
|
+
end
|
24
|
+
|
25
|
+
begin
|
26
|
+
b_stat = $tem.stat_buffers
|
27
|
+
print "TEM memory stat:\n"
|
28
|
+
pp b_stat
|
29
|
+
rescue
|
30
|
+
print "Could not retrieve TEM memory stat. Is the TEM activated?\n"
|
31
|
+
end
|
32
|
+
|
33
|
+
begin
|
34
|
+
k_stat = $tem.stat_keys
|
35
|
+
print "TEM crypto stat:\n"
|
36
|
+
pp k_stat
|
37
|
+
rescue
|
38
|
+
print "Could not retrieve TEM crypto stat. Is the TEM activated?\n"
|
39
|
+
end
|
data/dev_ca/ca_cert.cer
ADDED
Binary file
|
data/dev_ca/ca_cert.pem
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIFgDCCBGigAwIBAgIAMA0GCSqGSIb3DQEBBQUAMIHcMTAwLgYDVQQDDCdUcnVz
|
3
|
+
dGVkIEV4ZWN1dGlvbiBNb2R1bGUgRGV2ZWxvcG1lbnQgQ0ExFjAUBgNVBAgMDU1h
|
4
|
+
c3NhY2h1c2V0dHMxEjAQBgNVBAcMCUNhbWJyaWRnZTELMAkGA1UEBhMCVVMxLTAr
|
5
|
+
BgNVBAoMJE1hc3NhY2h1c2V0dHMgSW5zaXR1dGUgb2YgVGVjaG5vbG9neTFAMD4G
|
6
|
+
A1UECww3Q29tcHV0ZXIgU2NpZW5jZSBhbmQgQXJ0aWZpY2lhbCBJbnRlbGxpZ2Vu
|
7
|
+
Y2UgTGFib3JhdG9yeTAeFw0wODA2MDkxMTMyMTBaFw0xODA2MDkxMTMyMTBaMIHc
|
8
|
+
MTAwLgYDVQQDDCdUcnVzdGVkIEV4ZWN1dGlvbiBNb2R1bGUgRGV2ZWxvcG1lbnQg
|
9
|
+
Q0ExFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcMCUNhbWJyaWRnZTEL
|
10
|
+
MAkGA1UEBhMCVVMxLTArBgNVBAoMJE1hc3NhY2h1c2V0dHMgSW5zaXR1dGUgb2Yg
|
11
|
+
VGVjaG5vbG9neTFAMD4GA1UECww3Q29tcHV0ZXIgU2NpZW5jZSBhbmQgQXJ0aWZp
|
12
|
+
Y2lhbCBJbnRlbGxpZ2VuY2UgTGFib3JhdG9yeTCCASIwDQYJKoZIhvcNAQEBBQAD
|
13
|
+
ggEPADCCAQoCggEBAM7ebvoLQ/FF+woPjmivWcesdR5hZekmaRy9Md55kT3FRfqq
|
14
|
+
AYzEjblo77HVullgpplVCVlEgCXUN1vjVc2dknUPs3eeIIQIBWrX3Je8OY19sYh3
|
15
|
+
goybyAkpnDNXGZTpx29kHw9zXNPQRFnQCsUTsmkoZOUBmblqn0m8mxzvbA5mKiFk
|
16
|
+
cXr3bLUuTreilwEqW24ictGT85gDiadf2Yx2zmGpvvxtB1RCRdOujftCoV4YaWju
|
17
|
+
U1v/4bNY4rcQ6T33NIcA1cbF4QSeMvzbS33pnV4/RPbPjLbn0KVN1XcUGj6L7Nve
|
18
|
+
QFOsekCLRHRiahGVgIu90lHUS3FrRcY93p7v3m0CAwEAAaOCAUowggFGMA8GA1Ud
|
19
|
+
EwEB/wQFMAMBAf8wgfMGA1UdIwSB6zCB6KGB4qSB3zCB3DEwMC4GA1UEAwwnVHJ1
|
20
|
+
c3RlZCBFeGVjdXRpb24gTW9kdWxlIERldmVsb3BtZW50IENBMRYwFAYDVQQIDA1N
|
21
|
+
YXNzYWNodXNldHRzMRIwEAYDVQQHDAlDYW1icmlkZ2UxCzAJBgNVBAYTAlVTMS0w
|
22
|
+
KwYDVQQKDCRNYXNzYWNodXNldHRzIEluc2l0dXRlIG9mIFRlY2hub2xvZ3kxQDA+
|
23
|
+
BgNVBAsMN0NvbXB1dGVyIFNjaWVuY2UgYW5kIEFydGlmaWNpYWwgSW50ZWxsaWdl
|
24
|
+
bmNlIExhYm9yYXRvcnmCAQAwCwYDVR0PBAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIB
|
25
|
+
BjAdBgNVHQ4EFgQU9eaMHf5cp5ZV1AiqEpZChwV1vC8wDQYJKoZIhvcNAQEFBQAD
|
26
|
+
ggEBAIsZ3SVu08m2zWYZSlyf3ylczSLjCUGYlRg30JzCejIxZkYE+zzgwpPLIngQ
|
27
|
+
yXcSqXSlO0t14GbidVhOnSq6WoMqftxC6chT82GGOpl0oWGeFZnX7fSQQfI6Rwqk
|
28
|
+
VVxaLv23xD3GU5dpsGy81blrl4n0ocMcAeEynAOBAj/c+sw+lowIZtpZ32MgJRVc
|
29
|
+
iBmbAOV8RXj8hymylz+UlScrmjwl0k5hHQ+beDyLNkUDrKG13rs6iSl+AEXrzzbM
|
30
|
+
wpSr/41JWjwkIuM5D7MVVk06UtFWzTEm766DbP4plopkaYzzzmjCRelMoGIoI1yD
|
31
|
+
tAtZLRzXomQ2xLX70O+bKuyP694=
|
32
|
+
-----END CERTIFICATE-----
|
data/dev_ca/ca_key.pem
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
-----BEGIN RSA PRIVATE KEY-----
|
2
|
+
MIIEpAIBAAKCAQEAzt5u+gtD8UX7Cg+OaK9Zx6x1HmFl6SZpHL0x3nmRPcVF+qoB
|
3
|
+
jMSNuWjvsdW6WWCmmVUJWUSAJdQ3W+NVzZ2SdQ+zd54ghAgFatfcl7w5jX2xiHeC
|
4
|
+
jJvICSmcM1cZlOnHb2QfD3Nc09BEWdAKxROyaShk5QGZuWqfSbybHO9sDmYqIWRx
|
5
|
+
evdstS5Ot6KXASpbbiJy0ZPzmAOJp1/ZjHbOYam+/G0HVEJF066N+0KhXhhpaO5T
|
6
|
+
W//hs1jitxDpPfc0hwDVxsXhBJ4y/NtLfemdXj9E9s+MtufQpU3VdxQaPovs295A
|
7
|
+
U6x6QItEdGJqEZWAi73SUdRLcWtFxj3enu/ebQIDAQABAoIBAEiUvnc4kKQMm6HS
|
8
|
+
B3MvYt6t4YHBRpJhCawtrVuTZ6Q2nPDvyQ9svxT4fnD0vicxxAI0Vc1ePWAIb0vs
|
9
|
+
HWTBDmvIEH29m0b30X7FMf6C6eZ83Vc2JzXSSoL8eHOC8dTPmUu54zP2k/E1N2YT
|
10
|
+
mlO/L2+53nyC7T6i7DRg2kNytYTvLf5+gKI0Pca47xfE2oA6R7mbM7ew/1GBSwup
|
11
|
+
9SrszudcSf31quuDTOG2lGtUkzosi9p7LZ3SagqHR9YGRXeQ3xjNo/MgkAprffjC
|
12
|
+
xlrCdpvTnZS/ACu0TXGuDvEn8JtcPWg8ZeHx4UKW+Ll3eEoILaSxvFzgY8jR8RWy
|
13
|
+
xk0HVTkCgYEA61TbQcD6pqd+8m1WGEo2BagBsNavbU8v5Xoaj5Cebe968FybBiKU
|
14
|
+
T9thbbvxCy8PC/hEOn0S/tFzNdgZp17/HGNqRtLMkiogj4h+n8ikCbcMKBGIVqrw
|
15
|
+
tT3kgPe/66RLVnNx/QuY53AgSIMhEZtmuomuO0rVdJNA2z3ami/GuJsCgYEA4Qmh
|
16
|
+
T5rCgID/CGGt7lNTGkGhgt3IPBBlakXXhvwRcrmfkqKVztu0l4aRrwAA4tE6xkKa
|
17
|
+
/89FgliKpSFAp2ipmMysTfhmM4so6M/7JwxkZqBtl33umg+RM7J0qCl7IQzIXHb3
|
18
|
+
GB/6EJIzxTpxk/EF1CM+wuLIDlIWzN3N5wcXIZcCgYAU/QN1ENYKCQQ8cN3t2qiI
|
19
|
+
xpwn/m207QwThllaFobavTIUv92fpXPez20YEVwFKFRKOAE1yjPogBurYLOhBsrv
|
20
|
+
6DnxSRmvq4wt4PmSHJ3ss+OkqzOiryo6r+NyUSZPyN5jPnabH+6qLYjjjrZjUJ3P
|
21
|
+
4zmj1h/FfuCY7SJTABHUIwKBgQDAwqf7cRwUSOqr+kerMpKnlfpMB7+Bu6WzL1ob
|
22
|
+
lQU5GUlXqI7cHxQFC0708PLRVtmag+kTIC9xJHi2U9J2088aRI9/Rjv9AMGtEqIW
|
23
|
+
Y6YIxni5YDSmoJkHCGCmvslqmPFzSrADaTihQyq3UYWCbN1KRlp3QxyML8K5/3Bk
|
24
|
+
6YzlxwKBgQDhoquhyRjUzxsuKjKdLZa8RLwK720/kLOWgA1MfNEodIrcPZphNDpO
|
25
|
+
ln/KeMQ/If6zZ9KH/hd/KYet366X0gO6+e+Pon8YIYpwZrrLhZ8qKQHmLZDz4bY1
|
26
|
+
X+ghsQnpj5X0klQbpVtsKSKU6LL6eYR3yBEVwGvh94Rt02g++6K2+Q==
|
27
|
+
-----END RSA PRIVATE KEY-----
|
data/dev_ca/config.yml
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
---
|
2
|
+
:ca_validity_days: 3652
|
3
|
+
:issuer:
|
4
|
+
CN: Trusted Execution Module Development CA
|
5
|
+
L: Cambridge
|
6
|
+
ST: Massachusetts
|
7
|
+
C: US
|
8
|
+
O: Massachusetts Insitute of Technology
|
9
|
+
OU: Computer Science and Artificial Intelligence Laboratory
|
10
|
+
:ecert_validity_days: 730
|
11
|
+
:subject:
|
12
|
+
CN: Trusted Execution Module DevChip
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Tem::SCard::JavaCard
|
2
|
+
attr_accessor :terminal
|
3
|
+
|
4
|
+
def initialize(_terminal = nil)
|
5
|
+
@terminal = _terminal
|
6
|
+
end
|
7
|
+
|
8
|
+
def select_applet(aid)
|
9
|
+
result = @terminal.issue_apdu [0x00, 0xA4, 0x04, 0x00, aid.length, aid].flatten
|
10
|
+
(result == [0x90, 0x00])
|
11
|
+
end
|
12
|
+
|
13
|
+
def issue_apdu(apdu)
|
14
|
+
@terminal.issue_apdu apdu
|
15
|
+
end
|
16
|
+
|
17
|
+
# returns the failure code of an operation (success would be 0x9000)
|
18
|
+
# returns nil for success
|
19
|
+
def failure_code(reply_apdu)
|
20
|
+
status = reply_apdu[-2] * 256 + reply_apdu.length[-1]
|
21
|
+
return (status == 0x9000) ? nil : status
|
22
|
+
end
|
23
|
+
|
24
|
+
def reply_data(reply_apdu)
|
25
|
+
return reply_apdu[0...-2]
|
26
|
+
end
|
27
|
+
|
28
|
+
def install_applet(cap_contents)
|
29
|
+
raise "Not implemeted; it'd be nice though, right?"
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'socket'
|
2
|
+
class Tem::SCard::JCOPRemoteTerminal
|
3
|
+
def initialize(remote_host = 'localhost', remote_port = 8050)
|
4
|
+
@remote_host = remote_host
|
5
|
+
@remote_port = remote_port
|
6
|
+
@sockaddr = Socket.pack_sockaddr_in(@remote_port, @remote_host)
|
7
|
+
@socket = nil
|
8
|
+
end
|
9
|
+
|
10
|
+
def send_message(payload, message_type = 1, node_address = 0)
|
11
|
+
@socket.send [message_type, node_address, payload.length / 256, payload.length % 256, payload].flatten.pack('C*'), 0
|
12
|
+
end
|
13
|
+
|
14
|
+
def receive_message
|
15
|
+
header = @socket.recv(4)
|
16
|
+
message_type, node_address, payload_length = *header.unpack('CCn')
|
17
|
+
return @socket.recv(payload_length).unpack('C*')
|
18
|
+
end
|
19
|
+
|
20
|
+
def connect
|
21
|
+
begin
|
22
|
+
# connect to the terminal
|
23
|
+
@socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
|
24
|
+
@socket.connect(@sockaddr)
|
25
|
+
|
26
|
+
# wait for the card to be inserted
|
27
|
+
send_message [0, 1, 0, 0], 0
|
28
|
+
receive_message # ATR should come here, but who cares
|
29
|
+
rescue
|
30
|
+
@socket = nil
|
31
|
+
return false
|
32
|
+
end
|
33
|
+
return true
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
"#<JCOP Remote Terminal: disconnected>" if @socket.nil?
|
38
|
+
"#<JCOP Remote Terminal: #{@remote_host}:#{@remote_port}>"
|
39
|
+
end
|
40
|
+
|
41
|
+
def disconnect
|
42
|
+
unless @socket.nil?
|
43
|
+
@socket.close
|
44
|
+
@socket = nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def issue_apdu(apdu)
|
49
|
+
send_message apdu
|
50
|
+
return receive_message
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'pp'
|
2
|
+
|
3
|
+
class Tem::SCard::PCSCTerminal
|
4
|
+
include Smartcard
|
5
|
+
|
6
|
+
@@xmit_iorequest = {
|
7
|
+
Smartcard::PCSC::PROTOCOL_T0 => Smartcard::PCSC::IOREQUEST_T0,
|
8
|
+
Smartcard::PCSC::PROTOCOL_T1 => Smartcard::PCSC::IOREQUEST_T1,
|
9
|
+
}
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@context = nil
|
13
|
+
@readers = nil
|
14
|
+
@card = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def connect
|
18
|
+
begin
|
19
|
+
@context = PCSC::Context.new(PCSC::SCOPE_SYSTEM) if @context.nil?
|
20
|
+
|
21
|
+
# get the first reader
|
22
|
+
@readers = @context.list_readers nil
|
23
|
+
@reader_name = @readers.first
|
24
|
+
|
25
|
+
# get the reader's status
|
26
|
+
reader_states = PCSC::ReaderStates.new(1)
|
27
|
+
reader_states.set_reader_name_of!(0, @reader_name)
|
28
|
+
reader_states.set_current_state_of!(0, PCSC::STATE_UNKNOWN)
|
29
|
+
@context.get_status_change reader_states, 100
|
30
|
+
reader_states.acknowledge_events!
|
31
|
+
|
32
|
+
# prompt for card insertion unless that already happened
|
33
|
+
if (reader_states.current_state_of(0) & PCSC::STATE_PRESENT) == 0
|
34
|
+
puts "Please insert TEM card in reader #{@reader_name}\n"
|
35
|
+
while (reader_states.current_state_of(0) & PCSC::STATE_PRESENT) == 0 do
|
36
|
+
@context.get_status_change reader_states, PCSC::INFINITE_TIMEOUT
|
37
|
+
reader_states.acknowledge_events!
|
38
|
+
end
|
39
|
+
puts "Card detected\n"
|
40
|
+
end
|
41
|
+
|
42
|
+
# connect to card
|
43
|
+
@card = PCSC::Card.new(@context, @reader_name, PCSC::SHARE_EXCLUSIVE, PCSC::PROTOCOL_ANY)
|
44
|
+
|
45
|
+
# build the transmit / receive IoRequests
|
46
|
+
status = @card.status
|
47
|
+
@xmit_ioreq = @@xmit_iorequest[status[:protocol]]
|
48
|
+
if RUBY_PLATFORM =~ /win/ and (not RUBY_PLATFORM =~ /darwin/)
|
49
|
+
@recv_ioreq = nil
|
50
|
+
else
|
51
|
+
@recv_ioreq = PCSC::IoRequest.new
|
52
|
+
end
|
53
|
+
rescue
|
54
|
+
return false
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def to_s
|
59
|
+
"#<PC/SC Terminal: disconnected>" if @card.nil?
|
60
|
+
"#<PC/SC Terminal: #{@reader_name}>"
|
61
|
+
end
|
62
|
+
|
63
|
+
def disconnect
|
64
|
+
unless @card.nil?
|
65
|
+
@card.disconnect PCSC::DISPOSITION_LEAVE unless @card.nil?
|
66
|
+
@card = nil
|
67
|
+
end
|
68
|
+
unless @context.nil?
|
69
|
+
@context.release
|
70
|
+
@context = nil
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def issue_apdu(apdu)
|
75
|
+
xmit_apdu_string = apdu.map { |byte| byte.chr }.join('')
|
76
|
+
result_string = @card.transmit xmit_apdu_string, @xmit_ioreq, @recv_ioreq
|
77
|
+
return (0...(result_string.length)).map { |i| result_string[i].to_i }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# for compatibility with old source code
|
82
|
+
class Tem::SCard::Terminal < Tem::SCard::PCSCTerminal
|
83
|
+
end
|
data/lib/tem/_cert.rb
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
# Victor Costan:
|
2
|
+
# dropped because it wasn't hooked up to the rest of the code
|
3
|
+
# preserved to move all the features into the new ca.rb / ecert.rb
|
4
|
+
|
5
|
+
#@author: Jorge de la Garza (MIT '08), mongoose08@alum.mit.edu
|
6
|
+
#The Cert module contains methods for digesting a X.509 certificate into a tag
|
7
|
+
#for the TEM and to methods to reconstruct the certificate from the tag. Methods
|
8
|
+
#to create some sample certificates are also included for convenience.
|
9
|
+
|
10
|
+
module Tem::Cert
|
11
|
+
#@param key An OpenSSL::PKey instance that will be this cert's key and will be used to sign this cert
|
12
|
+
#@returns a self-signed X.509 certificate that is supposed to be the TEM manufacturer's
|
13
|
+
def self.create_issuer_cert(key)
|
14
|
+
issuer_cert = OpenSSL::X509::Certificate.new
|
15
|
+
issuer_cert.public_key = key.public_key
|
16
|
+
issuer_dist_name = OpenSSL::X509::Name.new [['CN', 'TEM Manufacturer'], ['L', 'Cambridge'], ['ST', 'Massachusetts'],\
|
17
|
+
['O', 'Trusted Execution Modules, Inc.'], ['OU', 'Certificates Division'], ['C', 'US']]
|
18
|
+
issuer_cert.issuer = issuer_dist_name
|
19
|
+
issuer_cert.subject = issuer_dist_name
|
20
|
+
issuer_cert.not_before = Time.now
|
21
|
+
issuer_cert.not_after = Time.now + (60 * 60 * 24 * 365.25) * 10
|
22
|
+
issuer_cert.sign key, OpenSSL::Digest::SHA1.new
|
23
|
+
return issuer_cert
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
#@param subject_key An OpenSSL::PKey instance that will be this cert's key
|
28
|
+
#@param issuer_key An OpenSSL::Pkey instance that will be used to sign this cert (i.e. the issuer's/manufacturer's key)
|
29
|
+
#@param issuer_cert The OpenSSL::X509::Certificate instance of the authority that issued this cert
|
30
|
+
#@returns An OpenSSL::X509::Certificate instance issued by issuer_cert and signed by issuer_key
|
31
|
+
def self.create_subject_cert(subject_key, issuer_key, issuer_cert)
|
32
|
+
subject_cert = OpenSSL::X509::Certificate.new
|
33
|
+
subject_cert.public_key = subject_key.public_key
|
34
|
+
subject_cert.serial = Time.now.to_i #no significance to this #, just a value for demonstration of purpose
|
35
|
+
subject_dist_name = OpenSSL::X509::Name.new [['CN', 'TEM Device'], ['L', 'Cambridge'], ['ST', 'Massachusetts'],\
|
36
|
+
['O', 'Trusted Execution Modules, Inc.'], ['OU', 'Certificates Division'], ['C', 'US']]
|
37
|
+
subject_cert.issuer = issuer_cert.subject
|
38
|
+
subject_cert.subject = subject_dist_name
|
39
|
+
subject_cert.not_before = Time.now
|
40
|
+
subject_cert.not_after = Time.now + (60 * 60 * 24 * 365.25) * 10
|
41
|
+
subject_cert.sign issuer_key, OpenSSL::Digest::SHA1.new
|
42
|
+
return subject_cert
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
#@param cert An OpenSSL::X509::Certificate instance
|
47
|
+
#@returns The tag to write to the TEM as a byte array
|
48
|
+
#The tag is 527 bytes long. What the bytes encode is as follows:
|
49
|
+
# -Serial number tag[0..3]
|
50
|
+
# -Not before date tag[4..7]
|
51
|
+
# -Not after date tag[8..11]
|
52
|
+
# -Modulus tag[12..267]
|
53
|
+
# -Public key exp tag[268..270]
|
54
|
+
# -Signature tag[271..526]
|
55
|
+
def self.create_tag_from_cert(cert)
|
56
|
+
tag_serial_num = Tem::CryptoAbi.to_tem_bignum(OpenSSL::BN.new(cert.serial.to_s))
|
57
|
+
while tag_serial_num.length < 4
|
58
|
+
tag_serial_num = [0] + tag_serial_num #make sure array is 4 bytes
|
59
|
+
end
|
60
|
+
#The dates are encoded as the number of seconds since epoch (Jan 1, 1970 00:00:00 GMT)
|
61
|
+
#TODO: check that dates are exactly 4 bytes, else throw an exception
|
62
|
+
tag_not_before = Tem::CryptoAbi.to_tem_bignum(OpenSSL::BN.new(cert.not_before.to_i.to_s))
|
63
|
+
tag_not_after = Tem::CryptoAbi.to_tem_bignum(OpenSSL::BN.new(cert.not_after.to_i.to_s))
|
64
|
+
tag_modulus = Tem::CryptoAbi.to_tem_bignum(OpenSSL::BN.new(cert.public_key.n.to_s))
|
65
|
+
#TODO: ensure that exponent is exactly three bytes, or come up with a safer way to encode it
|
66
|
+
tag_public_exp = Tem::CryptoAbi.to_tem_bignum(OpenSSL::BN.new(cert.public_key.e.to_s))
|
67
|
+
tag = [tag_serial_num, tag_not_before, tag_not_after, tag_modulus, tag_public_exp].flatten
|
68
|
+
return tag
|
69
|
+
end
|
70
|
+
|
71
|
+
#@param tag The tag read from the TEM
|
72
|
+
#@param issuer_cert The OpenSSL::X509::Certificate of the entity that issued the TEM's certificate
|
73
|
+
#@returns The unsigned OpenSSL::X509::Certificate from which the tag was created.
|
74
|
+
def self.create_cert_from_tag(tag, issuer_cert)
|
75
|
+
cert = OpenSSL::X509::Certificate.new
|
76
|
+
cert.public_key = Cert.extract_key(tag)
|
77
|
+
cert.serial = Cert.extract_serial_num(tag)
|
78
|
+
cert_name = OpenSSL::X509::Name.new [['CN', 'TEM Device'], ['L', 'Cambridge'], ['ST', 'Massachusetts'],\
|
79
|
+
['O', 'Trusted Execution Modules, Inc.'], ['OU', 'Certificates Division'], ['C', 'US']]
|
80
|
+
cert.issuer = issuer_cert.subject
|
81
|
+
cert.subject = cert_name
|
82
|
+
cert.not_before = Cert.extract_not_before(tag)
|
83
|
+
cert.not_after = Cert.extract_not_after(tag)
|
84
|
+
return cert
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
#returns a number
|
89
|
+
def self.extract_serial_num(tag)
|
90
|
+
serial_num_array = tag[0..3]
|
91
|
+
serial_num = 0
|
92
|
+
for i in (0..serial_num_array.length-1)
|
93
|
+
serial_num = serial_num << 8
|
94
|
+
serial_num += serial_num_array[i]
|
95
|
+
end
|
96
|
+
return serial_num
|
97
|
+
end
|
98
|
+
|
99
|
+
#returns a Time
|
100
|
+
def self.extract_not_before(tag)
|
101
|
+
time_array = tag[4..7]
|
102
|
+
offset_in_sec = 0
|
103
|
+
for i in (0..time_array.length-1)
|
104
|
+
offset_in_sec = offset_in_sec << 8
|
105
|
+
offset_in_sec += time_array[i]
|
106
|
+
end
|
107
|
+
return Time.at(offset_in_sec)
|
108
|
+
end
|
109
|
+
|
110
|
+
#returns a time
|
111
|
+
def self.extract_not_after(tag)
|
112
|
+
time_array = tag[8..11]
|
113
|
+
offset_in_sec = 0
|
114
|
+
for i in (0..time_array.length-1)
|
115
|
+
offset_in_sec = offset_in_sec << 8
|
116
|
+
offset_in_sec += time_array[i]
|
117
|
+
end
|
118
|
+
return Time.at(offset_in_sec)
|
119
|
+
end
|
120
|
+
|
121
|
+
#returns a OpenSSL::PKey::RSA public key
|
122
|
+
def self.extract_key(tag)
|
123
|
+
mod_array = tag[12..267]
|
124
|
+
mod = 0
|
125
|
+
for i in (0..mod_array.length-1)
|
126
|
+
mod = mod << 8
|
127
|
+
mod += mod_array[i]
|
128
|
+
end
|
129
|
+
exp_array = tag[268..271]
|
130
|
+
exp = 0
|
131
|
+
for i in (0..exp_array.length-1)
|
132
|
+
exp = exp << 8
|
133
|
+
exp += exp_array[i]
|
134
|
+
end
|
135
|
+
key = OpenSSL::PKey::RSA.new
|
136
|
+
key.n = mod
|
137
|
+
key.e = exp
|
138
|
+
return key.public_key
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
#@param cert A signed OpenSSL::X509::Certificate instance
|
143
|
+
#cert must be signed with sha1WithRSAEncryption algorithm
|
144
|
+
#TODO: how to make this method compatible with any algorithm
|
145
|
+
#@returns a byte array corresponding to the signature
|
146
|
+
def self.extract_sig_from_cert(cert)
|
147
|
+
str = 'Signature Algorithm: sha1WithRSAEncryption'
|
148
|
+
text_sig = cert.to_text
|
149
|
+
first_index = text_sig.index(str)
|
150
|
+
text_sig = text_sig[first_index+1..-1]
|
151
|
+
second_index = text_sig.index(str)
|
152
|
+
sig_start_index = second_index+str.length + 1 #the 1 is for the newline character
|
153
|
+
text_sig = text_sig[sig_start_index..-1]
|
154
|
+
sig_array = []
|
155
|
+
text_sig.each(':') {|byte| sig_array.push(byte.delete(':').hex)}
|
156
|
+
return sig_array
|
157
|
+
end
|
158
|
+
end
|
data/lib/tem/abi.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
module Tem::Abi
|
2
|
+
def self.included(klass)
|
3
|
+
klass.extend MixedMethods
|
4
|
+
|
5
|
+
klass.tem_value_type :byte, 1, :signed => true, :endian => :big
|
6
|
+
klass.tem_value_type :ubyte, 1, :signed => false, :endian => :big
|
7
|
+
klass.tem_value_type :short, 2, :signed => true, :endian => :big
|
8
|
+
klass.tem_value_type :ushort, 2, :signed => false, :endian => :big
|
9
|
+
klass.tem_value_type :ps_key, 20, :signed => false, :endian => :big
|
10
|
+
klass.tem_value_type :ps_value, 20, :signed => false, :endian => :big
|
11
|
+
end
|
12
|
+
|
13
|
+
module MixedMethods
|
14
|
+
def tem_value_type(name, bytes, options = {:signed => true, :endian => :big})
|
15
|
+
range = 1 << (8 * bytes)
|
16
|
+
if options[:signed]
|
17
|
+
min, max = -(range >> 1), (range >> 1) - 1
|
18
|
+
else
|
19
|
+
min, max = 0, range - 1
|
20
|
+
end
|
21
|
+
|
22
|
+
badass_defines = Proc.new do
|
23
|
+
define_method("read_tem_#{name}".to_sym) do |array, offset|
|
24
|
+
array = array.reverse unless options[:endian] == :big
|
25
|
+
n = (0...bytes).inject(0) { |v, i| (v << 8) | array[offset + i] }
|
26
|
+
rv = (options[:signed] and n > max) ? n - range : n
|
27
|
+
# pp [:read, name, array, offset, rv]
|
28
|
+
return rv
|
29
|
+
end
|
30
|
+
define_method("to_tem_#{name}".to_sym) do |n|
|
31
|
+
n = n.to_i
|
32
|
+
raise "Value #{n} not between #{min} and #{max}" unless (n <= max) and (n >= min)
|
33
|
+
n += range if(options[:signed] and n < 0)
|
34
|
+
array = []
|
35
|
+
bytes.times { array.push(n & 0xFF); n >>= 8 }
|
36
|
+
array.reverse! if options[:endian] == :big
|
37
|
+
# pp [:to, name, n, array]
|
38
|
+
return array
|
39
|
+
end
|
40
|
+
define_method("to_tem_#{name}_reladdr".to_sym) do |n|
|
41
|
+
n = n.to_i
|
42
|
+
n += range if (n < 0 and (not options[:signed]))
|
43
|
+
array = []
|
44
|
+
bytes.times { array.push(n & 0xFF); n >>= 8 }
|
45
|
+
array.reverse! if options[:endian] == :big
|
46
|
+
return array
|
47
|
+
end
|
48
|
+
define_method("tem_#{name}_length".to_sym) { bytes }
|
49
|
+
end
|
50
|
+
|
51
|
+
self.class_eval(&badass_defines)
|
52
|
+
(class << self; self; end).module_eval(&badass_defines)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|