certificate_authority 0.1.3 → 0.1.4

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