certificate_authority 0.1.3 → 0.1.4

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.
@@ -3,60 +3,93 @@ module CertificateAuthority
3
3
  def public_key
4
4
  raise "Required implementation"
5
5
  end
6
-
6
+
7
7
  def private_key
8
8
  raise "Required implementation"
9
9
  end
10
-
10
+
11
11
  def is_in_hardware?
12
12
  raise "Required implementation"
13
13
  end
14
-
14
+
15
15
  def is_in_memory?
16
16
  raise "Required implementation"
17
17
  end
18
18
  end
19
-
19
+
20
20
  class MemoryKeyMaterial
21
21
  include KeyMaterial
22
22
  include ActiveModel::Validations
23
-
23
+
24
24
  attr_accessor :keypair
25
25
  attr_accessor :private_key
26
26
  attr_accessor :public_key
27
-
27
+
28
28
  def initialize
29
29
  end
30
-
30
+
31
31
  validates_each :private_key do |record, attr, value|
32
32
  record.errors.add :private_key, "cannot be blank" if record.private_key.nil?
33
33
  end
34
34
  validates_each :public_key do |record, attr, value|
35
35
  record.errors.add :public_key, "cannot be blank" if record.public_key.nil?
36
36
  end
37
-
37
+
38
38
  def is_in_hardware?
39
39
  false
40
40
  end
41
-
41
+
42
42
  def is_in_memory?
43
43
  true
44
44
  end
45
-
46
- def generate_key(modulus_bits=1024)
45
+
46
+ def generate_key(modulus_bits=2048)
47
47
  self.keypair = OpenSSL::PKey::RSA.new(modulus_bits)
48
48
  self.private_key = keypair
49
49
  self.public_key = keypair.public_key
50
50
  self.keypair
51
51
  end
52
-
52
+
53
53
  def private_key
54
54
  @private_key
55
55
  end
56
-
56
+
57
57
  def public_key
58
58
  @public_key
59
59
  end
60
-
61
60
  end
62
- end
61
+
62
+ class SigningRequestKeyMaterial
63
+ include KeyMaterial
64
+ include ActiveModel::Validations
65
+
66
+ validates_each :public_key do |record, attr, value|
67
+ record.errors.add :public_key, "cannot be blank" if record.public_key.nil?
68
+ end
69
+
70
+ attr_accessor :public_key
71
+
72
+ def initialize(request=nil)
73
+ if request.is_a? OpenSSL::X509::Request
74
+ raise "Invalid certificate signing request" unless request.verify request.public_key
75
+ self.public_key = request.public_key
76
+ end
77
+ end
78
+
79
+ def is_in_hardware?
80
+ false
81
+ end
82
+
83
+ def is_in_memory?
84
+ true
85
+ end
86
+
87
+ def private_key
88
+ nil
89
+ end
90
+
91
+ def public_key
92
+ @public_key
93
+ end
94
+ end
95
+ end
@@ -1,77 +1,77 @@
1
1
  module CertificateAuthority
2
2
  class OCSPHandler
3
3
  include ActiveModel::Validations
4
-
4
+
5
5
  attr_accessor :ocsp_request
6
6
  attr_accessor :certificate_ids
7
-
7
+
8
8
  attr_accessor :certificates
9
9
  attr_accessor :parent
10
-
10
+
11
11
  attr_accessor :ocsp_response_body
12
-
12
+
13
13
  validate do |crl|
14
14
  errors.add :parent, "A parent entity must be set" if parent.nil?
15
15
  end
16
16
  validate :all_certificates_available
17
-
17
+
18
18
  def initialize
19
19
  self.certificates = {}
20
20
  end
21
-
21
+
22
22
  def <<(cert)
23
23
  self.certificates[cert.serial_number.number.to_s] = cert
24
24
  end
25
-
25
+
26
26
  def extract_certificate_serials
27
27
  raise "No valid OCSP request was supplied" if self.ocsp_request.nil?
28
28
  openssl_request = OpenSSL::OCSP::Request.new(self.ocsp_request)
29
-
29
+
30
30
  self.certificate_ids = openssl_request.certid.collect do |cert_id|
