Module: Tem::Cert

Defined in:
lib/tem/_cert.rb

Overview

@author: Jorge de la Garza (MIT ‘08), [email protected] The Cert module contains methods for digesting a X.509 certificate into a tag for the TEM and to methods to reconstruct the certificate from the tag. Methods to create some sample certificates are also included for convenience.

Class Method Summary collapse

Class Method Details

.create_cert_from_tag(tag, issuer_cert) ⇒ Object

Parameters:

  • tag

    The tag read from the TEM

  • issuer_cert

    The OpenSSL::X509::Certificate of the entity that issued the TEM’s certificate



74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/tem/_cert.rb', line 74

def self.create_cert_from_tag(tag, issuer_cert)
  cert = OpenSSL::X509::Certificate.new
  cert.public_key = Cert.extract_key(tag)
  cert.serial = Cert.extract_serial_num(tag)
  cert_name = OpenSSL::X509::Name.new [['CN', 'TEM Device'], ['L', 'Cambridge'], ['ST', 'Massachusetts'],\
                       ['O', 'Trusted Execution Modules, Inc.'], ['OU', 'Certificates Division'], ['C', 'US']]
  cert.issuer = issuer_cert.subject
  cert.subject = cert_name
  cert.not_before = Cert.extract_not_before(tag)
  cert.not_after = Cert.extract_not_after(tag)
  return cert
end

.create_issuer_cert(key) ⇒ Object

Parameters:

  • key

    An OpenSSL::PKey instance that will be this cert’s key and will be used to sign this cert



13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/tem/_cert.rb', line 13

def self.create_issuer_cert(key)
  issuer_cert = OpenSSL::X509::Certificate.new
  issuer_cert.public_key = key.public_key
  issuer_dist_name = OpenSSL::X509::Name.new [['CN', 'TEM Manufacturer'], ['L', 'Cambridge'], ['ST', 'Massachusetts'],\
                       ['O', 'Trusted Execution Modules, Inc.'], ['OU', 'Certificates Division'], ['C', 'US']]
  issuer_cert.issuer = issuer_dist_name
  issuer_cert.subject = issuer_dist_name
  issuer_cert.not_before = Time.now
  issuer_cert.not_after = Time.now + (60 * 60 * 24 * 365.25) * 10
  issuer_cert.sign key, OpenSSL::Digest::SHA1.new
  return issuer_cert
end

.create_subject_cert(subject_key, issuer_key, issuer_cert) ⇒ Object

Parameters:

  • subject_key

    An OpenSSL::PKey instance that will be this cert’s key

  • issuer_key

    An OpenSSL::Pkey instance that will be used to sign this cert (i.e. the issuer’s/manufacturer’s key)

  • issuer_cert

    The OpenSSL::X509::Certificate instance of the authority that issued this cert



31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/tem/_cert.rb', line 31

def self.create_subject_cert(subject_key, issuer_key, issuer_cert)
  subject_cert = OpenSSL::X509::Certificate.new
  subject_cert.public_key = subject_key.public_key
  subject_cert.serial = Time.now.to_i   #no significance to this #, just a value for demonstration of purpose
  subject_dist_name = OpenSSL::X509::Name.new [['CN', 'TEM Device'], ['L', 'Cambridge'], ['ST', 'Massachusetts'],\
                       ['O', 'Trusted Execution Modules, Inc.'], ['OU', 'Certificates Division'], ['C', 'US']]
  subject_cert.issuer = issuer_cert.subject
  subject_cert.subject = subject_dist_name
  subject_cert.not_before = Time.now
  subject_cert.not_after = Time.now + (60 * 60 * 24 * 365.25) * 10
  subject_cert.sign issuer_key, OpenSSL::Digest::SHA1.new
  return subject_cert
end

.create_tag_from_cert(cert) ⇒ Object

The tag is 527 bytes long. What the bytes encode is as follows:

-Serial number   tag[0..3]
-Not before date tag[4..7]
-Not after date  tag[8..11]
-Modulus         tag[12..267]
-Public key exp  tag[268..270]
-Signature       tag[271..526]

