r509 0.8.1 → 0.9
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.
- data/README.md +343 -151
- data/Rakefile +26 -23
- data/bin/r509 +126 -112
- data/bin/r509-parse +24 -24
- data/doc/R509.html +169 -7
- data/doc/R509/ASN1.html +370 -0
- data/doc/R509/ASN1/GeneralName.html +1121 -0
- data/doc/R509/ASN1/GeneralNames.html +843 -0
- data/doc/R509/ASN1/NoticeReference.html +392 -0
- data/doc/R509/ASN1/PolicyInformation.html +387 -0
- data/doc/R509/ASN1/PolicyQualifiers.html +455 -0
- data/doc/R509/ASN1/UserNotice.html +386 -0
- data/doc/R509/{Crl.html → CRL.html} +7 -7
- data/doc/R509/CRL/Administrator.html +1559 -0
- data/doc/R509/{Crl/Parser.html → CRL/SignedList.html} +501 -210
- data/doc/R509/{Csr.html → CSR.html} +444 -314
- data/doc/R509/Cert.html +866 -617
- data/doc/R509/Cert/Extensions.html +52 -41
- data/doc/R509/Cert/Extensions/AuthorityInfoAccess.html +70 -35
- data/doc/R509/Cert/Extensions/AuthorityKeyIdentifier.html +387 -4
- data/doc/R509/Cert/Extensions/BasicConstraints.html +61 -25
- data/doc/R509/Cert/Extensions/CRLDistributionPoints.html +354 -0
- data/doc/R509/Cert/Extensions/CertificatePolicies.html +340 -0
- data/doc/R509/Cert/Extensions/ExtendedKeyUsage.html +440 -49
- data/doc/R509/Cert/Extensions/{CrlDistributionPoints.html → InhibitAnyPolicy.html} +52 -35
- data/doc/R509/Cert/Extensions/KeyUsage.html +247 -121
- data/doc/R509/Cert/Extensions/NameConstraints.html +445 -0
- data/doc/R509/Cert/Extensions/OCSPNoCheck.html +239 -0
- data/doc/R509/Cert/Extensions/PolicyConstraints.html +424 -0
- data/doc/R509/Cert/Extensions/SubjectAlternativeName.html +437 -62
- data/doc/R509/Cert/Extensions/SubjectKeyIdentifier.html +52 -10
- data/doc/R509/CertificateAuthority.html +4 -4
- data/doc/R509/CertificateAuthority/Signer.html +154 -187
- data/doc/R509/Config.html +6 -6
- data/doc/R509/Config/{CaConfig.html → CAConfig.html} +451 -348
- data/doc/R509/Config/{CaConfigPool.html → CAConfigPool.html} +47 -47
- data/doc/R509/Config/CAProfile.html +1015 -0
- data/doc/R509/Config/SubjectItemPolicy.html +86 -86
- data/doc/R509/IOHelpers.html +22 -22
- data/doc/R509/MessageDigest.html +14 -14
- data/doc/R509/NameSanitizer.html +53 -53
- data/doc/R509/{Ocsp.html → OCSP.html} +9 -9
- data/doc/R509/{Ocsp → OCSP}/Request.html +7 -7
- data/doc/R509/{Ocsp → OCSP}/Request/Nonce.html +56 -11
- data/doc/R509/{Ocsp → OCSP}/Response.html +44 -44
- data/doc/R509/{OidMapper.html → OIDMapper.html} +23 -39
- data/doc/R509/PrivateKey.html +415 -168
- data/doc/R509/R509Error.html +3 -3
- data/doc/R509/{Spki.html → SPKI.html} +354 -192
- data/doc/R509/Subject.html +224 -113
- data/doc/R509/Validity.html +27 -5
- data/doc/R509/Validity/Checker.html +13 -13
- data/doc/R509/Validity/DefaultChecker.html +13 -13
- data/doc/R509/Validity/DefaultWriter.html +14 -14
- data/doc/R509/Validity/Status.html +39 -39
- data/doc/R509/Validity/Writer.html +18 -18
- data/doc/_index.html +138 -35
- data/doc/class_list.html +1 -1
- data/doc/css/style.css +10 -0
- data/doc/file.README.html +368 -171
- data/doc/file.r509.html +92 -69
- data/doc/frames.html +1 -1
- data/doc/index.html +368 -171
- data/doc/method_list.html +910 -390
- data/doc/top-level-namespace.html +3 -3
- data/lib/r509.rb +32 -16
- data/lib/r509/asn1.rb +375 -0
- data/lib/r509/cert.rb +381 -364
- data/lib/r509/cert/extensions.rb +443 -76
- data/lib/r509/certificate_authority.rb +407 -0
- data/lib/r509/config.rb +547 -351
- data/lib/r509/crl.rb +336 -366
- data/lib/r509/csr.rb +278 -289
- data/lib/r509/ec-hack.rb +37 -0
- data/lib/r509/exceptions.rb +3 -3
- data/lib/r509/io_helpers.rb +44 -44
- data/lib/r509/message_digest.rb +53 -0
- data/lib/r509/ocsp.rb +80 -70
- data/lib/r509/oid_mapper.rb +32 -0
- data/lib/r509/private_key.rb +228 -0
- data/lib/r509/spki.rb +145 -93
- data/lib/r509/subject.rb +203 -110
- data/lib/r509/validity.rb +70 -68
- data/lib/r509/version.rb +2 -2
- data/r509.yaml +92 -69
- data/spec/asn1_spec.rb +402 -0
- data/spec/cert/extensions_spec.rb +957 -494
- data/spec/cert_spec.rb +382 -307
- data/spec/certificate_authority_spec.rb +668 -250
- data/spec/config_spec.rb +515 -302
- data/spec/crl_spec.rb +197 -198
- data/spec/csr_spec.rb +334 -289
- data/spec/fixtures.rb +247 -171
- data/spec/fixtures/cert1.der +0 -0
- data/spec/fixtures/cert1.pem +0 -0
- data/spec/fixtures/cert1_public_key_modulus.txt +0 -0
- data/spec/fixtures/cert3.p12 +0 -0
- data/spec/fixtures/cert3.pem +0 -0
- data/spec/fixtures/cert3_key.pem +0 -0
- data/spec/fixtures/cert3_key_des3.pem +0 -0
- data/spec/fixtures/cert4.pem +0 -0
- data/spec/fixtures/cert5.pem +0 -0
- data/spec/fixtures/cert6.pem +0 -0
- data/spec/fixtures/cert_expired.pem +0 -0
- data/spec/fixtures/cert_inhibit.pem +24 -0
- data/spec/fixtures/cert_name_constraints.pem +29 -0
- data/spec/fixtures/cert_not_yet_valid.pem +0 -0
- data/spec/fixtures/cert_ocsp_no_check.pem +18 -0
- data/spec/fixtures/cert_policy_constraints.pem +31 -0
- data/spec/fixtures/cert_san.pem +0 -0
- data/spec/fixtures/cert_san2.pem +0 -0
- data/spec/fixtures/cert_unknown_extension.pem +28 -0
- data/spec/fixtures/config_pool_test_minimal.yaml +11 -11
- data/spec/fixtures/config_test.yaml +54 -36
- data/spec/fixtures/config_test_dsa.yaml +35 -0
- data/spec/fixtures/config_test_ec.yaml +35 -0
- data/spec/fixtures/config_test_engine_key.yaml +5 -5
- data/spec/fixtures/config_test_engine_no_key_name.yaml +4 -4
- data/spec/fixtures/config_test_minimal.yaml +4 -4
- data/spec/fixtures/config_test_password.yaml +5 -5
- data/spec/fixtures/config_test_various.yaml +111 -74
- data/spec/fixtures/crl_list_file.txt +0 -0
- data/spec/fixtures/crl_with_reason.pem +0 -0
- data/spec/fixtures/csr1.der +0 -0
- data/spec/fixtures/csr1.pem +0 -0
- data/spec/fixtures/csr1_key.der +0 -0
- data/spec/fixtures/csr1_key.pem +0 -0
- data/spec/fixtures/csr1_key_encrypted_des3.pem +0 -0
- data/spec/fixtures/csr1_newlines.pem +0 -0
- data/spec/fixtures/csr1_no_begin_end.pem +0 -0
- data/spec/fixtures/csr1_public_key_modulus.txt +0 -0
- data/spec/fixtures/csr2.pem +0 -0
- data/spec/fixtures/csr2_key.pem +0 -0
- data/spec/fixtures/csr3.pem +0 -0
- data/spec/fixtures/csr4.pem +0 -0
- data/spec/fixtures/csr_dsa.pem +0 -0
- data/spec/fixtures/csr_invalid_signature.pem +0 -0
- data/spec/fixtures/dsa_key.pem +0 -0
- data/spec/fixtures/dsa_root.cer +28 -0
- data/spec/fixtures/dsa_root.key +20 -0
- data/spec/fixtures/ec_csr2.der +0 -0
- data/spec/fixtures/ec_csr2.pem +8 -0
- data/spec/fixtures/ec_key1.der +0 -0
- data/spec/fixtures/ec_key1.pem +6 -0
- data/spec/fixtures/ec_key1_encrypted.pem +9 -0
- data/spec/fixtures/ec_key2.pem +6 -0
- data/spec/fixtures/hmacsha1.sig +1 -0
- data/spec/fixtures/hmacsha512.sig +1 -0
- data/spec/fixtures/key4.pem +0 -0
- data/spec/fixtures/key4_encrypted_des3.pem +0 -0
- data/spec/fixtures/missing_key_identifier_ca.cer +0 -0
- data/spec/fixtures/missing_key_identifier_ca.key +0 -0
- data/spec/fixtures/ocsptest.r509.local.pem +0 -0
- data/spec/fixtures/ocsptest.r509.local_ocsp_request.der +0 -0
- data/spec/fixtures/ocsptest2.r509.local.pem +0 -0
- data/spec/fixtures/second_ca.cer +0 -0
- data/spec/fixtures/second_ca.key +0 -0
- data/spec/fixtures/spkac.der +0 -0
- data/spec/fixtures/spkac.txt +0 -0
- data/spec/fixtures/spkac_dsa.txt +1 -1
- data/spec/fixtures/spkac_dsa_no_verify.txt +1 -0
- data/spec/fixtures/spkac_ec.txt +1 -0
- data/spec/fixtures/spkac_rsa_newlines.txt +13 -0
- data/spec/fixtures/stca.pem +0 -0
- data/spec/fixtures/stca_ocsp_request.der +0 -0
- data/spec/fixtures/stca_ocsp_response.der +0 -0
- data/spec/fixtures/test1.csr +0 -0
- data/spec/fixtures/test_ca.cer +0 -0
- data/spec/fixtures/test_ca.key +0 -0
- data/spec/fixtures/test_ca.p12 +0 -0
- data/spec/fixtures/test_ca_des3.key +0 -0
- data/spec/fixtures/test_ca_ec.cer +14 -0
- data/spec/fixtures/test_ca_ec.key +6 -0
- data/spec/fixtures/test_ca_ec_ee.cer +22 -0
- data/spec/fixtures/test_ca_ec_ee.key +6 -0
- data/spec/fixtures/test_ca_ocsp.cer +0 -0
- data/spec/fixtures/test_ca_ocsp.key +0 -0
- data/spec/fixtures/test_ca_ocsp.p12 +0 -0
- data/spec/fixtures/test_ca_ocsp_chain.txt +0 -0
- data/spec/fixtures/test_ca_ocsp_response.der +0 -0
- data/spec/fixtures/test_ca_subroot.cer +0 -0
- data/spec/fixtures/test_ca_subroot.key +0 -0
- data/spec/fixtures/test_ca_subroot_ocsp.cer +0 -0
- data/spec/fixtures/test_ca_subroot_ocsp.key +0 -0
- data/spec/fixtures/test_ca_subroot_ocsp_response.der +0 -0
- data/spec/fixtures/unknown_oid.csr +0 -0
- data/spec/message_digest_spec.rb +104 -84
- data/spec/ocsp_spec.rb +105 -105
- data/spec/oid_mapper_spec.rb +21 -21
- data/spec/private_key_spec.rb +275 -0
- data/spec/r509_spec.rb +35 -0
- data/spec/spec_helper.rb +15 -6
- data/spec/spki_spec.rb +221 -142
- data/spec/subject_spec.rb +232 -164
- data/spec/validity_spec.rb +91 -91
- metadata +79 -25
- data/doc/R509/Config/CaProfile.html +0 -651
- data/doc/R509/Crl/Administrator.html +0 -2073
- data/lib/r509/certificateauthority.rb +0 -290
- data/lib/r509/messagedigest.rb +0 -49
- data/lib/r509/oidmapper.rb +0 -32
- data/lib/r509/privatekey.rb +0 -185
- data/spec/privatekey_spec.rb +0 -198
data/spec/ocsp_spec.rb
CHANGED
@@ -2,110 +2,110 @@ require 'spec_helper'
|
|
2
2
|
require 'r509/ocsp'
|
3
3
|
require 'openssl'
|
4
4
|
|
5
|
-
describe R509::
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
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
110
|
|
111
111
|
end
|
data/spec/oid_mapper_spec.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'r509/
|
2
|
+
require 'r509/oid_mapper'
|
3
3
|
|
4
4
|
|
5
5
|
# NOTE
|
@@ -7,25 +7,25 @@ require 'r509/oidmapper'
|
|
7
7
|
# each test. Accordingly, we MUST use OIDs (and short names) here that will not
|
8
8
|
# be present in any other tests (or in the real world)
|
9
9
|
|
10
|
-
describe R509::
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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
31
|
end
|
@@ -0,0 +1,275 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'r509/private_key'
|
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
|
+
@ec_key_pem = TestFixtures::EC_KEY1
|
13
|
+
@ec_key_der = TestFixtures::EC_KEY1_DER
|
14
|
+
@ec_key_encrypted = TestFixtures::EC_KEY1_ENCRYPTED
|
15
|
+
end
|
16
|
+
it "throws an exception when given a type other than DSA, RSA, or EC" do
|
17
|
+
expect { R509::PrivateKey.new(:type=>:not_rsa_or_dsa) }.to raise_error(ArgumentError)
|
18
|
+
end
|
19
|
+
it "throws an exception when no hash is provided" do
|
20
|
+
expect { R509::PrivateKey.new('string') }.to raise_error(ArgumentError,'Must provide a hash of options')
|
21
|
+
end
|
22
|
+
it "returns the right value for #rsa?" do
|
23
|
+
private_key = R509::PrivateKey.new(:key=>@key_csr)
|
24
|
+
private_key.dsa?.should == false
|
25
|
+
private_key.ec?.should == false
|
26
|
+
private_key.rsa?.should == true
|
27
|
+
end
|
28
|
+
it "returns the right value for #dsa?" do
|
29
|
+
private_key = R509::PrivateKey.new(:key => @dsa_key)
|
30
|
+
private_key.rsa?.should == false
|
31
|
+
private_key.ec?.should == false
|
32
|
+
private_key.dsa?.should == true
|
33
|
+
end
|
34
|
+
it "generates a default 2048-bit RSA key when nothing is passed to the constructor" do
|
35
|
+
private_key = R509::PrivateKey.new
|
36
|
+
private_key.rsa?.should == true
|
37
|
+
private_key.bit_strength.should == 2048
|
38
|
+
end
|
39
|
+
it "defaults to RSA" do
|
40
|
+
private_key = R509::PrivateKey.new(:bit_strength=>1024)
|
41
|
+
private_key.key.kind_of?(OpenSSL::PKey::RSA).should == true
|
42
|
+
end
|
43
|
+
it "loads a pre-existing RSA key" do
|
44
|
+
private_key = R509::PrivateKey.new(:key=>@key_csr)
|
45
|
+
private_key.to_pem.should == @key_csr
|
46
|
+
@key_csr.should_not == nil
|
47
|
+
end
|
48
|
+
it "generates an RSA key at the default bit strength (2048)" do
|
49
|
+
private_key = R509::PrivateKey.new(:type => :rsa)
|
50
|
+
private_key.bit_strength.should == 2048
|
51
|
+
private_key.key.n.to_i.to_s(2).size.should == 2048
|
52
|
+
end
|
53
|
+
it "generates an RSA key at a custom bit strength" do
|
54
|
+
private_key = R509::PrivateKey.new(:type => :rsa, :bit_strength => 512)
|
55
|
+
private_key.bit_strength.should == 512
|
56
|
+
private_key.key.n.to_i.to_s(2).size.should == 512
|
57
|
+
end
|
58
|
+
it "loads a pre-existing DSA key" do
|
59
|
+
private_key = R509::PrivateKey.new(:key => @dsa_key)
|
60
|
+
private_key.key.kind_of?(OpenSSL::PKey::DSA).should == true
|
61
|
+
private_key.key.to_pem.should == @dsa_key
|
62
|
+
@dsa_key.should_not == nil
|
63
|
+
end
|
64
|
+
it "generates a DSA key at the default bit strength (2048)" do
|
65
|
+
private_key = R509::PrivateKey.new(:type => :dsa)
|
66
|
+
private_key.dsa?.should == true
|
67
|
+
private_key.bit_strength.should == 2048
|
68
|
+
private_key.key.p.to_i.to_s(2).size.should == 2048
|
69
|
+
end
|
70
|
+
it "generates a DSA key at a custom bit strength" do
|
71
|
+
private_key = R509::PrivateKey.new(:type => :dsa, :bit_strength => 512)
|
72
|
+
private_key.bit_strength.should == 512
|
73
|
+
private_key.key.p.to_i.to_s(2).size.should == 512
|
74
|
+
end
|
75
|
+
it "has an exponent of 65537 for new RSA keys" do
|
76
|
+
#this test actually checks ruby's underlying libs to make sure they're
|
77
|
+
#doing what they're supposed to be doing.
|
78
|
+
private_key = R509::PrivateKey.new(:type => :rsa, :bit_strength => 512)
|
79
|
+
private_key.key.e.should == 65537
|
80
|
+
end
|
81
|
+
it "returns the public key" do
|
82
|
+
private_key = R509::PrivateKey.new(:key => @key_csr)
|
83
|
+
private_key.public_key.n.to_i.should == @csr_public_key_modulus.to_i
|
84
|
+
end
|
85
|
+
it "returns pem" do
|
86
|
+
#load the DER, check that it matches the PEM on to_pem
|
87
|
+
private_key = R509::PrivateKey.new(:key => @key_csr_der)
|
88
|
+
private_key.to_pem.should == @key_csr
|
89
|
+
end
|
90
|
+
it "returns der" do
|
91
|
+
#load the PEM, check that it matches the DER on to_der
|
92
|
+
private_key = R509::PrivateKey.new(:key => @key_csr)
|
93
|
+
private_key.to_der.should == @key_csr_der
|
94
|
+
end
|
95
|
+
it "writes pem" do
|
96
|
+
private_key = R509::PrivateKey.new(:key => @key_csr)
|
97
|
+
sio = StringIO.new
|
98
|
+
sio.set_encoding("BINARY") if sio.respond_to?(:set_encoding)
|
99
|
+
private_key.write_pem(sio)
|
100
|
+
sio.string.should == @key_csr
|
101
|
+
end
|
102
|
+
it "writes der" do
|
103
|
+
private_key = R509::PrivateKey.new(:key => @key_csr_der)
|
104
|
+
sio = StringIO.new
|
105
|
+
sio.set_encoding("BINARY") if sio.respond_to?(:set_encoding)
|
106
|
+
private_key.write_der(sio)
|
107
|
+
sio.string.should == @key_csr_der
|
108
|
+
end
|
109
|
+
it "loads an encrypted private key with the right password" do
|
110
|
+
private_key = R509::PrivateKey.new(:key => @key_csr_encrypted, :password => 'Testing1')
|
111
|
+
private_key.public_key.n.to_i.should == @csr_public_key_modulus.to_i
|
112
|
+
end
|
113
|
+
it "fails to load an encrypted private key with wrong password" do
|
114
|
+
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.")
|
115
|
+
end
|
116
|
+
it "returns an encrypted pem" do
|
117
|
+
private_key = R509::PrivateKey.new(:key => @key_csr)
|
118
|
+
encrypted_private_key = private_key.to_encrypted_pem('des3','Testing1')
|
119
|
+
decrypted_private_key = R509::PrivateKey.new(:key => encrypted_private_key, :password => 'Testing1')
|
120
|
+
private_key.to_pem.should == decrypted_private_key.to_pem
|
121
|
+
end
|
122
|
+
it "writes an encrypted pem" do
|
123
|
+
private_key = R509::PrivateKey.new(:key => @key_csr)
|
124
|
+
sio = StringIO.new
|
125
|
+
sio.set_encoding("BINARY") if sio.respond_to?(:set_encoding)
|
126
|
+
private_key.write_encrypted_pem(sio,'des3','Testing1')
|
127
|
+
sio.string.match(/Proc-Type: 4,ENCRYPTED/).should_not == nil
|
128
|
+
end
|
129
|
+
it "creates an encrypted private key with des3 cipher" do
|
130
|
+
private_key = R509::PrivateKey.new(:key => @key_csr)
|
131
|
+
sio = StringIO.new
|
132
|
+
sio.set_encoding("BINARY") if sio.respond_to?(:set_encoding)
|
133
|
+
private_key.write_encrypted_pem(sio,'des3','Testing1')
|
134
|
+
sio.string.match(/DES-EDE3-CBC/).should_not == nil
|
135
|
+
end
|
136
|
+
it "creates an encrypted private key with aes128 cipher" do
|
137
|
+
private_key = R509::PrivateKey.new(:key => @key_csr)
|
138
|
+
sio = StringIO.new
|
139
|
+
sio.set_encoding("BINARY") if sio.respond_to?(:set_encoding)
|
140
|
+
private_key.write_encrypted_pem(sio,'aes128','Testing1')
|
141
|
+
sio.string.match(/AES-128-CBC/).should_not == nil
|
142
|
+
end
|
143
|
+
it "returns false for in_hardware? when not using an engine" do
|
144
|
+
private_key = R509::PrivateKey.new(:key => @key_csr)
|
145
|
+
private_key.in_hardware?.should == false
|
146
|
+
end
|
147
|
+
it "returns true for in_hardware? when an engine is present" do
|
148
|
+
engine = double("engine")
|
149
|
+
engine.should_receive(:kind_of?).with(OpenSSL::Engine).and_return(true)
|
150
|
+
key_name = "r509_key"
|
151
|
+
key = R509::PrivateKey.new(
|
152
|
+
:engine => engine,
|
153
|
+
:key_name => key_name
|
154
|
+
)
|
155
|
+
key.in_hardware?.should == true
|
156
|
+
end
|
157
|
+
it "raises an error if you provide engine and key" do
|
158
|
+
expect { R509::PrivateKey.new(:key => @key_csr, :engine => 'not really an engine') }.to raise_error(ArgumentError, "You can't pass both :key and :engine")
|
159
|
+
end
|
160
|
+
it "raises an error if you provide a key_name with no engine" do
|
161
|
+
expect { R509::PrivateKey.new(:key_name => 'my_key') }.to raise_error(ArgumentError, 'When providing a :key_name you MUST provide an :engine')
|
162
|
+
end
|
163
|
+
it "raises an error when providing an engine with no key_name" do
|
164
|
+
expect { R509::PrivateKey.new(:engine => 'engine_goes_here') }.to raise_error(ArgumentError, 'When providing an :engine you MUST provide a :key_name')
|
165
|
+
end
|
166
|
+
it "raises an error if engine is not an OpenSSL::Engine" do
|
167
|
+
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')
|
168
|
+
end
|
169
|
+
it "raises an error if you call output methods (pem,der,write) when using a hardware key" do
|
170
|
+
engine = double("engine")
|
171
|
+
engine.should_receive(:kind_of?).with(OpenSSL::Engine).and_return(true)
|
172
|
+
key_name = "r509_key"
|
173
|
+
key = R509::PrivateKey.new(
|
174
|
+
:engine => engine,
|
175
|
+
:key_name => key_name
|
176
|
+
)
|
177
|
+
expect { key.to_pem }.to raise_error(R509::R509Error, "This method cannot be called when using keys in hardware")
|
178
|
+
expect { key.to_der }.to raise_error(R509::R509Error, "This method cannot be called when using keys in hardware")
|
179
|
+
expect { key.to_encrypted_pem('aes256','password') }.to raise_error(R509::R509Error, "This method cannot be called when using keys in hardware")
|
180
|
+
expect { key.write_encrypted_pem('/dev/null','aes256','password') }.to raise_error(R509::R509Error, "This method cannot be called when using keys in hardware")
|
181
|
+
expect { key.write_der('/dev/null') }.to raise_error(R509::R509Error, "This method cannot be called when using keys in hardware")
|
182
|
+
end
|
183
|
+
it "loads a hardware key successfully" do
|
184
|
+
engine = double("engine")
|
185
|
+
engine.should_receive(:kind_of?).with(OpenSSL::Engine).and_return(true)
|
186
|
+
faux_key = double("faux_key")
|
187
|
+
faux_key.should_receive(:public_key).and_return("returning public key")
|
188
|
+
key_name = "r509_key"
|
189
|
+
engine.should_receive(:load_private_key).twice.with(key_name).and_return(faux_key)
|
190
|
+
key = R509::PrivateKey.new(
|
191
|
+
:engine => engine,
|
192
|
+
:key_name => key_name
|
193
|
+
)
|
194
|
+
key.kind_of?(R509::PrivateKey).should == true
|
195
|
+
key.public_key.should == "returning public key"
|
196
|
+
end
|
197
|
+
it "loads a private key with load_from_file" do
|
198
|
+
path = File.dirname(__FILE__) + '/fixtures/key4.pem'
|
199
|
+
key = R509::PrivateKey.load_from_file path
|
200
|
+
key.rsa?.should == true
|
201
|
+
end
|
202
|
+
it "loads a private key with load_from_file with password" do
|
203
|
+
path = File.dirname(__FILE__) + '/fixtures/key4_encrypted_des3.pem'
|
204
|
+
key = R509::PrivateKey.load_from_file( path, 'r509')
|
205
|
+
key.rsa?.should == true
|
206
|
+
end
|
207
|
+
|
208
|
+
it "returns an error for curve_name for dsa/rsa" do
|
209
|
+
private_key = R509::PrivateKey.new(:key => @key_csr)
|
210
|
+
expect { private_key.curve_name }.to raise_error(R509::R509Error, 'Curve name is only available with EC private keys')
|
211
|
+
end
|
212
|
+
|
213
|
+
context "elliptic curves", :ec => true do
|
214
|
+
it "loads a pre-existing EC key" do
|
215
|
+
private_key = R509::PrivateKey.new(:key => @ec_key_pem)
|
216
|
+
private_key.to_pem.should == @ec_key_pem
|
217
|
+
@ec_key_pem.should_not be_nil
|
218
|
+
end
|
219
|
+
|
220
|
+
it "loads an encrypted private key with the right password" do
|
221
|
+
private_key = R509::PrivateKey.new(:key => @ec_key_encrypted, :password => 'Testing1')
|
222
|
+
private_key.to_pem.should == @ec_key_pem
|
223
|
+
@ec_key_encrypted.should_not be_nil
|
224
|
+
@ec_key_pem.should_not be_nil
|
225
|
+
end
|
226
|
+
|
227
|
+
it "returns the right value for #ec?" do
|
228
|
+
path = File.dirname(__FILE__) + '/fixtures/ec_key1.der'
|
229
|
+
private_key = R509::PrivateKey.load_from_file path
|
230
|
+
private_key.rsa?.should == false
|
231
|
+
private_key.dsa?.should == false
|
232
|
+
private_key.ec?.should == true
|
233
|
+
end
|
234
|
+
|
235
|
+
it "returns the curve_name" do
|
236
|
+
private_key = R509::PrivateKey.new(:key => @ec_key_pem)
|
237
|
+
private_key.curve_name.should == 'secp384r1'
|
238
|
+
end
|
239
|
+
|
240
|
+
it "generates an elliptic curve key using the default curve (secp384r1)" do
|
241
|
+
private_key = R509::PrivateKey.new(:type => :ec)
|
242
|
+
private_key.curve_name.should == 'secp384r1'
|
243
|
+
end
|
244
|
+
|
245
|
+
it "generates an elliptic curve key using a specified curve" do
|
246
|
+
private_key = R509::PrivateKey.new(:type => :ec, :curve_name => 'sect283r1')
|
247
|
+
private_key.curve_name.should == 'sect283r1'
|
248
|
+
end
|
249
|
+
|
250
|
+
it "returns the public key" do
|
251
|
+
private_key = R509::PrivateKey.new(:key => @ec_key_pem)
|
252
|
+
public_key = private_key.public_key
|
253
|
+
public_key.public_key?.should == true
|
254
|
+
public_key.private_key?.should == false
|
255
|
+
end
|
256
|
+
|
257
|
+
it "returns the pem" do
|
258
|
+
private_key = R509::PrivateKey.new(:key => @ec_key_pem)
|
259
|
+
private_key.to_pem.should == @ec_key_pem
|
260
|
+
end
|
261
|
+
|
262
|
+
it "returns the der" do
|
263
|
+
private_key = R509::PrivateKey.new(:key => @ec_key_pem)
|
264
|
+
private_key.to_der.should == @ec_key_der
|
265
|
+
end
|
266
|
+
|
267
|
+
it "returns error for bit_strength" do
|
268
|
+
private_key = R509::PrivateKey.new(:key => @ec_key_pem)
|
269
|
+
expect { private_key.bit_strength }.to raise_error(R509::R509Error,'Bit strength is not available for EC at this time.')
|
270
|
+
end
|
271
|
+
|
272
|
+
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|