tem_ruby 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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