Parameters:

  • cert

    An OpenSSL::X509::Certificate instance



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/tem/_cert.rb', line 55

def self.create_tag_from_cert(cert)
  tag_serial_num = Tem::CryptoAbi.to_tem_bignum(OpenSSL::BN.new(cert.serial.to_s))
  while tag_serial_num.length < 4
    tag_serial_num = [0] + tag_serial_num  #make sure array is 4 bytes
  end
  #The dates are encoded as the number of seconds since epoch (Jan 1, 1970 00:00:00 GMT)
  #TODO: check that dates are exactly 4 bytes, else throw an exception
  tag_not_before = Tem::CryptoAbi.to_tem_bignum(OpenSSL::BN.new(cert.not_before.to_i.to_s))
  tag_not_after = Tem::CryptoAbi.to_tem_bignum(OpenSSL::BN.new(cert.not_after.to_i.to_s))
  tag_modulus = Tem::CryptoAbi.to_tem_bignum(OpenSSL::BN.new(cert.public_key.n.to_s))
  #TODO: ensure that exponent is exactly three bytes, or come up with a safer way to encode it
  tag_public_exp = Tem::CryptoAbi.to_tem_bignum(OpenSSL::BN.new(cert.public_key.e.to_s))
  tag = [tag_serial_num, tag_not_before, tag_not_after, tag_modulus, tag_public_exp].flatten
  return tag
end

.extract_key(tag) ⇒ Object

returns a OpenSSL::PKey::RSA public key



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/tem/_cert.rb', line 122

def self.extract_key(tag)
  mod_array = tag[12..267]
  mod = 0
  for i in (0..mod_array.length-1)
    mod = mod << 8
    mod += mod_array[i]
  end
  exp_array = tag[268..271]
  exp = 0
  for i in (0..exp_array.length-1)
    exp = exp << 8
    exp += exp_array[i]
  end
  key = OpenSSL::PKey::RSA.new
  key.n = mod
  key.e = exp
  return key.public_key
end

.extract_not_after(tag) ⇒ Object

returns a time



111
112
113
114
115
116
117
118
119
# File 'lib/tem/_cert.rb', line 111

def self.extract_not_after(tag)
  time_array = tag[8..11]
  offset_in_sec = 0
  for i in (0..time_array.length-1)
    offset_in_sec = offset_in_sec << 8
    offset_in_sec += time_array[i]
  end
  return Time.at(offset_in_sec)
end

.extract_not_before(tag) ⇒ Object

returns a Time



100
101
102
103
104
105
106
107
108
# File 'lib/tem/_cert.rb', line 100

def self.extract_not_before(tag)
  time_array = tag[4..7]
  offset_in_sec = 0
  for i in (0..time_array.length-1)
    offset_in_sec = offset_in_sec << 8
    offset_in_sec += time_array[i]
  end
  return Time.at(offset_in_sec)
end

.extract_serial_num(tag) ⇒ Object

returns a number



89
90
91
92
93
94
95
96
97
# File 'lib/tem/_cert.rb', line 89

def self.extract_serial_num(tag)
  serial_num_array = tag[0..3]
  serial_num = 0
  for i in (0..serial_num_array.length-1)
    serial_num = serial_num << 8
    serial_num += serial_num_array[i]
  end
  return serial_num
end

.extract_sig_from_cert(cert) ⇒ Object

cert must be signed with sha1WithRSAEncryption algorithm TODO: how to make this method compatible with any algorithm

Parameters:

  • cert

    A signed OpenSSL::X509::Certificate instance



146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/tem/_cert.rb', line 146

def self.extract_sig_from_cert(cert)
  str = 'Signature Algorithm: sha1WithRSAEncryption'
  text_sig = cert.to_text
  first_index = text_sig.index(str)
  text_sig = text_sig[first_index+1..-1]
  second_index = text_sig.index(str)
  sig_start_index = second_index+str.length + 1 #the 1 is for the newline character
  text_sig = text_sig[sig_start_index..-1]
  sig_array = []
  text_sig.each(':') {|byte| sig_array.push(byte.delete(':').hex)}
  return sig_array
end