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
@@ -0,0 +1,17 @@
1
+ -----BEGIN CERTIFICATE REQUEST-----
2
+ MIICrTCCAZUCAQAwaDEjMCEGEioDBAUGBwgJCAcGBQQDAgEAAAwLcmFuZG9tIG9p
3
+ ZCExJjAkBg0rA4QfhDcgK4JPAQEBDBNhbm90aGVyIHJhbmRvbSBvaWQhMRkwFwYD
4
+ VQQDDBBub3JtYWxkb21haW4uY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
5
+ CgKCAQEA1Ku9+ENnhWSN4OxMz7DSLvoOXLzF1l4nhrjLJSN3EKp/4yG922c8weXa
6
+ 1CJzsMnlJkl+G2SLdkBKSI936F0nsvz09wJT3qP79H2BZYnxpsmCFKWo1lyK7fqa
7
+ RbaTSbvyLPZfl78lQYdK+4na8sSDSVXYOsS9uabFf0/5oeCn+nBHl8VwV0FV+vSx
8
+ PrqtKMe5JENp+gfPdJsvQJF4c09TNx7mTOE14MJ/C93V8EoVku6EQmkOxZ6yUqSI
9
+ 5DDVzj7awUe+J02HiqBlLEhNpJCl2EB65tZ6vQ8e+12zKcjdqF0Vc27v2h1790oL
10
+ BmvB0wA81FfrSy7O4onqI+ZKq2D5fQIDAQABoAAwDQYJKoZIhvcNAQEFBQADggEB
11
+ ALyylQQ+N0Hs7SPc6UwQLifyF4yGJeY3wSt5970pVKlGnMdd3S7TK1C8vfHyrdD9
12
+ MSnphxAV/gZvg/XjNtGloRG8niuQZwd0ij+x6H4hMHyyVvT2LrAAyF+yhA/SPCWM
13
+ h706CFgVlzlXmYtX8E1EajHZhWuQ8Jzsi2FlsqysEXn/dqLTCjEZHm9Zb6uYNeEN
14
+ MGr25IzVECe9SNAM86/KWj6rUwfgpoBKWMFBYYMm5vj+4ILq8apACzH8kK6Fn79y
15
+ ENMiGNMHxTTkWar5zhWpvFMXTuzR0o/EfyTfgq+6z25N0yTH+96X9RTILM+j1dA1
16
+ jAlJ5/nUDrNh1IvwpgshWoo=
17
+ -----END CERTIFICATE REQUEST-----
@@ -0,0 +1,89 @@
1
+ require 'spec_helper'
2
+ require 'r509/messagedigest'
3
+ require 'openssl'
4
+
5
+ describe R509::MessageDigest do
6
+ it "translates sha1 name -> digest" do
7
+ md = R509::MessageDigest.new("sha1")
8
+ md.name.should == "sha1"
9
+ md.digest.kind_of?(OpenSSL::Digest::SHA1).should == true
10
+ end
11
+ it "translates SHA1 name -> digest" do
12
+ md = R509::MessageDigest.new("SHA1")
13
+ md.name.should == "sha1"
14
+ md.digest.kind_of?(OpenSSL::Digest::SHA1).should == true
15
+ end
16
+ it "translates sha256 name -> digest" do
17
+ md = R509::MessageDigest.new("sha256")
18
+ md.name.should == "sha256"
19
+ md.digest.kind_of?(OpenSSL::Digest::SHA256).should == true
20
+ end
21
+ it "translates SHA256 name -> digest" do
22
+ md = R509::MessageDigest.new("SHA256")
23
+ md.name.should == "sha256"
24
+ md.digest.kind_of?(OpenSSL::Digest::SHA256).should == true
25
+ end
26
+ it "translates sha512 name -> digest" do
27
+ md = R509::MessageDigest.new("sha512")
28
+ md.name.should == "sha512"
29
+ md.digest.kind_of?(OpenSSL::Digest::SHA512).should == true
30
+ end
31
+ it "translates SHA512 name -> digest" do
32
+ md = R509::MessageDigest.new("SHA512")
33
+ md.name.should == "sha512"
34
+ md.digest.kind_of?(OpenSSL::Digest::SHA512).should == true
35
+ end
36
+ it "translates md5 name -> digest" do
37
+ md = R509::MessageDigest.new("md5")
38
+ md.name.should == "md5"
39
+ md.digest.kind_of?(OpenSSL::Digest::MD5).should == true
40
+ end
41
+ it "translates MD5 name -> digest" do
42
+ md = R509::MessageDigest.new("MD5")
43
+ md.name.should == "md5"
44
+ md.digest.kind_of?(OpenSSL::Digest::MD5).should == true
45
+ end
46
+ it "translates dss1 name -> digest" do
47
+ md = R509::MessageDigest.new("dss1")
48
+ md.name.should == "dss1"
49
+ md.digest.kind_of?(OpenSSL::Digest::DSS1).should == true
50
+ end
51
+ it "translates DSS1 name -> digest" do
52
+ md = R509::MessageDigest.new("DSS1")
53
+ md.name.should == "dss1"
54
+ md.digest.kind_of?(OpenSSL::Digest::DSS1).should == true
55
+ end
56
+ it "translates unknown name -> digest" do
57
+ md = R509::MessageDigest.new("unknown")
58
+ md.name.should == "sha1"
59
+ md.digest.kind_of?(OpenSSL::Digest::SHA1).should == true
60
+ end
61
+ it "translates sha1 digest -> name" do
62
+ md = R509::MessageDigest.new(OpenSSL::Digest::SHA1.new)
63
+ md.name.should == "sha1"
64
+ md.digest.kind_of?(OpenSSL::Digest::SHA1).should == true
65
+ end
66
+ it "translates sha256 digest -> name" do
67
+ md = R509::MessageDigest.new(OpenSSL::Digest::SHA256.new)
68
+ md.name.should == "sha256"
69
+ md.digest.kind_of?(OpenSSL::Digest::SHA256).should == true
70
+ end
71
+ it "translates sha512 digest -> name" do
72
+ md = R509::MessageDigest.new(OpenSSL::Digest::SHA512.new)
73
+ md.name.should == "sha512"
74
+ md.digest.kind_of?(OpenSSL::Digest::SHA512).should == true
75
+ end
76
+ it "translates md5 digest -> name" do
77
+ md = R509::MessageDigest.new(OpenSSL::Digest::MD5.new)
78
+ md.name.should == "md5"
79
+ md.digest.kind_of?(OpenSSL::Digest::MD5).should == true
80
+ end
81
+ it "translates dss1 digest -> name" do
82
+ md = R509::MessageDigest.new(OpenSSL::Digest::DSS1.new)
83
+ md.name.should == "dss1"
84
+ md.digest.kind_of?(OpenSSL::Digest::DSS1).should == true
85
+ end
86
+ it "exception on unknown digest -> name" do
87
+ expect{ R509::MessageDigest.new(12345) }.to raise_error(ArgumentError)
88
+ end
89
+ end
data/spec/ocsp_spec.rb ADDED
@@ -0,0 +1,111 @@
1
+ require 'spec_helper'
2
+ require 'r509/ocsp'
3
+ require 'openssl'
4
+
5
+ describe R509::Ocsp::Response do
6
+ before :all do
7
+ @ocsp_test_cert = TestFixtures::OCSP_TEST_CERT
8
+ @test_ca_config = TestFixtures.test_ca_config
9
+ @test_ca_ocsp_response = TestFixtures::TEST_CA_OCSP_RESPONSE
10
+ @test_ca_subroot_ocsp_response = TestFixtures::TEST_CA_SUBROOT_OCSP_RESPONSE
11
+ @ocsp_response_der = TestFixtures::STCA_OCSP_RESPONSE
12
+ @stca_cert = TestFixtures::STCA_CERT
13
+ end
14
+ it "raises an exception if you try to pass the wrong type to the constructor" do
15
+ expect { R509::Ocsp::Response.new(@ocsp_response_der) }.to raise_error(R509::R509Error, 'You must pass an OpenSSL::OCSP::Response object to the constructor. See R509::Ocsp::Response.parse if you are trying to parse')
16
+ end
17
+ it "raises an exception if you pass nil to #parse" do
18
+ expect { R509::Ocsp::Response.parse(nil) }.to raise_error(R509::R509Error, 'You must pass a DER encoded OCSP response to this method')
19
+ end
20
+ it "parses a response der and returns the right object on #parse" do
21
+ ocsp_response = R509::Ocsp::Response.parse(@ocsp_response_der)
22
+ ocsp_response.kind_of?(R509::Ocsp::Response).should == true
23
+ ocsp_response.status.should == OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL
24
+ end
25
+ it "returns data on to_der" do
26
+ ocsp_response = R509::Ocsp::Response.parse(@ocsp_response_der)
27
+ ocsp_response.to_der.should_not == nil
28
+ end
29
+ it "returns a BasicResponse object on #basic" do
30
+ ocsp_response = R509::Ocsp::Response.parse(@ocsp_response_der)
31
+ ocsp_response.basic.kind_of?(OpenSSL::OCSP::BasicResponse).should == true
32
+ end
33
+ it "returns true if response verifies (in validity period, chain builds to trusted root that's provided)" do
34
+ ocsp_response = R509::Ocsp::Response.parse(@test_ca_ocsp_response)
35
+ ocsp_response.verify(TestFixtures.test_ca_config.ca_cert.cert).should == true
36
+ end
37
+ it "verify supports an single certificate and uses it to validate" do
38
+ ocsp_response = R509::Ocsp::Response.parse(@test_ca_ocsp_response)
39
+ ocsp_response.verify(TestFixtures.test_ca_config.ca_cert.cert).should == true
40
+ end
41
+ it "verify supports an array of certificates and uses all of them to validate a chain" do
42
+ ocsp_response = R509::Ocsp::Response.parse(@test_ca_subroot_ocsp_response)
43
+ ocsp_response.verify([TestFixtures.test_ca_config.ca_cert.cert,TestFixtures.test_ca_subroot_cert.cert]).should == true
44
+ end
45
+ it "verify returns false if you don't give it enough certs to build a chain to a trusted root" do
46
+ ocsp_response = R509::Ocsp::Response.parse(@test_ca_subroot_ocsp_response)
47
+ ocsp_response.verify([TestFixtures.test_ca_config.ca_cert.cert]).should == false
48
+ end
49
+ it "returns false if response does not verify" do
50
+ #expired response
51
+ ocsp_response = R509::Ocsp::Response.parse(@ocsp_response_der)
52
+ ocsp_response.verify(OpenSSL::X509::Certificate.new(@stca_cert)).should == false
53
+ end
54
+ it "nonce is present and equal" do
55
+ ocsp_request = OpenSSL::OCSP::Request.new
56
+ ocsp_request.add_nonce
57
+ basic_response = OpenSSL::OCSP::BasicResponse.new
58
+ basic_response.copy_nonce(ocsp_request)
59
+ response_double = double("ocsp_response")
60
+ response_double.should_receive(:kind_of?).and_return('OpenSSL::OCSP::Response')
61
+ response_double.should_receive(:basic).and_return(basic_response)
62
+ ocsp_response = R509::Ocsp::Response.new(response_double)
63
+ ocsp_response.check_nonce(ocsp_request).should == R509::Ocsp::Request::Nonce::PRESENT_AND_EQUAL
64
+ end
65
+ it "no nonce" do
66
+ ocsp_request = OpenSSL::OCSP::Request.new
67
+ basic_response = OpenSSL::OCSP::BasicResponse.new
68
+ basic_response.copy_nonce(ocsp_request)
69
+ response_double = double("ocsp_response")
70
+ response_double.should_receive(:kind_of?).and_return('OpenSSL::OCSP::Response')
71
+ response_double.should_receive(:basic).and_return(basic_response)
72
+ ocsp_response = R509::Ocsp::Response.new(response_double)
73
+ ocsp_response.check_nonce(ocsp_request).should == R509::Ocsp::Request::Nonce::BOTH_ABSENT
74
+ end
75
+ it "has a nonce in the response only" do
76
+ ocsp_request = OpenSSL::OCSP::Request.new
77
+ nonce_request = OpenSSL::OCSP::Request.new
78
+ nonce_request.add_nonce
79
+ basic_response = OpenSSL::OCSP::BasicResponse.new
80
+ basic_response.copy_nonce(nonce_request)
81
+ response_double = double("ocsp_response")
82
+ response_double.should_receive(:kind_of?).and_return('OpenSSL::OCSP::Response')
83
+ response_double.should_receive(:basic).and_return(basic_response)
84
+ ocsp_response = R509::Ocsp::Response.new(response_double)
85
+ ocsp_response.check_nonce(ocsp_request).should == R509::Ocsp::Request::Nonce::RESPONSE_ONLY
86
+ end
87
+ it "nonce in request and response is not equal" do
88
+ ocsp_request = OpenSSL::OCSP::Request.new
89
+ ocsp_request.add_nonce
90
+ second_request = OpenSSL::OCSP::Request.new
91
+ second_request.add_nonce
92
+ basic_response = OpenSSL::OCSP::BasicResponse.new
93
+ basic_response.copy_nonce(ocsp_request)
94
+ response_double = double("ocsp_response")
95
+ response_double.should_receive(:kind_of?).and_return('OpenSSL::OCSP::Response')
96
+ response_double.should_receive(:basic).and_return(basic_response)
97
+ ocsp_response = R509::Ocsp::Response.new(response_double)
98
+ ocsp_response.check_nonce(second_request).should == R509::Ocsp::Request::Nonce::NOT_EQUAL
99
+ end
100
+ it "nonce in request only" do
101
+ ocsp_request = OpenSSL::OCSP::Request.new
102
+ ocsp_request.add_nonce
103
+ basic_response = OpenSSL::OCSP::BasicResponse.new
104
+ response_double = double("ocsp_response")
105
+ response_double.should_receive(:kind_of?).and_return('OpenSSL::OCSP::Response')
106
+ response_double.should_receive(:basic).and_return(basic_response)
107
+ ocsp_response = R509::Ocsp::Response.new(response_double)
108
+ ocsp_response.check_nonce(ocsp_request).should == R509::Ocsp::Request::Nonce::REQUEST_ONLY
109
+ end
110
+
111
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+ require 'r509/oidmapper'
3
+
4
+
5
+ # NOTE
6
+ # The nature of OID registration means that the state does NOT get reset between
7
+ # each test. Accordingly, we MUST use OIDs (and short names) here that will not
8
+ # be present in any other tests (or in the real world)
9
+
10
+ describe R509::OidMapper do
11
+ it "registers one new oid" do
12
+ subject = R509::Subject.new [['1.4.3.2.1.2.3.5.5.5.5.5','random_oid']]
13
+ subject['1.4.3.2.1.2.3.5.5.5.5.5'].should == 'random_oid'
14
+ expect { R509::Subject.new [['myOidName','random_oid']] }.to raise_error(OpenSSL::X509::NameError,'invalid field name')
15
+
16
+ R509::OidMapper.register('1.4.3.2.1.2.3.5.5.5.5.5','myOidName').should == true
17
+ subject_new = R509::Subject.new [['myOidName','random_oid']]
18
+ subject_new['myOidName'].should == 'random_oid'
19
+ end
20
+ it "registers a batch of new oids" do
21
+ expect { R509::Subject.new [['testOidName','random_oid']] }.to raise_error(OpenSSL::X509::NameError,'invalid field name')
22
+ expect { R509::Subject.new [['anotherOidName','second_random']] }.to raise_error(OpenSSL::X509::NameError,'invalid field name')
23
+ R509::OidMapper.batch_register([
24
+ {:oid => '1.4.3.2.1.2.3.4.4.4.4', :short_name => 'testOidName'},
25
+ {:oid => '1.4.3.2.1.2.5.4.4.4.4', :short_name => 'anotherOidName'}
26
+ ])
27
+ subject_new = R509::Subject.new [['testOidName','random_oid'],['anotherOidName','second_random']]
28
+ subject_new['testOidName'].should == 'random_oid'
29
+ subject_new['anotherOidName'].should == 'second_random'
30
+ end
31
+ end
@@ -0,0 +1,198 @@
1
+ require 'spec_helper'
2
+ require 'r509/privatekey'
3
+ require 'stringio'
4
+
5
+ describe R509::PrivateKey do
6
+ before :all do
7
+ @key_csr = TestFixtures::KEY_CSR
8
+ @key_csr_encrypted = TestFixtures::KEY_CSR_ENCRYPTED
9
+ @csr_public_key_modulus = TestFixtures::CSR_PUBLIC_KEY_MODULUS
10
+ @key_csr_der = TestFixtures::KEY_CSR_DER
11
+ @dsa_key = TestFixtures::DSA_KEY
12
+ end
13
+ it "throws an exception when given a type other than DSA or RSA" do
14
+ expect { R509::PrivateKey.new(:type=>:not_rsa_or_dsa) }.to raise_error(ArgumentError)
15
+ end
16
+ it "throws an exception when no hash is provided" do
17
+ expect { R509::PrivateKey.new('string') }.to raise_error(ArgumentError,'Must provide a hash of options')
18
+ end
19
+ it "returns the right value for #rsa?" do
20
+ private_key = R509::PrivateKey.new(:key=>@key_csr)
21
+ private_key.dsa?.should == false
22
+ private_key.rsa?.should == true
23
+ end
24
+ it "returns the right value for #dsa?" do
25
+ private_key = R509::PrivateKey.new(:key => @dsa_key)
26
+ private_key.rsa?.should == false
27
+ private_key.dsa?.should == true
28
+ end
29
+ it "defaults to RSA" do
30
+ private_key = R509::PrivateKey.new(:bit_strength=>1024)
31
+ private_key.key.kind_of?(OpenSSL::PKey::RSA).should == true
32
+ end
33
+ it "loads a pre-existing RSA key" do
34
+ private_key = R509::PrivateKey.new(:key=>@key_csr)
35
+ private_key.to_pem.should == @key_csr
36
+ @key_csr.should_not == nil
37
+ end
38
+ it "generates an RSA key at the default bit strength (2048)" do
39
+ private_key = R509::PrivateKey.new(:type => :rsa)
40
+ private_key.bit_strength.should == 2048
41
+ private_key.key.n.to_i.to_s(2).size.should == 2048
42
+ end
43
+ it "generates an RSA key at a custom bit strength" do
44
+ private_key = R509::PrivateKey.new(:type => :rsa, :bit_strength => 512)
45
+ private_key.bit_strength.should == 512
46
+ private_key.key.n.to_i.to_s(2).size.should == 512
47
+ end
48
+ it "loads a pre-existing DSA key" do
49
+ private_key = R509::PrivateKey.new(:key => @dsa_key)
50
+ private_key.key.kind_of?(OpenSSL::PKey::DSA).should == true
51
+ private_key.key.to_pem.should == @dsa_key
52
+ @dsa_key.should_not == nil
53
+ end
54
+ it "generates a DSA key at the default bit strength (2048)" do
55
+ private_key = R509::PrivateKey.new(:type => :dsa)
56
+ private_key.dsa?.should == true
57
+ private_key.bit_strength.should == 2048
58
+ private_key.key.p.to_i.to_s(2).size.should == 2048
59
+ end
60
+ it "generates a DSA key at a custom bit strength" do
61
+ private_key = R509::PrivateKey.new(:type => :dsa, :bit_strength => 512)
62
+ private_key.bit_strength.should == 512
63
+ private_key.key.p.to_i.to_s(2).size.should == 512
64
+ end
65
+ it "has an exponent of 65537 for new RSA keys" do
66
+ #this test actually checks ruby's underlying libs to make sure they're
67
+ #doing what they're supposed to be doing.
68
+ private_key = R509::PrivateKey.new(:type => :rsa, :bit_strength => 512)
69
+ private_key.key.e.should == 65537
70
+ end
71
+ it "returns the public key" do
72
+ private_key = R509::PrivateKey.new(:key => @key_csr)
73
+ private_key.public_key.n.to_i.should == @csr_public_key_modulus.to_i
74
+ end
75
+ it "returns pem" do
76
+ #load the DER, check that it matches the PEM on to_pem
77
+ private_key = R509::PrivateKey.new(:key => @key_csr_der)
78
+ private_key.to_pem.should == @key_csr
79
+ end
80
+ it "returns der" do
81
+ #load the PEM, check that it matches the DER on to_der
82
+ private_key = R509::PrivateKey.new(:key => @key_csr)
83
+ private_key.to_der.should == @key_csr_der
84
+ end
85
+ it "writes pem" do
86
+ private_key = R509::PrivateKey.new(:key => @key_csr)
87
+ sio = StringIO.new
88
+ sio.set_encoding("BINARY") if sio.respond_to?(:set_encoding)
89
+ private_key.write_pem(sio)
90
+ sio.string.should == @key_csr
91
+ end
92
+ it "writes der" do
93
+ private_key = R509::PrivateKey.new(:key => @key_csr_der)
94
+ sio = StringIO.new
95
+ sio.set_encoding("BINARY") if sio.respond_to?(:set_encoding)
96
+ private_key.write_der(sio)
97
+ sio.string.should == @key_csr_der
98
+ end
99
+ it "loads an encrypted private key with the right password" do
100
+ private_key = R509::PrivateKey.new(:key => @key_csr_encrypted, :password => 'Testing1')
101
+ private_key.public_key.n.to_i.should == @csr_public_key_modulus.to_i
102
+ end
103
+ it "fails to load an encrypted private key with wrong password" do
104
+ expect { R509::PrivateKey.new(:key => @key_csr_encrypted, :password => 'wrongPassword') }.to raise_error(R509::R509Error,"Failed to load private key. Invalid key or incorrect password.")
105
+ end
106
+ it "returns an encrypted pem" do
107
+ private_key = R509::PrivateKey.new(:key => @key_csr)
108
+ encrypted_private_key = private_key.to_encrypted_pem('des3','Testing1')
109
+ decrypted_private_key = R509::PrivateKey.new(:key => encrypted_private_key, :password => 'Testing1')
110
+ private_key.to_pem.should == decrypted_private_key.to_pem
111
+ end
112
+ it "writes an encrypted pem" do
113
+ private_key = R509::PrivateKey.new(:key => @key_csr)
114
+ sio = StringIO.new
115
+ sio.set_encoding("BINARY") if sio.respond_to?(:set_encoding)
116
+ private_key.write_encrypted_pem(sio,'des3','Testing1')
117
+ sio.string.match(/Proc-Type: 4,ENCRYPTED/).should_not == nil
118
+ end
119
+ it "creates an encrypted private key with des3 cipher" do
120
+ private_key = R509::PrivateKey.new(:key => @key_csr)
121
+ sio = StringIO.new
122
+ sio.set_encoding("BINARY") if sio.respond_to?(:set_encoding)
123
+ private_key.write_encrypted_pem(sio,'des3','Testing1')
124
+ sio.string.match(/DES-EDE3-CBC/).should_not == nil
125
+ end
126
+ it "creates an encrypted private key with aes128 cipher" do
127
+ private_key = R509::PrivateKey.new(:key => @key_csr)
128
+ sio = StringIO.new
129
+ sio.set_encoding("BINARY") if sio.respond_to?(:set_encoding)
130
+ private_key.write_encrypted_pem(sio,'aes128','Testing1')
131
+ sio.string.match(/AES-128-CBC/).should_not == nil
132
+ end
133
+ it "returns false for in_hardware? when not using an engine" do
134
+ private_key = R509::PrivateKey.new(:key => @key_csr)
135
+ private_key.in_hardware?.should == false
136
+ end
137
+ it "returns true for in_hardware? when an engine is present" do
138
+ engine = double("engine")
139
+ engine.should_receive(:kind_of?).with(OpenSSL::Engine).and_return(true)
140
+ key_name = "r509_key"
141
+ key = R509::PrivateKey.new(
142
+ :engine => engine,
143
+ :key_name => key_name
144
+ )
145
+ key.in_hardware?.should == true
146
+ end
147
+ it "raises an error if you provide engine and key" do
148
+ expect { R509::PrivateKey.new(:key => @key_csr, :engine => 'not really an engine') }.to raise_error(ArgumentError, "You can't pass both :key and :engine")
149
+ end
150
+ it "raises an error if you provide a key_name with no engine" do
151
+ expect { R509::PrivateKey.new(:key_name => 'my_key') }.to raise_error(ArgumentError, 'When providing a :key_name you MUST provide an :engine')
152
+ end
153
+ it "raises an error when providing an engine with no key_name" do
154
+ expect { R509::PrivateKey.new(:engine => 'engine_goes_here') }.to raise_error(ArgumentError, 'When providing an :engine you MUST provide a :key_name')
155
+ end
156
+ it "raises an error if engine is not an OpenSSL::Engine" do
157
+ expect { R509::PrivateKey.new(:key_name => 'my_key', :engine => 'not really an engine') }.to raise_error(ArgumentError, 'When providing an engine, it must be of type OpenSSL::Engine')
158
+ end
159
+ it "raises an error if you call output methods (pem,der,write) when using a hardware key" do
160
+ engine = double("engine")
161
+ engine.should_receive(:kind_of?).with(OpenSSL::Engine).and_return(true)
162
+ key_name = "r509_key"
163
+ key = R509::PrivateKey.new(
164
+ :engine => engine,
165
+ :key_name => key_name
166
+ )
167
+ expect { key.to_pem }.to raise_error(R509::R509Error, "This method cannot be called when using keys in hardware")
168
+ expect { key.to_der }.to raise_error(R509::R509Error, "This method cannot be called when using keys in hardware")
169
+ expect { key.to_encrypted_pem('aes256','password') }.to raise_error(R509::R509Error, "This method cannot be called when using keys in hardware")
170
+ expect { key.write_encrypted_pem('/dev/null','aes256','password') }.to raise_error(R509::R509Error, "This method cannot be called when using keys in hardware")
171
+ expect { key.write_der('/dev/null') }.to raise_error(R509::R509Error, "This method cannot be called when using keys in hardware")
172
+ end
173
+ it "loads a hardware key successfully" do
174
+ engine = double("engine")
175
+ engine.should_receive(:kind_of?).with(OpenSSL::Engine).and_return(true)
176
+ faux_key = double("faux_key")
177
+ faux_key.should_receive(:public_key).and_return("returning public key")
178
+ key_name = "r509_key"
179
+ engine.should_receive(:load_private_key).with(key_name).and_return(faux_key)
180
+ key = R509::PrivateKey.new(
181
+ :engine => engine,
182
+ :key_name => key_name
183
+ )
184
+ key.kind_of?(R509::PrivateKey).should == true
185
+ key.public_key.should == "returning public key"
186
+ end
187
+ it "loads a private key with load_from_file" do
188
+ path = File.dirname(__FILE__) + '/fixtures/key4.pem'
189
+ key = R509::PrivateKey.load_from_file path
190
+ key.rsa?.should == true
191
+ end
192
+ it "loads a private key with load_from_file with password" do
193
+ path = File.dirname(__FILE__) + '/fixtures/key4_encrypted_des3.pem'
194
+ key = R509::PrivateKey.load_from_file( path, 'r509')
195
+ key.rsa?.should == true
196
+ end
197
+ end
198
+