r509 0.8

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.
Files changed (162) hide show
  1. data/README.md +447 -0
  2. data/Rakefile +38 -0
  3. data/bin/r509 +96 -0
  4. data/bin/r509-parse +35 -0
  5. data/doc/R509.html +154 -0
  6. data/doc/R509/Cert.html +3954 -0
  7. data/doc/R509/Cert/Extensions.html +360 -0
  8. data/doc/R509/Cert/Extensions/AuthorityInfoAccess.html +391 -0
  9. data/doc/R509/Cert/Extensions/AuthorityKeyIdentifier.html +148 -0
  10. data/doc/R509/Cert/Extensions/BasicConstraints.html +482 -0
  11. data/doc/R509/Cert/Extensions/CrlDistributionPoints.html +316 -0
  12. data/doc/R509/Cert/Extensions/ExtendedKeyUsage.html +780 -0
  13. data/doc/R509/Cert/Extensions/KeyUsage.html +1230 -0
  14. data/doc/R509/Cert/Extensions/SubjectAlternativeName.html +467 -0
  15. data/doc/R509/Cert/Extensions/SubjectKeyIdentifier.html +216 -0
  16. data/doc/R509/CertificateAuthority.html +126 -0
  17. data/doc/R509/CertificateAuthority/Signer.html +855 -0
  18. data/doc/R509/Config.html +127 -0
  19. data/doc/R509/Config/CaConfig.html +2144 -0
  20. data/doc/R509/Config/CaConfigPool.html +599 -0
  21. data/doc/R509/Config/CaProfile.html +656 -0
  22. data/doc/R509/Config/SubjectItemPolicy.html +578 -0
  23. data/doc/R509/Crl.html +126 -0
  24. data/doc/R509/Crl/Administrator.html +2077 -0
  25. data/doc/R509/Crl/Parser.html +1224 -0
  26. data/doc/R509/Csr.html +2248 -0
  27. data/doc/R509/IOHelpers.html +564 -0
  28. data/doc/R509/MessageDigest.html +396 -0
  29. data/doc/R509/NameSanitizer.html +319 -0
  30. data/doc/R509/Ocsp.html +128 -0
  31. data/doc/R509/Ocsp/Request.html +126 -0
  32. data/doc/R509/Ocsp/Request/Nonce.html +160 -0
  33. data/doc/R509/Ocsp/Response.html +837 -0
  34. data/doc/R509/OidMapper.html +393 -0
  35. data/doc/R509/PrivateKey.html +1647 -0
  36. data/doc/R509/R509Error.html +134 -0
  37. data/doc/R509/Spki.html +1424 -0
  38. data/doc/R509/Subject.html +836 -0
  39. data/doc/R509/Validity.html +160 -0
  40. data/doc/R509/Validity/Checker.html +320 -0
  41. data/doc/R509/Validity/DefaultChecker.html +283 -0
  42. data/doc/R509/Validity/DefaultWriter.html +330 -0
  43. data/doc/R509/Validity/Status.html +561 -0
  44. data/doc/R509/Validity/Writer.html +394 -0
  45. data/doc/_index.html +501 -0
  46. data/doc/class_list.html +53 -0
  47. data/doc/css/common.css +1 -0
  48. data/doc/css/full_list.css +57 -0
  49. data/doc/css/style.css +328 -0
  50. data/doc/file.README.html +534 -0
  51. data/doc/file.r509.html +149 -0
  52. data/doc/file_list.html +58 -0
  53. data/doc/frames.html +28 -0
  54. data/doc/index.html +534 -0
  55. data/doc/js/app.js +208 -0
  56. data/doc/js/full_list.js +173 -0
  57. data/doc/js/jquery.js +4 -0
  58. data/doc/methods_list.html +1932 -0
  59. data/doc/top-level-namespace.html +112 -0
  60. data/lib/r509.rb +22 -0
  61. data/lib/r509/cert.rb +414 -0
  62. data/lib/r509/cert/extensions.rb +309 -0
  63. data/lib/r509/certificateauthority.rb +290 -0
  64. data/lib/r509/config.rb +407 -0
  65. data/lib/r509/crl.rb +379 -0
  66. data/lib/r509/csr.rb +324 -0
  67. data/lib/r509/exceptions.rb +5 -0
  68. data/lib/r509/io_helpers.rb +52 -0
  69. data/lib/r509/messagedigest.rb +49 -0
  70. data/lib/r509/ocsp.rb +85 -0
  71. data/lib/r509/oidmapper.rb +32 -0
  72. data/lib/r509/privatekey.rb +185 -0
  73. data/lib/r509/spki.rb +112 -0
  74. data/lib/r509/subject.rb +133 -0
  75. data/lib/r509/validity.rb +92 -0
  76. data/lib/r509/version.rb +4 -0
  77. data/r509.yaml +73 -0
  78. data/spec/cert/extensions_spec.rb +632 -0
  79. data/spec/cert_spec.rb +321 -0
  80. data/spec/certificate_authority_spec.rb +260 -0
  81. data/spec/config_spec.rb +349 -0
  82. data/spec/crl_spec.rb +215 -0
  83. data/spec/csr_spec.rb +302 -0
  84. data/spec/fixtures.rb +233 -0
  85. data/spec/fixtures/cert1.der +0 -0
  86. data/spec/fixtures/cert1.pem +24 -0
  87. data/spec/fixtures/cert1_public_key_modulus.txt +1 -0
  88. data/spec/fixtures/cert3.p12 +0 -0
  89. data/spec/fixtures/cert3.pem +28 -0
  90. data/spec/fixtures/cert3_key.pem +27 -0
  91. data/spec/fixtures/cert3_key_des3.pem +30 -0
  92. data/spec/fixtures/cert4.pem +14 -0
  93. data/spec/fixtures/cert5.pem +30 -0
  94. data/spec/fixtures/cert6.pem +26 -0
  95. data/spec/fixtures/cert_expired.pem +26 -0
  96. data/spec/fixtures/cert_not_yet_valid.pem +26 -0
  97. data/spec/fixtures/cert_san.pem +27 -0
  98. data/spec/fixtures/cert_san2.pem +22 -0
  99. data/spec/fixtures/config_pool_test_minimal.yaml +15 -0
  100. data/spec/fixtures/config_test.yaml +41 -0
  101. data/spec/fixtures/config_test_engine_key.yaml +7 -0
  102. data/spec/fixtures/config_test_engine_no_key_name.yaml +6 -0
  103. data/spec/fixtures/config_test_minimal.yaml +7 -0
  104. data/spec/fixtures/config_test_password.yaml +7 -0
  105. data/spec/fixtures/config_test_various.yaml +100 -0
  106. data/spec/fixtures/crl_list_file.txt +1 -0
  107. data/spec/fixtures/crl_with_reason.pem +17 -0
  108. data/spec/fixtures/csr1.der +0 -0
  109. data/spec/fixtures/csr1.pem +17 -0
  110. data/spec/fixtures/csr1_key.der +0 -0
  111. data/spec/fixtures/csr1_key.pem +27 -0
  112. data/spec/fixtures/csr1_key_encrypted_des3.pem +30 -0
  113. data/spec/fixtures/csr1_newlines.pem +32 -0
  114. data/spec/fixtures/csr1_no_begin_end.pem +15 -0
  115. data/spec/fixtures/csr1_public_key_modulus.txt +1 -0
  116. data/spec/fixtures/csr2.pem +15 -0
  117. data/spec/fixtures/csr2_key.pem +27 -0
  118. data/spec/fixtures/csr3.pem +16 -0
  119. data/spec/fixtures/csr4.pem +25 -0
  120. data/spec/fixtures/csr_dsa.pem +15 -0
  121. data/spec/fixtures/csr_invalid_signature.pem +13 -0
  122. data/spec/fixtures/dsa_key.pem +20 -0
  123. data/spec/fixtures/key4.pem +27 -0
  124. data/spec/fixtures/key4_encrypted_des3.pem +30 -0
  125. data/spec/fixtures/missing_key_identifier_ca.cer +21 -0
  126. data/spec/fixtures/missing_key_identifier_ca.key +27 -0
  127. data/spec/fixtures/ocsptest.r509.local.pem +27 -0
  128. data/spec/fixtures/ocsptest.r509.local_ocsp_request.der +0 -0
  129. data/spec/fixtures/ocsptest2.r509.local.pem +27 -0
  130. data/spec/fixtures/second_ca.cer +26 -0
  131. data/spec/fixtures/second_ca.key +27 -0
  132. data/spec/fixtures/spkac.der +0 -0
  133. data/spec/fixtures/spkac.txt +1 -0
  134. data/spec/fixtures/spkac_dsa.txt +1 -0
  135. data/spec/fixtures/stca.pem +22 -0
  136. data/spec/fixtures/stca_ocsp_request.der +0 -0
  137. data/spec/fixtures/stca_ocsp_response.der +0 -0
  138. data/spec/fixtures/test1.csr +17 -0
  139. data/spec/fixtures/test_ca.cer +22 -0
  140. data/spec/fixtures/test_ca.key +28 -0
  141. data/spec/fixtures/test_ca.p12 +0 -0
  142. data/spec/fixtures/test_ca_des3.key +30 -0
  143. data/spec/fixtures/test_ca_ocsp.cer +26 -0
  144. data/spec/fixtures/test_ca_ocsp.key +27 -0
  145. data/spec/fixtures/test_ca_ocsp.p12 +0 -0
  146. data/spec/fixtures/test_ca_ocsp_chain.txt +48 -0
  147. data/spec/fixtures/test_ca_ocsp_response.der +0 -0
  148. data/spec/fixtures/test_ca_subroot.cer +26 -0
  149. data/spec/fixtures/test_ca_subroot.key +27 -0
  150. data/spec/fixtures/test_ca_subroot_ocsp.cer +25 -0
  151. data/spec/fixtures/test_ca_subroot_ocsp.key +27 -0
  152. data/spec/fixtures/test_ca_subroot_ocsp_response.der +0 -0
  153. data/spec/fixtures/unknown_oid.csr +17 -0
  154. data/spec/message_digest_spec.rb +89 -0
  155. data/spec/ocsp_spec.rb +111 -0
  156. data/spec/oid_mapper_spec.rb +31 -0
  157. data/spec/privatekey_spec.rb +198 -0
  158. data/spec/spec_helper.rb +14 -0
  159. data/spec/spki_spec.rb +157 -0
  160. data/spec/subject_spec.rb +203 -0
  161. data/spec/validity_spec.rb +98 -0
  162. metadata +257 -0
