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 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
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # benchmarks a TEM
4
+ require 'rubygems'
5
+ require 'tem_ruby'
6
+
7
+ require 'timings/timings.rb'
8
+
9
+ TemTimings.all_timings
data/bin/tem_ca ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Manages the TEM Certificates and CA
4
+
5
+ require 'rubygems'
6
+ require 'tem_ruby'
7
+
8
+ case ARGV[0]
9
+ when 'config'
10
+ Tem::CA.scaffold_config
11
+ when 'ca'
12
+ Tem::CA.scaffold_ca
13
+ end
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
Binary file
@@ -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