tem_ruby 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|