data/spec/csr_spec.rb ADDED
@@ -0,0 +1,302 @@
1
+ require 'spec_helper'
2
+ require 'stringio'
3
+ require 'r509/csr'
4
+
5
+
6
+ describe R509::Csr do
7
+ before :all do
8
+ @cert = TestFixtures::CERT
9
+ @cert_san = TestFixtures::CERT_SAN
10
+ @csr = TestFixtures::CSR
11
+ @csr_newlines = TestFixtures::CSR_NEWLINES
12
+ @csr_no_begin_end = TestFixtures::CSR_NO_BEGIN_END
13
+ @csr_der = TestFixtures::CSR_DER
14
+ @csr_public_key_modulus = TestFixtures::CSR_PUBLIC_KEY_MODULUS
15
+ @csr_invalid_signature = TestFixtures::CSR_INVALID_SIGNATURE
16
+ @csr2 = TestFixtures::CSR2
17
+ @csr3 = TestFixtures::CSR3
18
+ @csr_der = TestFixtures::CSR_DER
19
+ @csr_dsa = TestFixtures::CSR_DSA
20
+ @csr4_multiple_attrs = TestFixtures::CSR4_MULTIPLE_ATTRS
21
+ @key3 = TestFixtures::KEY3
22
+ @key_csr2 = TestFixtures::KEY_CSR2
23
+ @dsa_key = TestFixtures::DSA_KEY
24
+ @csr_unknown_oid = TestFixtures::CSR_UNKNOWN_OID
25
+ end
26
+
27
+ it "raises an exception when passing non-hash" do
28
+ expect { R509::Csr.new('invalid') }.to raise_error(ArgumentError, 'Must provide a hash of options')
29
+ end
30
+ it "key creation defaults to RSA when no type or key is passed" do
31
+ csr = R509::Csr.new(:subject => [['CN','testing.rsa']], :bit_strength => 1024)
32
+ csr.rsa?.should == true
33
+ csr.dsa?.should == false
34
+ end
35
+ it "returns expected value for to_der" do
36
+ csr = R509::Csr.new(:csr => @csr)
37
+ csr.to_der.should == @csr_der
38
+ end
39
+ it "loads a csr with extraneous newlines" do
40
+ csr = R509::Csr.new(:csr => @csr_newlines)
41
+ csr.to_pem.should match(/-----BEGIN CERTIFICATE REQUEST-----/)
42
+ end
43
+ it "loads a csr with no begin/end lines" do
44
+ csr = R509::Csr.new(:csr => @csr_no_begin_end)
45
+ csr.to_pem.should match(/-----BEGIN CERTIFICATE REQUEST-----/)
46
+ end
47
+ it "returns true from #has_private_key? when private key is present" do
48
+ csr = R509::Csr.new(:bit_strength => 512, :subject => [['CN','private-key-check.com']])
49
+ csr.has_private_key?.should == true
50
+ end
51
+ it "returns false from #has_private_key? when private key is not present" do
52
+ csr = R509::Csr.new(:csr => @csr)
53
+ csr.has_private_key?.should == false
54
+ end
55
+ it "key creation defaults to 2048 when no bit strength or key is passed" do
56
+ csr = R509::Csr.new(:subject => [['CN','testing2048.rsa']])
57
+ csr.bit_strength.should == 2048
58
+ end
59
+ it "creates a CSR when a key is provided" do
60
+ csr = R509::Csr.new(:key => @key3, :subject => [['CN','pregenerated.com']], :bit_strength => 1024)
61
+ csr.to_pem.should match(/CERTIFICATE REQUEST/)
62
+ #validate the CSR matches the key
63
+ csr.req.verify(csr.key.public_key).should == true
64
+ end
65
+ it "loads successfully when an R509::PrivateKey is provided" do
66
+ key = R509::PrivateKey.new(:key => @key3)
67
+ expect { R509::Csr.new(:key => key, :csr => @csr3)}.to_not raise_error
68
+ end
69
+ it "raises an exception when you pass a cert and subject" do
70
+ expect { R509::Csr.new(:cert => @cert, :subject => [['CN','fail.com']]) }.to raise_error(ArgumentError,'Can only provide one of cert, subject, or csr')
71
+ end
72
+ it "raises an exception when you pass a cert and CSR" do
73
+ expect { R509::Csr.new(:cert => @cert, :csr => @csr) }.to raise_error(ArgumentError,'Can only provide one of cert, subject, or csr')
74
+ end
75
+ it "raises an exception when you pass a subject and CSR" do
76
+ expect { R509::Csr.new(:subject => [['CN','error.com']], :csr => @csr) }.to raise_error(ArgumentError,'Can only provide one of cert, subject, or csr')
77
+ end
78
+ it "raises an exception for not providing valid type when key is nil" do
79
+ expect { R509::Csr.new(:subject => [['CN','error.com']], :type => :invalid_symbol) }.to raise_error(ArgumentError,'Must provide :rsa or :dsa as type when key is nil')
80
+ end
81
+ it "raises an exception when you don't provide cert, subject, or CSR" do
82
+ expect { R509::Csr.new(:bit_strength => 1024) }.to raise_error(ArgumentError,'Must provide one of cert, subject, or csr')
83
+ end
84
+ it "raises an exception if you provide a list of domains with an existing CSR" do
85
+ expect { R509::Csr.new(:csr => @csr, :san_names => ['moredomainsiwanttoadd.com']) }.to raise_error(ArgumentError,'You can\'t add domains to an existing CSR')
86
+ end
87
+ it "changes the message_digest to DSS1 when passed a DSA key" do
88
+ csr = R509::Csr.new(:subject => [["CN","dsasigned.com"]], :key => @dsa_key)
89
+ csr.message_digest.name.should == 'dss1'
90
+ csr.signature_algorithm.should == 'dsaWithSHA1'
91
+ #dss1 is actually the same as SHA1
92
+ #Yes this is confusing
93
+ #see http://www.ruby-doc.org/stdlib-1.9.3/libdoc/openssl/rdoc/OpenSSL/PKey/DSA.html
94
+ end
95
+ it "changes the message_digest to DSS1 when creating a DSA key" do
96
+ csr = R509::Csr.new(:subject => [["CN","dsasigned.com"]], :type => :dsa, :bit_strength => 512)
97
+ csr.message_digest.name.should == 'dss1'
98
+ csr.signature_algorithm.should == 'dsaWithSHA1'
99
+ #dss1 is actually the same as SHA1
100
+ #Yes this is confusing
101
+ #see http://www.ruby-doc.org/stdlib-1.9.3/libdoc/openssl/rdoc/OpenSSL/PKey/DSA.html
102
+ end
103
+ it "signs a CSR properly when passed a DSA key" do
104
+ csr = R509::Csr.new(:subject => [["CN","dsasigned.com"]], :key => @dsa_key)
105
+ csr.verify_signature.should == true
106
+ end
107
+ it "signs a CSR properly when creating a DSA key" do
108
+ csr = R509::Csr.new(:subject => [["CN","dsasigned.com"]], :type => :dsa, :bit_strength => 512)
109
+ csr.verify_signature.should == true
110
+ end
111
+ it "writes to pem" do
112
+ csr = R509::Csr.new(:csr => @csr)
113
+ sio = StringIO.new
114
+ sio.set_encoding("BINARY") if sio.respond_to?(:set_encoding)
115
+ csr.write_pem(sio)
116
+ sio.string.should == @csr
117
+ end
118
+ it "writes to der" do
119
+ sio = StringIO.new
120
+ sio.set_encoding("BINARY") if sio.respond_to?(:set_encoding)
121
+ csr = R509::Csr.new(:csr => @csr)
122
+ csr.write_der(sio)
123
+ sio.string.should == @csr_der
124
+ end
125
+ it "duplicate SAN names should be removed" do
126
+ csr = R509::Csr.new( :bit_strength => 512, :subject => [['CN','test2345.com']], :san_names => ["test2.local","test.local","test.local"] )
127
+ csr.san_names.should == ["test2.local", "test.local"]
128
+ end
129
+ it "creates a valid hash object with to_hash" do
130
+ csr = R509::Csr.new(:csr => @csr)
131
+ csr.to_hash[:subject].kind_of?(R509::Subject).should == true
132
+ csr.to_hash[:subject].to_s.should == '/CN=test.local/O=Testing CSR'
133
+ csr.to_hash[:san_names].should == ["test.local", "additionaldomains.com", "saniam.com"]
134
+ end
135
+ it "san_names is an empty array when there are no SAN names" do
136
+ csr = R509::Csr.new( :subject => [['CN','langui.sh'],['emailAddress','ca@langui.sh']], :bit_strength => 512)
137
+ csr.san_names.should == []
138
+ end
139
+ context "when initialized" do
140
+ it "raises exception when providing invalid csr" do
141
+ expect { R509::Csr.new({:csr => 'invalid csr'}) }.to raise_error(OpenSSL::X509::RequestError)
142
+ end
143
+ it "raises exception when providing invalid key" do
144
+ expect { R509::Csr.new({:csr => @csr, :key => 'invalid key'}) }.to raise_error(R509::R509Error,"Failed to load private key. Invalid key or incorrect password.")
145
+ end
146
+ end
147
+ context "when passing a cert to generate" do
148
+ it "returns a valid pem" do
149
+ csr = R509::Csr.new( :bit_strength => 1024, :cert => @cert )
150
+ csr.to_pem.should match(/CERTIFICATE REQUEST/)
151
+ end
152
+ it "has a public key length of 2048 by default" do
153
+ csr = R509::Csr.new( :cert => @cert )
154
+ csr.bit_strength.should == 2048
155
+ end
156
+ it "generates a matching CSR" do
157
+ csr = R509::Csr.new( :bit_strength => 1024, :cert => @cert )
158
+ csr.subject.to_s.should == '/C=US/ST=Illinois/L=Chicago/O=Paul Kehrer/CN=langui.sh'
159
+ end
160
+ it "SAN domains from the cert should be encoded in the request" do
161
+ csr = R509::Csr.new( :bit_strength => 1024, :cert => @cert_san )
162
+ csr.san_names.should == ["langui.sh"]
163
+ end
164
+ it "duplicate SAN names should be removed" do
165
+ csr = R509::Csr.new( :cert => @cert, :san_names => ["test2.local","test.local","test.local"] )
166
+ csr.san_names.should == ["test2.local", "test.local"]
167
+ end
168
+ it "SAN names added in addition to those present in the cert should be merged" do
169
+ csr = R509::Csr.new( :cert => @cert_san, :san_names => ["test2.local","test.local","test.local"] )
170
+ csr.san_names.should == ["langui.sh","test2.local", "test.local"]
171
+ end
172
+ end
173
+ context "when passing a subject array" do
174
+ it "generates a matching CSR" do
175
+ csr = R509::Csr.new( :subject=> [['CN','langui.sh'],['ST','Illinois'],['L','Chicago'],['C','US'],['emailAddress','ca@langui.sh']], :bit_strength => 1024)
176
+ csr.subject.to_s.should == '/CN=langui.sh/ST=Illinois/L=Chicago/C=US/emailAddress=ca@langui.sh'
177
+ end
178
+ it "adds SAN domains to a generated CSR" do
179
+ csr = R509::Csr.new( :subject => [['CN','langui.sh'],['emailAddress','ca@langui.sh']], :bit_strength => 1024, :san_names => ['domain2.com','domain3.com'])
180
+ csr.subject.to_s.should == '/CN=langui.sh/emailAddress=ca@langui.sh'
181
+ csr.san_names.should == ["domain2.com", "domain3.com"]
182
+ end
183
+ it "generates a matching csr when supplying raw oids" do
184
+ csr = R509::Csr.new( :subject => [['2.5.4.3','common name'],['2.5.4.15','business category'],['2.5.4.7','locality'],['1.3.6.1.4.1.311.60.2.1.3','jurisdiction oid openssl typically does not know']], :bit_strength => 1024 )
185
+ csr.subject.to_s.should == "/CN=common name/businessCategory=business category/L=locality/jurisdictionOfIncorporationCountryName=jurisdiction oid openssl typically does not know"
186
+ end
187
+ end
188
+ context "when supplying an existing csr" do
189
+ it "populates the bit_strength" do
190
+ csr = R509::Csr.new({ :csr => @csr })
191
+ csr.bit_strength.should == 2048
192
+ end
193
+ it "populates the subject" do
194
+ csr = R509::Csr.new({ :csr => @csr })
195
+ csr.subject.to_s.should == '/CN=test.local/O=Testing CSR'
196
+ end
197
+ it "parses the san names" do
198
+ csr = R509::Csr.new({ :csr => @csr })
199
+ csr.san_names.should == ["test.local", "additionaldomains.com", "saniam.com"]
200
+ end
201
+ it "parses san names when there are multiple non-SAN attributes" do
202
+ csr = R509::Csr.new({ :csr => @csr4_multiple_attrs })
203
+ csr.san_names.should == ["adomain.com", "anotherdomain.com", "justanexample.com"]
204
+ end
205
+ it "fetches a subject component" do
206
+ csr = R509::Csr.new({ :csr => @csr })
207
+ csr.subject_component('CN').to_s.should == 'test.local'
208
+ end
209
+ it "returns nil when subject component not found" do
210
+ csr = R509::Csr.new({ :csr => @csr })
211
+ csr.subject_component('OU').should be_nil
212
+ end
213
+ it "returns the signature algorithm" do
214
+ csr = R509::Csr.new({ :csr => @csr })
215
+ csr.signature_algorithm.should == 'sha1WithRSAEncryption'
216
+ end
217
+ it "returns RSA key algorithm for RSA CSR" do
218
+ csr = R509::Csr.new({ :csr => @csr })
219
+ csr.key_algorithm.should == 'RSA'
220
+ end
221
+ it "returns DSA key algorithm for DSA CSR" do
222
+ csr = R509::Csr.new({ :csr => @csr_dsa })
223
+ csr.key_algorithm.should == 'DSA'
224
+ end
225
+ it "returns the public key" do
226
+ #this is more complex than it should have to be. diff versions of openssl
227
+ #return subtly diff PEM encodings so we need to look at the modulus (n)
228
+ #but beware, because n is not present for DSA certificates
229
+ csr = R509::Csr.new({ :csr => @csr })
230
+ csr.public_key.n.to_i.should == @csr_public_key_modulus.to_i
231
+ end
232
+ it "returns true with valid signature" do
233
+ csr = R509::Csr.new({ :csr => @csr })
234
+ csr.verify_signature.should == true
235
+ end
236
+ it "returns false on invalid signature" do
237
+ csr = R509::Csr.new({ :csr => @csr_invalid_signature })
238
+ csr.verify_signature.should == false
239
+ end
240
+ it "works when the CSR has unknown OIDs" do
241
+ csr = R509::Csr.new(:csr => @csr_unknown_oid)
242
+ csr.subject["1.2.3.4.5.6.7.8.9.8.7.6.5.4.3.2.1.0.0"].should == "random oid!"
243
+ csr.subject["1.3.3.543.567.32.43.335.1.1.1"].should == "another random oid!"
244
+ end
245
+ end
246
+ context "when supplying a key with csr" do
247
+ it "raises exception on non-matching key" do
248
+ expect { R509::Csr.new({:csr => @csr, :key => @key_csr2}) }.to raise_error(R509::R509Error, 'Key does not match request.')
249
+ end
250
+ it "accepts matching key" do
251
+ csr = R509::Csr.new({:csr => @csr2, :key => @key_csr2})
252
+ csr.to_pem.should == @csr2
253
+ end
254
+ end
255
+ context "when setting alternate signature algorithms" do
256
+ it "sets sha1 if you pass an invalid message digest" do
257
+ csr = R509::Csr.new(:message_digest => 'sha88', :bit_strength => 512, :subject => [['CN','langui.sh']])
258
+ csr.message_digest.name.should == 'sha1'
259
+ csr.signature_algorithm.should == "sha1WithRSAEncryption"
260
+ end
261
+ it "sets sha256 properly" do
262
+ csr = R509::Csr.new(:message_digest => 'sha256', :bit_strength => 512, :subject => [['CN','sha256-signature-alg.test']])
263
+ csr.message_digest.name.should == 'sha256'
264
+ csr.signature_algorithm.should == "sha256WithRSAEncryption"
265
+ end
266
+ it "sets sha512 properly" do
267
+ csr = R509::Csr.new(:message_digest => 'sha512', :bit_strength => 1024, :subject => [['CN','sha512-signature-alg.test']])
268
+ csr.message_digest.name.should == 'sha512'
269
+ csr.signature_algorithm.should == "sha512WithRSAEncryption"
270
+ end
271
+ it "sets md5 properly" do
272
+ csr = R509::Csr.new(:message_digest => 'md5', :bit_strength => 512, :subject => [['CN','md5-signature-alg.test']])
273
+ csr.message_digest.name.should == 'md5'
274
+ csr.signature_algorithm.should == "md5WithRSAEncryption"
275
+ end
276
+ end
277
+ it "checks rsa?" do
278
+ csr = R509::Csr.new({:csr => @csr})
279
+ csr.rsa?.should == true
280
+ csr.dsa?.should == false
281
+ end
282
+ it "gets RSA bit strength" do
283
+ csr = R509::Csr.new({:csr => @csr})
284
+ csr.bit_strength.should == 2048
285
+ end
286
+ it "checks dsa?" do
287
+ csr = R509::Csr.new({:csr => @csr_dsa})
288
+ csr.rsa?.should == false
289
+ csr.dsa?.should == true
290
+ end
291
+ it "gets DSA bit strength" do
292
+ csr = R509::Csr.new({:csr => @csr_dsa})
293
+ csr.bit_strength.should == 1024
294
+ end
295
+
296
+ it "loads a csr with load_from_file" do
297
+ path = File.dirname(__FILE__) + '/fixtures/csr1.pem'
298
+ csr = R509::Csr.load_from_file path
299
+ csr.message_digest.name.should == 'sha1'
300
+ end
301
+
302
+ end
data/spec/fixtures.rb ADDED
@@ -0,0 +1,233 @@
1
+ require 'spec_helper'
2
+ require 'pathname'
3
+ require 'r509/io_helpers'
4
+
5
+ module TestFixtures
6
+ extend R509::IOHelpers
7
+
8
+ FIXTURES_PATH = Pathname.new(__FILE__).dirname + "fixtures"
9
+
10
+ def self.read_fixture(filename)
11
+ read_data((FIXTURES_PATH + filename).to_s)
12
+ end
13
+
14
+ #Trustwave cert for langui.sh
15
+ CERT = read_fixture('cert1.pem')
16
+
17
+ #Trustwave root cert
18
+ STCA_CERT = read_fixture('stca.pem')
19
+
20
+ CERT_PUBLIC_KEY_MODULUS = read_fixture('cert1_public_key_modulus.txt')
21
+
22
+ # cert without key usage
23
+ CERT4 = read_fixture('cert4.pem')
24
+
25
+ # cert with multiple EKU
26
+ CERT5 = read_fixture('cert5.pem')
27
+
28
+ # cert with DSA public key
29
+ CERT6 = read_fixture('cert6.pem')
30
+
31
+ CERT_EXPIRED = read_fixture("cert_expired.pem")
32
+
33
+ CERT_NOT_YET_VALID = read_fixture("cert_not_yet_valid.pem")
34
+
35
+ DSA_KEY = read_fixture('dsa_key.pem')
36
+
37
+ # this CSR has unknown OIDs, which we should successfully parse out into Subject
38
+ CSR_UNKNOWN_OID = read_fixture('unknown_oid.csr')
39
+
40
+
41
+ #san cert from self-signed CA for langui.sh
42
+ CERT_SAN = read_fixture('cert_san.pem')
43
+
44
+ #Another san cert for langui.sh, but differentiating between the CN and
45
+ # SANs.
46
+ CERT_SAN2 = read_fixture('cert_san2.pem')
47
+
48
+ CERT_DER = read_fixture('cert1.der')
49
+
50
+ SPKI = read_fixture('spkac.txt')
51
+
52
+ SPKI_DER = read_fixture('spkac.der')
53
+
54
+ SPKI_DSA = read_fixture('spkac_dsa.txt')
55
+
56
+ CSR = read_fixture('csr1.pem')
57
+
58
+ CSR_PUBLIC_KEY_MODULUS = read_fixture('csr1_public_key_modulus.txt')
59
+
60
+ CSR_INVALID_SIGNATURE = read_fixture('csr_invalid_signature.pem')
61
+
62
+ CSR_DER = read_fixture('csr1.der')
63
+
64
+ CSR_NEWLINES = read_fixture('csr1_newlines.pem')
65
+
66
+ CSR_NO_BEGIN_END = read_fixture('csr1_no_begin_end.pem')
67
+
68
+ CSR_DSA = read_fixture('csr_dsa.pem')
69
+
70
+ KEY_CSR = read_fixture('csr1_key.pem')
71
+
72
+ KEY_CSR_DER = read_fixture('csr1_key.der')
73
+
74
+ KEY_CSR_ENCRYPTED = read_fixture('csr1_key_encrypted_des3.pem')
75
+
76
+ CSR2 = read_fixture('csr2.pem')
77
+
78
+ KEY_CSR2 = read_fixture('csr2_key.pem')
79
+
80
+ CSR3 = read_fixture('csr3.pem')
81
+
82
+ CERT3 = read_fixture('cert3.pem')
83
+
84
+ KEY3 = read_fixture('cert3_key.pem')
85
+
86
+ KEY3_ENCRYPTED = read_fixture('cert3_key_des3.pem')
87
+
88
+ CERT3_P12 = read_fixture('cert3.p12')
89
+
90
+ CSR4_MULTIPLE_ATTRS = read_fixture('csr4.pem')
91
+
92
+ KEY4_ENCRYPTED_DES3 = read_fixture('key4_encrypted_des3.pem')
93
+
94
+ KEY4 = read_fixture('key4.pem')
95
+
96
+ TEST_CA_CERT = read_fixture('test_ca.cer')
97
+ TEST_CA_KEY = read_fixture('test_ca.key')
98
+
99
+ TEST_CA_OCSP_CERT = read_fixture('test_ca_ocsp.cer')
100
+ TEST_CA_OCSP_KEY = read_fixture('test_ca_ocsp.key')
101
+
102
+ TEST_CA_SUBROOT_CERT = read_fixture('test_ca_subroot.cer')
103
+ TEST_CA_SUBROOT_KEY = read_fixture('test_ca_subroot.key')
104
+
105
+ #this chain contains 2 certs. root and OCSP delegate
106
+ #in a prod environment you'd really only need the delegate
107
+ #since the root would be present in the root store of the
108
+ #client, but I wanted to test > 1
109
+ TEST_CA_OCSP_CHAIN = read_fixture('test_ca_ocsp_chain.txt')
110
+
111
+ TEST_CA_OCSP_RESPONSE = read_fixture('test_ca_ocsp_response.der')
112
+
113
+ TEST_CA_SUBROOT_OCSP_RESPONSE = read_fixture('test_ca_subroot_ocsp_response.der')
114
+
115
+ SECOND_CA_CERT = read_fixture('second_ca.cer')
116
+ SECOND_CA_KEY = read_fixture('second_ca.key')
117
+
118
+ OCSP_TEST_CERT = read_fixture('ocsptest.r509.local.pem')
119
+ OCSP_TEST_CERT2 = read_fixture('ocsptest2.r509.local.pem')
120
+
121
+ STCA_OCSP_REQUEST = read_fixture('stca_ocsp_request.der')
122
+ STCA_OCSP_RESPONSE = read_fixture('stca_ocsp_response.der')
123
+
124
+ CRL_LIST_FILE = (FIXTURES_PATH+'crl_list_file.txt').to_s
125
+
126
+ CRL_REASON = read_fixture("crl_with_reason.pem")
127
+
128
+ def self.test_ca_cert
129
+ R509::Cert.new(:cert => TEST_CA_CERT, :key => TEST_CA_KEY)
130
+ end
131
+
132
+ def self.test_ca_subroot_cert
133
+ R509::Cert.new(:cert => TEST_CA_SUBROOT_CERT, :key => TEST_CA_SUBROOT_KEY)
134
+ end
135
+
136
+ def self.test_ca_server_profile
137
+ R509::Config::CaProfile.new(
138
+ :basic_constraints => "CA:FALSE",
139
+ :key_usage => ["digitalSignature","keyEncipherment"],
140
+ :extended_key_usage => ["serverAuth"],
141
+ :certificate_policies => [
142
+ [
143
+ "policyIdentifier=2.16.840.1.12345.1.2.3.4.1",
144
+ "CPS.1=http://example.com/cps"
145
+ ]
146
+ ]
147
+ )
148
+
149
+ end
150
+
151
+ def self.test_ca_server_profile_with_subject_item_policy
152
+ subject_item_policy = R509::Config::SubjectItemPolicy.new(
153
+ "CN" => "required",
154
+ "O" => "optional",
155
+ "ST" => "required",
156
+ "C" => "required",
157
+ "OU" => "optional"
158
+ )
159
+ R509::Config::CaProfile.new(
160
+ :basic_constraints => "CA:FALSE",
161
+ :key_usage => ["digitalSignature","keyEncipherment"],
162
+ :extended_key_usage => ["serverAuth"],
163
+ :certificate_policies => [
164
+ [
165
+ "policyIdentifier=2.16.840.1.12345.1.2.3.4.1",
166
+ "CPS.1=http://example.com/cps"
167
+ ]
168
+ ],
169
+ :subject_item_policy => subject_item_policy
170
+ )
171
+ end
172
+
173
+ def self.test_ca_subroot_profile
174
+ R509::Config::CaProfile.new(
175
+ :basic_constraints => "CA:TRUE,pathlen:0",
176
+ :key_usage => ["keyCertSign","cRLSign"],
177
+ :extended_key_usage => [],
178
+ :certificate_policies => nil)
179
+ end
180
+
181
+ def self.test_ca_ocspsigner_profile
182
+ R509::Config::CaProfile.new(
183
+ :basic_constraints => "CA:FALSE",
184
+ :key_usage => ["digitalSignature"],
185
+ :extended_key_usage => ["OCSPSigning"],
186
+ :certificate_policies => nil)
187
+ end
188
+
189
+ # @return [R509::Config::CaConfig]
190
+ def self.test_ca_config
191
+ crl_list_sio = StringIO.new
192
+ crl_list_sio.set_encoding("BINARY") if crl_list_sio.respond_to?(:set_encoding)
193
+ crl_number_sio = StringIO.new
194
+ crl_number_sio.set_encoding("BINARY") if crl_number_sio.respond_to?(:set_encoding)
195
+
196
+ opts = {
197
+ :ca_cert => test_ca_cert(),
198
+ :cdp_location => 'URI:http://crl.domain.com/test_ca.crl',
199
+ :ocsp_location => 'URI:http://ocsp.domain.com',
200
+ :ocsp_start_skew_seconds => 3600,
201
+ :ocsp_validity_hours => 48,
202
+ :crl_list_file => crl_list_sio,
203
+ :crl_number_file => crl_number_sio
204
+ }
205
+ ret = R509::Config::CaConfig.new(opts)
206
+
207
+ ret.set_profile("server", self.test_ca_server_profile)
208
+ ret.set_profile("subroot", self.test_ca_subroot_profile)
209
+ ret.set_profile("ocspsigner", self.test_ca_ocspsigner_profile)
210
+ ret.set_profile("server_with_subject_item_policy", self.test_ca_server_profile_with_subject_item_policy)
211
+
212
+ ret
213
+ end
214
+
215
+ # @return [R509::Config::CaConfig]
216
+ def self.test_ca_no_profile_config
217
+ crl_list_sio = StringIO.new
218
+ crl_list_sio.set_encoding("BINARY") if crl_list_sio.respond_to?(:set_encoding)
219
+ crl_number_sio = StringIO.new
220
+ crl_number_sio.set_encoding("BINARY") if crl_number_sio.respond_to?(:set_encoding)
221
+
222
+ opts = {
223
+ :ca_cert => test_ca_cert(),
224
+ :cdp_location => 'URI:http://crl.domain.com/test_ca.crl',
225
+ :ocsp_location => 'URI:http://ocsp.domain.com',
226
+ :ocsp_start_skew_seconds => 3600,
227
+ :ocsp_validity_hours => 48,
228
+ :crl_list_file => crl_list_sio,
229
+ :crl_number_file => crl_number_sio
230
+ }
231
+ R509::Config::CaConfig.new(opts)
232
+ end
233
+ end