r509 0.8

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