31
31
  cert_id.serial
32
32
  end
33
-
33
+
34
34
  self.certificate_ids
35
35
  end
36
-
37
-
36
+
37
+
38
38
  def response
39
39
  raise "Invalid response" unless valid?
40
-
40
+
41
41
  openssl_ocsp_response = OpenSSL::OCSP::BasicResponse.new
42
42
  openssl_ocsp_request = OpenSSL::OCSP::Request.new(self.ocsp_request)
43
43
  openssl_ocsp_response.copy_nonce(openssl_ocsp_request)
44
-
44
+
45
45
  openssl_ocsp_request.certid.each do |cert_id|
46
46
  certificate = self.certificates[cert_id.serial.to_s]
47
-
48
- openssl_ocsp_response.add_status(cert_id,
49
- OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0,
47
+
48
+ openssl_ocsp_response.add_status(cert_id,
49
+ OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0,
50
50
  0, 0, 30, nil)
51
51
  end
52
-
53
-
52
+
53
+
54
54
  openssl_ocsp_response.sign(OpenSSL::X509::Certificate.new(self.parent.to_pem), self.parent.key_material.private_key, nil, nil)
55
55
  final_response = OpenSSL::OCSP::Response.create(OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, openssl_ocsp_response)
56
56
  self.ocsp_response_body = final_response
57
57
  self.ocsp_response_body
58
58
  end
59
-
59
+
60
60
  def to_der
61
61
  raise "No signed OCSP response body available" if self.ocsp_response_body.nil?
62
62
  self.ocsp_response_body.to_der
63
63
  end
64
-
64
+
65
65
  private
66
-
66
+
67
67
  def all_certificates_available
68
68
  openssl_ocsp_request = OpenSSL::OCSP::Request.new(self.ocsp_request)
69
-
69
+
70
70
  openssl_ocsp_request.certid.each do |cert_id|
71
71
  certificate = self.certificates[cert_id.serial.to_s]
72
72
  errors.add(:base, "Certificate #{cert_id.serial} has not been added yet") if certificate.nil?
73
73
  end
74
74
  end
75
-
75
+
76
76
  end
77
- end
77
+ end
@@ -3,43 +3,43 @@ module CertificateAuthority
3
3
  include KeyMaterial
4
4
  include ActiveModel::Validations
5
5
  include ActiveModel::Serialization
6
-
6
+
7
7
  attr_accessor :engine
8
8
  attr_accessor :token_id
9
9
  attr_accessor :pkcs11_lib
10
10
  attr_accessor :openssl_pkcs11_engine_lib
11
11
  attr_accessor :pin
12
-
12
+
13
13
  def initialize(attributes = {})
14
14
  @attributes = attributes
15
15
  initialize_engine
16
16
  end
17
-
17
+
18
18
  def is_in_hardware?
19
19
  true
20
20
  end
21
-
21
+
22
22
  def is_in_memory?
23
23
  false
24
24
  end
25
-
25
+
26
26
  def generate_key(modulus_bits=1024)
27
27
  puts "Key generation is not currently supported in hardware"
28
28
  nil
29
29
  end
30
-
30
+
31
31
  def private_key
32
32
  initialize_engine
33
33
  self.engine.load_private_key(self.token_id)
34
34
  end
35
-
35
+
36
36
  def public_key
37
37
  initialize_engine
38
38
  self.engine.load_public_key(self.token_id)
39
39
  end
40
-
40
+
41
41
  private
42
-
42
+
43
43
  def initialize_engine
44
44
  ## We're going to return early and try again later if params weren't passed in
45
45
  ## at initialization. Any attempt at getting a public/private key will try
@@ -47,7 +47,7 @@ module CertificateAuthority
47
47
  return false if self.openssl_pkcs11_engine_lib.nil? or self.pkcs11_lib.nil?
48
48
  return self.engine unless self.engine.nil?
49
49
  OpenSSL::Engine.load
50
-
50
+
51
51
  pkcs11 = OpenSSL::Engine.by_id("dynamic") do |e|
52
52
  e.ctrl_cmd("SO_PATH",self.openssl_pkcs11_engine_lib)
53
53
  e.ctrl_cmd("ID","pkcs11")
@@ -56,10 +56,10 @@ module CertificateAuthority
56
56
  e.ctrl_cmd("PIN",self.pin) unless self.pin.nil? or self.pin == ""
57
57
  e.ctrl_cmd("MODULE_PATH",self.pkcs11_lib)
58
58
  end
59
-
59
+
60
60
  self.engine = pkcs11
61
61
  pkcs11
62
62
  end
63
-
63
+
64
64
  end
65
- end
65
+ end
@@ -1,9 +1,9 @@
1
1
  module CertificateAuthority
2
2
  class SerialNumber
3
3
  include ActiveModel::Validations
4
-
4
+
5
5
  attr_accessor :number
6
-
6
+
7
7
  validates :number, :presence => true, :numericality => {:greater_than => 0}
8
8
  end
9
- end
9
+ end
@@ -1,18 +1,16 @@
1
1
  module CertificateAuthority
2
2
  module SigningEntity
3
-
3
+
4
4
  def self.included(mod)
5
5
  mod.class_eval do
6
- attr_accessor :signing_entity
6
+ attr_accessor :signing_entity
7
7
  end
8
8
  end
9
-
9
+
10
10
  def signing_entity=(val)
11
11
  raise "invalid param" unless [true,false].include?(val)
12
12
  @signing_entity = val
13
13
  end
14
-
15
-
16
-
14
+
17
15
  end
18
- end
16
+ end
@@ -3,44 +3,44 @@ require File.dirname(__FILE__) + '/units_helper'
3
3
  describe CertificateAuthority::CertificateRevocationList do
4
4
  before(:each) do
5
5
  @crl = CertificateAuthority::CertificateRevocationList.new
6
-
6
+
7
7
  @root_certificate = CertificateAuthority::Certificate.new
8
8
  @root_certificate.signing_entity = true
9
9
  @root_certificate.subject.common_name = "CRL Root"
10
- @root_certificate.key_material.generate_key
10
+ @root_certificate.key_material.generate_key(1024)
11
11
  @root_certificate.serial_number.number = 1
12
12
  @root_certificate.sign!
13
-
13
+
14
14
  @certificate = CertificateAuthority::Certificate.new
15
- @certificate.key_material.generate_key
15
+ @certificate.key_material.generate_key(1024)
16
16
  @certificate.subject.common_name = "http://bogusSite.com"
17
17
  @certificate.parent = @root_certificate
18
18
  @certificate.serial_number.number = 2
19
19
  @certificate.sign!
20
-
20
+
21
21
  @crl.parent = @root_certificate
22
22
  @certificate.revoked_at = Time.now
23
23
  end
24
-
24
+
25
25
  it "should accept a list of certificates" do
26
26
  @crl << @certificate
27
27
  end
28
-
28
+
29
29
  it "should complain if you add a certificate without a revocation time" do
30
30
  @certificate.revoked_at = nil
31
31
  lambda{ @crl << @certificate}.should raise_error
32
32
  end
33
-
33
+
34
34
  it "should have a 'parent' that will be responsible for signing" do
35
35
  @crl.parent = @root_certificate
36
36
  @crl.parent.should_not be_nil
37
37
  end
38
-
38
+
39
39
  it "should raise an error if you try and sign a CRL without attaching a parent" do
40
40
  @crl.parent = nil
41
41
  lambda { @crl.sign! }.should raise_error
42
42
  end
43
-
43
+
44
44
  it "should be able to generate a proper CRL" do
45
45
  @crl << @certificate
46
46
  lambda {@crl.to_pem}.should raise_error
@@ -49,20 +49,20 @@ describe CertificateAuthority::CertificateRevocationList do
49
49
  @crl.to_pem.should_not be_nil
50
50
  OpenSSL::X509::CRL.new(@crl.to_pem).should_not be_nil
51
51
  end
52
-
52
+
53
53
  describe "Next update" do
54
54
  it "should be able to set a 'next_update' value" do
55
55
  @crl.next_update = (60 * 60 * 10) # 10 Hours
56
56
  @crl.next_update.should_not be_nil
57
57
  end
58
-
58
+
59
59
  it "should throw an error if we try and sign up with a negative next_update" do
60
60
  @crl.sign!
61
61
  @crl.next_update = - (60 * 60 * 10)
62
62
  lambda{@crl.sign!}.should raise_error
63
63
  end
64
-
64
+
65
65
  end
66
-
67
-
68
- end
66
+
67
+
68
+ end
@@ -4,165 +4,163 @@ describe CertificateAuthority::Certificate do
4
4
  before(:each) do
5
5
  @certificate = CertificateAuthority::Certificate.new
6
6
  end
7
-
7
+
8
8
  describe CertificateAuthority::SigningEntity do
9
9
  it "should behave as a signing entity" do
10
10
  @certificate.respond_to?(:is_signing_entity?).should be_true
11
11
  end
12
-
12
+
13
13
  it "should only be a signing entity if it's identified as a CA", :rfc3280 => true do
14
14
  @certificate.is_signing_entity?.should be_false
15
15
  @certificate.signing_entity = true
16
16
  @certificate.is_signing_entity?.should be_true
17
17
  end
18
-
18
+
19
19
  describe "Root certificates" do
20
20
  before(:each) do
21
21
  @certificate.signing_entity = true
22
22
  end
23
-
23
+
24
24
  it "should be able to be identified as a root certificate" do
25
25
  @certificate.is_root_entity?.should be_true
26
26
  end
27
-
27
+
28
28
  it "should only be a root certificate if the parent entity is itself", :rfc3280 => true do
29
29
  @certificate.parent.should == @certificate
30
30
  end
31
-
31
+
32
32
  it "should be a root certificate by default" do
33
33
  @certificate.is_root_entity?.should be_true
34
34
  end
35
-
35
+
36
36
  it "should be able to self-sign" do
37
37
  @certificate.serial_number.number = 1
38
38
  @certificate.subject.common_name = "chrischandler.name"
39
- @certificate.key_material.generate_key
39
+ @certificate.key_material.generate_key(1024)
40
40
  @certificate.sign!
41
41
  cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
42
42
  cert.subject.to_s.should == cert.issuer.to_s
43
43
  end
44
-
44
+
45
45
  it "should have the basicContraint CA:TRUE" do
46
46
  @certificate.serial_number.number = 1
47
47
  @certificate.subject.common_name = "chrischandler.name"
48
- @certificate.key_material.generate_key
48
+ @certificate.key_material.generate_key(1024)
49
49
  @certificate.sign!
50
50
  cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
51
51
  cert.extensions.map{|i| [i.oid,i.value] }.select{|i| i.first == "basicConstraints"}.first[1].should == "CA:TRUE"
52
52
  end
53
53
  end
54
-
54
+
55
55
  describe "Intermediate certificates" do
56
56
  before(:each) do
57
57
  @different_cert = CertificateAuthority::Certificate.new
58
58
  @different_cert.signing_entity = true
59
59
  @different_cert.subject.common_name = "chrischandler.name root"
60
- @different_cert.key_material.generate_key
60
+ @different_cert.key_material.generate_key(1024)
61
61
  @different_cert.serial_number.number = 2
62
62
  @different_cert.sign! #self-signed
63
63
  @certificate.parent = @different_cert
64
64
  @certificate.signing_entity = true
65
65
  end
66
-
66
+
67
67
  it "should be able to be identified as an intermediate certificate" do
68
68
  @certificate.is_intermediate_entity?.should be_true
69
69
  end
70
-
70
+
71
71
  it "should not be identified as a root" do
72
72
  @certificate.is_root_entity?.should be_false
73
73
  end
74
-
74
+
75
75
  it "should only be an intermediate certificate if the parent is a different entity" do
76
76
  @certificate.parent.should_not == @certificate
77
77
  @certificate.parent.should_not be_nil
78
78
  end
79
-
79
+
80
80
  it "should correctly be signed by a parent certificate" do
81
81
  @certificate.subject.common_name = "chrischandler.name"
82
- @certificate.key_material.generate_key
82
+ @certificate.key_material.generate_key(1024)
83
83
  @certificate.signing_entity = true
84
84
  @certificate.serial_number.number = 1
85
85
  @certificate.sign!
86
86
  cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
87
87
  cert.subject.to_s.should_not == cert.issuer.to_s
88
88
  end
89
-
89
+
90
90
  it "should have the basicContraint CA:TRUE" do
91
91
  @certificate.subject.common_name = "chrischandler.name"
92
- @certificate.key_material.generate_key
92
+ @certificate.key_material.generate_key(1024)
93
93
  @certificate.signing_entity = true
94
94
  @certificate.serial_number.number = 3
95
95
  @certificate.sign!
96
96
  cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
97
- # cert.extensions.first.value.should == "CA:TRUE"
98
97
  cert.extensions.map{|i| [i.oid,i.value] }.select{|i| i.first == "basicConstraints"}.first[1].should == "CA:TRUE"
99
98
  end
100
-
99
+
101
100
  end
102
-
101
+
103
102
  describe "Terminal certificates" do
104
103
  before(:each) do
105
104
  @different_cert = CertificateAuthority::Certificate.new
106
105
  @different_cert.signing_entity = true
107
106
  @different_cert.subject.common_name = "chrischandler.name root"
108
- @different_cert.key_material.generate_key
107
+ @different_cert.key_material.generate_key(1024)
109
108
  @different_cert.serial_number.number = 1
110
109
  @different_cert.sign! #self-signed
111
110
  @certificate.parent = @different_cert
112
111
  end
113
-
112
+
114
113
  it "should not be identified as an intermediate certificate" do
115
114
  @certificate.is_intermediate_entity?.should be_false
116
115
  end
117
-
116
+
118
117
  it "should not be identified as a root" do
119
118
  @certificate.is_root_entity?.should be_false
120
119
  end
121
-
120
+
122
121
  it "should have the basicContraint CA:FALSE" do
123
122
  @certificate.subject.common_name = "chrischandler.name"
124
- @certificate.key_material.generate_key
123
+ @certificate.key_material.generate_key(1024)
125
124
  @certificate.signing_entity = false
126
125
  @certificate.serial_number.number = 1
127
126
  @certificate.sign!
128
127
  cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
129
- # cert.extensions.first.value.should == "CA:FALSE"
130
128
  cert.extensions.map{|i| [i.oid,i.value] }.select{|i| i.first == "basicConstraints"}.first[1].should == "CA:FALSE"
131
129
  end
132
130
  end
133
-
131
+
134
132
 
135
133
  it "should be able to be identified as a root certificate" do
136
134
  @certificate.respond_to?(:is_root_entity?).should be_true
137
135
  end
138
136
  end #End of SigningEntity
139
-
137
+
140
138
  describe "Signed certificates" do
141
139
  before(:each) do
142
140
  @certificate = CertificateAuthority::Certificate.new
143
141
  @certificate.subject.common_name = "chrischandler.name"
144
- @certificate.key_material.generate_key
142
+ @certificate.key_material.generate_key(1024)
145
143
  @certificate.serial_number.number = 1
146
144
  @certificate.sign!
147
145
  end
148
-
146
+
149
147
  it "should have a PEM encoded certificate body available" do
150
148
  @certificate.to_pem.should_not be_nil
151
149
  OpenSSL::X509::Certificate.new(@certificate.to_pem).should_not be_nil
152
150
  end
153
151
  end
154
-
152
+
155
153
  describe "X.509 V3 Extensions on Signed Certificates" do
156
154
  before(:each) do
157
155
  @certificate = CertificateAuthority::Certificate.new
158
156
  @certificate.subject.common_name = "chrischandler.name"
159
- @certificate.key_material.generate_key
157
+ @certificate.key_material.generate_key(1024)
160
158
  @certificate.serial_number.number = 1
161
159
  @signing_profile = {
162
160
  "extensions" => {
163
161
  "subjectAltName" => {"uris" => ["www.chrischandler.name"]},
164
- "certificatePolicies" => {
165
- "policy_identifier" => "1.3.5.7",
162
+ "certificatePolicies" => {
163
+ "policy_identifier" => "1.3.5.7",
166
164
  "cps_uris" => ["http://my.host.name/", "http://my.your.name/"],
167
165
  "user_notice" => {
168
166
  "explicit_text" => "Testing!", "organization" => "RSpec Test organization name", "notice_numbers" => "1,2,3,4"
@@ -172,58 +170,78 @@ describe CertificateAuthority::Certificate do
172
170
  }
173
171
  @certificate.sign!(@signing_profile)
174
172
  end
175
-
173
+
176
174
  describe "SubjectAltName" do
177
175
  before(:each) do
178
176
  @certificate = CertificateAuthority::Certificate.new
179
177
  @certificate.subject.common_name = "chrischandler.name"
180
- @certificate.key_material.generate_key
178
+ @certificate.key_material.generate_key(1024)
181
179
  @certificate.serial_number.number = 1
182
180
  end
183
-
184
- it "should have a subjectAltName if specified" do
181
+
182
+ it "should have a subjectAltName if specified" do
185
183
  @certificate.sign!({"extensions" => {"subjectAltName" => {"uris" => ["www.chrischandler.name"]}}})
186
184
  cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
187
185
  cert.extensions.map(&:oid).include?("subjectAltName").should be_true
188
186
  end
189
-
187
+
190
188
  it "should NOT have a subjectAltName if one was not specified" do
191
189
  @certificate.sign!
192
190
  cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
193
191
  cert.extensions.map(&:oid).include?("subjectAltName").should be_false
194
192
  end
195
193
  end
196
-
194
+
197
195
  describe "AuthorityInfoAccess" do
198
196
  before(:each) do
199
197
  @certificate = CertificateAuthority::Certificate.new
200
198
  @certificate.subject.common_name = "chrischandler.name"
201
- @certificate.key_material.generate_key
199
+ @certificate.key_material.generate_key(1024)
202
200
  @certificate.serial_number.number = 1
203
201
  end
204
-
202
+
205
203
  it "should have an authority info access if specified" do
206
204
  @certificate.sign!({"extensions" => {"authorityInfoAccess" => {"ocsp" => ["www.chrischandler.name"]}}})
207
205
  cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
208
206
  cert.extensions.map(&:oid).include?("authorityInfoAccess").should be_true
209
207
  end
210
-
211
208
  end
212
-
213
-
209
+
210
+ describe "CrlDistributionPoints" do
211
+ before(:each) do
212
+ @certificate = CertificateAuthority::Certificate.new
213
+ @certificate.subject.common_name = "chrischandler.name"
214
+ @certificate.key_material.generate_key(1024)
215
+ @certificate.serial_number.number = 1
216
+ end
217
+
218
+ it "should have a crlDistributionPoint if specified" do
219
+ @certificate.sign!({"extensions" => {"crlDistributionPoints" => {"uri" => ["http://crlThingy.com"]}}})
220
+ cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
221
+ cert.extensions.map(&:oid).include?("crlDistributionPoints").should be_true
222
+ end
223
+
224
+ it "should NOT have a crlDistributionPoint if one was not specified" do
225
+ @certificate.sign!
226
+ cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
227
+ cert.extensions.map(&:oid).include?("crlDistributionPoints").should be_false
228
+ end
229
+ end
230
+
231
+
214
232
  describe "CertificatePolicies" do
215
233
  before(:each) do
216
234
  @certificate = CertificateAuthority::Certificate.new
217
235
  @certificate.subject.common_name = "chrischandler.name"
218
- @certificate.key_material.generate_key
236
+ @certificate.key_material.generate_key(1024)
219
237
  @certificate.serial_number.number = 1
220
238
  end
221
-
239
+
222
240
  it "should have a certificatePolicy if specified" do
223
241
  @certificate.sign!({
224
242
  "extensions" => {
225
- "certificatePolicies" => {
226
- "policy_identifier" => "1.3.5.7",
243
+ "certificatePolicies" => {
244
+ "policy_identifier" => "1.3.5.7",
227
245
  "cps_uris" => ["http://my.host.name/", "http://my.your.name/"]
228
246
  }
229
247
  }
@@ -231,13 +249,13 @@ describe CertificateAuthority::Certificate do
231
249
  cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
232
250
  cert.extensions.map(&:oid).include?("certificatePolicies").should be_true
233
251
  end
234
-
252
+
235
253
  it "should contain a nested userNotice if specified" do
236
254
  pending
237
255
  # @certificate.sign!({
238
256
  # "extensions" => {
239
- # "certificatePolicies" => {
240
- # "policy_identifier" => "1.3.5.7",
257
+ # "certificatePolicies" => {
258
+ # "policy_identifier" => "1.3.5.7",
241
259
  # "cps_uris" => ["http://my.host.name/", "http://my.your.name/"],
242
260
  # "user_notice" => {
243
261
  # "explicit_text" => "Testing!", "organization" => "RSpec Test organization name", "notice_numbers" => "1,2,3,4"
@@ -248,53 +266,55 @@ describe CertificateAuthority::Certificate do
248
266
  # cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
249
267
  # cert.extensions.map(&:oid).include?("certificatePolicies").should be_true
250
268
  end
251
-
269
+
252
270
  it "should NOT include a certificatePolicy if not specified" do
253
271
  @certificate.sign!
254
272
  cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
255
273
  cert.extensions.map(&:oid).include?("certificatePolicies").should be_false
256
- end
274
+ end
257
275
  end
258
-
259
-
276
+
277
+
260
278
  it "should support BasicContraints" do
261
279
  cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
262
280
  cert.extensions.map(&:oid).include?("basicConstraints").should be_true
263
281
  end
264
-
265
- it "should support crlDistributionPoints" do
266
- cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
267
- cert.extensions.map(&:oid).include?("crlDistributionPoints").should be_true
268
- end
269
-
282
+
270
283
  it "should support subjectKeyIdentifier" do
271
284
  cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
272
285
  cert.extensions.map(&:oid).include?("subjectKeyIdentifier").should be_true
273
286
  end
274
-
287
+
275
288
  it "should support authorityKeyIdentifier" do
276
289
  cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
277
290
  cert.extensions.map(&:oid).include?("authorityKeyIdentifier").should be_true
278
291
  end
279
-
292
+
293
+ it "should order subjectKeyIdentifier before authorityKeyIdentifier" do
294
+ cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
295
+ cert.extensions.map(&:oid).select do |oid|
296
+ ["subjectKeyIdentifier", "authorityKeyIdentifier"].include?(oid)
297
+ end.should == ["subjectKeyIdentifier", "authorityKeyIdentifier"]
298
+ end
299
+
280
300
  it "should support keyUsage" do
281
301
  cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
282
302
  cert.extensions.map(&:oid).include?("keyUsage").should be_true
283
303
  end
284
-
304
+
285
305
  it "should support extendedKeyUsage" do
286
306
  cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
287
307
  cert.extensions.map(&:oid).include?("extendedKeyUsage").should be_true
288
308
  end
289
309
  end
290
-
310
+
291
311
  describe "Signing profile" do
292
312
  before(:each) do
293
313
  @certificate = CertificateAuthority::Certificate.new
294
314
  @certificate.subject.common_name = "chrischandler.name"
295
- @certificate.key_material.generate_key
315
+ @certificate.key_material.generate_key(1024)
296
316
  @certificate.serial_number.number = 1
297
-
317
+
298
318
  @signing_profile = {
299
319
  "extensions" => {
300
320
  "basicConstraints" => {"ca" => false},
@@ -313,51 +333,96 @@ describe CertificateAuthority::Certificate do
313
333
  }
314
334
  }
315
335
  end
316
-
336
+
317
337
  it "should be able to sign with an optional policy hash" do
318
338
  @certificate.sign!(@signing_profile)
319
339
  end
320
-
340
+
341
+ it "should support a default signing digest of SHA512" do
342
+ @certificate.sign!(@signing_profile)
343
+ cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
344
+ cert.signature_algorithm.should == "sha512WithRSAEncryption"
345
+ end
346
+
347
+ it "should support a configurable digest algorithm" do
348
+ @signing_profile.merge!({"digest" => "SHA1"})
349
+ @certificate.sign!(@signing_profile)
350
+ cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
351
+ cert.signature_algorithm.should == "sha1WithRSAEncryption"
352
+ end
353
+
354
+ end
355
+
356
+ describe "from_openssl" do
357
+ before(:each) do
358
+ @pem_cert=<<CERT
359
+ -----BEGIN CERTIFICATE-----
360
+ MIICFDCCAc6gAwIBAgIJAPDLgMilKuayMA0GCSqGSIb3DQEBBQUAMEgxCzAJBgNV
361
+ BAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMQowCAYDVQQKEwEgMRgwFgYDVQQD
362
+ Ew9WZXJ5IFNtYWxsIENlcnQwHhcNMTIwNTAzMDMyODI1WhcNMTMwNTAzMDMyODI1
363
+ WjBIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKU29tZS1TdGF0ZTEKMAgGA1UEChMB
364
+ IDEYMBYGA1UEAxMPVmVyeSBTbWFsbCBDZXJ0MEwwDQYJKoZIhvcNAQEBBQADOwAw
365
+ OAIxAN6+33+WQ3FBMt+vMhshxOj+8W7V64pDKCJ3pVlnSn36imBWqrN0AGWX8qjv
366
+ S+GzGwIDAQABo4GqMIGnMB0GA1UdDgQWBBRMUQ/HpPrAkKOufS5h+xPtEuzyWDB4
367
+ BgNVHSMEcTBvgBRMUQ/HpPrAkKOufS5h+xPtEuzyWKFMpEowSDELMAkGA1UEBhMC
368
+ VVMxEzARBgNVBAgTClNvbWUtU3RhdGUxCjAIBgNVBAoTASAxGDAWBgNVBAMTD1Zl
369
+ cnkgU21hbGwgQ2VydIIJAPDLgMilKuayMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN
370
+ AQEFBQADMQAq0CsqEChn4uf6MkXYBwaAAmS3JLmagyliJe5zM3y8dZz6Em2Ugb8o
371
+ 1cCaKaHJHSg=
372
+ -----END CERTIFICATE-----
373
+ CERT
374
+ @openssl_cert = OpenSSL::X509::Certificate.new @pem_cert
375
+ @small_cert = CertificateAuthority::Certificate.from_openssl @openssl_cert
376
+ end
377
+
378
+ it "should reject non-Certificate arguments" do
379
+ lambda { CertificateAuthority::Certificate.from_openssl "a string" }.should raise_error
380
+ end
381
+
382
+ it "should only be missing a private key" do
383
+ @small_cert.should_not be_valid
384
+ @small_cert.key_material.private_key = "data"
385
+ @small_cert.should be_valid
386
+ end
321
387
  end
322
-
323
-
388
+
324
389
  it "should have a distinguished name" do
325
390
  @certificate.distinguished_name.should_not be_nil
326
391
  end
327
-
392
+
328
393
  it "should have a serial number" do
329
394
  @certificate.serial_number.should_not be_nil
330
395
  end
331
-
396
+
332
397
  it "should have a subject" do
333
398
  @certificate.subject.should_not be_nil
334
399
  end
335
-
400
+
336
401
  it "should be able to have a parent entity" do
337
402
  @certificate.respond_to?(:parent).should be_true
338
403
  end
339
-
404
+
340
405
  it "should have key material" do
341
406
  @certificate.key_material.should_not be_nil
342
407
  end
343
-
408
+
344
409
  it "should have a not_before field" do
345
410
  @certificate.not_before.should_not be_nil
346
411
  end
347
-
412
+
348
413
  it "should have a not_after field" do
349
414
  @certificate.not_after.should_not be_nil
350
415
  end
351
-
416
+
352
417
  it "should default to one year validity" do
353
418
  @certificate.not_after.should < Time.now + 65 * 60 * 24 * 365 and
354
419
  @certificate.not_after.should > Time.now + 55 * 60 * 24 * 365
355
420
  end
356
-
421
+
357
422
  it "should be able to have a revoked at time" do
358
423
  @certificate.revoked?.should be_false
359
424
  @certificate.revoked_at = Time.now
360
425
  @certificate.revoked?.should be_true
361
426
  end
362
-
363
- end
427
+
428
+ end