ruby-sslyze 1.1.0 → 1.2.0

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.
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+ require 'xml_examples'
3
+ require 'sslyze/xml/certinfo/certificate/public_key'
4
+
5
+ describe SSLyze::XML::Certinfo::Certificate::PublicKey do
6
+ include_examples "XML specs"
7
+
8
+ let(:xpath) { '/document/results/target/certinfo/receivedCertificateChain/certificate/publicKey' }
9
+
10
+ subject { described_class.new(xml.at(xpath)) }
11
+
12
+ describe "#algorithm" do
13
+ context "when the algorithm attribute is RSA" do
14
+ let(:xpath) { "#{super()}[@algorithm='RSA']" }
15
+
16
+ it { expect(subject.algorithm).to be :RSA }
17
+ end
18
+
19
+ context "when the algorithm attribute is DSA" do
20
+ let(:xpath) { "#{super()}[@algorithm='DSA']" }
21
+
22
+ pending "need to find a target with a DSA public key" do
23
+ expect(subject.algorithm).to be :DSA
24
+ end
25
+ end
26
+
27
+ context "when the algorithm attribute is EllipticCurve" do
28
+ let(:xpath) { "#{super()}[@algorithm='EllipticCurve']" }
29
+
30
+ it { expect(subject.algorithm).to be :EC }
31
+ end
32
+ end
33
+
34
+ describe "#size" do
35
+ let(:expected_size) { 2048 }
36
+ let(:xpath) { "#{super()}[@size=#{expected_size}]" }
37
+
38
+ it "should parse the size attribute" do
39
+ expect(subject.size).to be expected_size
40
+ end
41
+ end
42
+
43
+ describe "#curve" do
44
+ context "when the curve attribute is present" do
45
+ let(:expected_curve) { :secp256r1 }
46
+ let(:xpath) { "#{super()}[@curve='#{expected_curve}']" }
47
+
48
+ it { expect(subject.curve).to be(expected_curve) }
49
+ end
50
+
51
+ context "when the curve attribute is missing" do
52
+ let(:xpath) { "#{super()}[not(@curve)]" }
53
+
54
+ it { expect(subject.curve).to be nil }
55
+ end
56
+ end
57
+
58
+ describe "#exponent" do
59
+ context "when the exponent attribute is present" do
60
+ let(:xpath) { "#{super()}[@exponent]" }
61
+
62
+ it { expect(subject.exponent).to be 65537 }
63
+ end
64
+
65
+ context "when the exponent attribute is missing" do
66
+ let(:xpath) { "#{super()}[not(@exponent)]" }
67
+
68
+ it { expect(subject.exponent).to be nil }
69
+ end
70
+ end
71
+ end
@@ -116,7 +116,7 @@ JqbaIVifYwqwNN+4lRxS3F5lNlA/il12IOgbRioLI62o8G0DaEUQgHNf8vSG
116
116
 
117
117
  describe "#public_key" do
118
118
  it do
119
- expect(subject.public_key).to be_a(SSLyze::X509::PublicKey)
119
+ expect(subject.public_key).to be_a(described_class::PublicKey)
120
120
  end
121
121
  end
122
122
 
@@ -50,9 +50,7 @@ describe SSLyze::XML::Certinfo::OCSPStapling::OCSPResponse do
50
50
  end
51
51
 
52
52
  describe "#produced_at" do
53
- let(:expected_time) { 'Mar 12 12:34:51 2018 GMT' }
54
-
55
- let(:xpath) { "#{super()}[producedAt/text()='#{expected_time}']" }
53
+ let(:expected_time) { node.at_xpath('producedAt').inner_text }
56
54
 
57
55
  it "should query producedAt and return a Time object" do
58
56
  expect(subject.produced_at).to be == Time.parse(expected_time)
@@ -13,15 +13,14 @@ describe SSLyze::XML::Certinfo::ReceivedCertificateChain do
13
13
 
14
14
  describe "#each_certificate" do
15
15
  context "when 'certificate' XML children are present" do
16
- let(:xpath) { "#{super()}[certificate]" }
17
- let(:xpath_count) { xml.xpath(xpath).count }
16
+ let(:xpath) { "#{super()}[certificate]" }
17
+ let(:count) { node.xpath('./certificate').count }
18
18
 
19
19
  it "should yield successive Certificate objects" do
20
20
  expect { |b|
21
21
  subject.each_certificate(&b)
22
22
  }.to yield_successive_args(
23
- SSLyze::XML::Certinfo::Certificate,
24
- SSLyze::XML::Certinfo::Certificate
23
+ *[SSLyze::XML::Certinfo::Certificate] * count
25
24
  )
26
25
  end
27
26
  end
@@ -70,8 +69,6 @@ describe SSLyze::XML::Certinfo::ReceivedCertificateChain do
70
69
  let(:xpath_count) { xml.at(xpath).xpath('certificate').count - 2 }
71
70
 
72
71
  it "should yield the intermediate certificates" do
73
- pending "<receivedCertificateChain/> always has at most two <certificate/> children"
74
-
75
72
  expect { |b|
76
73
  subject.each_intermediate(&b)
77
74
  }.to yield_successive_args(
@@ -97,8 +94,6 @@ describe SSLyze::XML::Certinfo::ReceivedCertificateChain do
97
94
  let(:xpath_count) { xml.at(xpath).xpath('certificate').count - 2 }
98
95
 
99
96
  it "should yield the intermediate certificates" do
100
- pending "<receivedCertificateChain/> always has at most two <certificate/> children"
101
-
102
97
  expect(subject.intermediates).to be_a(Array).and(all(be_kind_of(SSLyze::XML::Certinfo::Certificate)))
103
98
  end
104
99
  end
@@ -28,8 +28,6 @@ describe SSLyze::XML::HTTPHeaders::HTTPStrictTransportSecurity do
28
28
  end
29
29
 
30
30
  it do
31
- pending "need an example with no 'includeSubDomains' attribute"
32
-
33
31
  expect(subject.include_sub_domains?).to be nil
34
32
  end
35
33
  end
@@ -50,8 +48,6 @@ describe SSLyze::XML::HTTPHeaders::HTTPStrictTransportSecurity do
50
48
  end
51
49
 
52
50
  it do
53
- pending "need an example where 'isSupported' is 'False'"
54
-
55
51
  expect(subject.is_supported?).to be false
56
52
  end
57
53
  end
@@ -74,8 +70,6 @@ describe SSLyze::XML::HTTPHeaders::HTTPStrictTransportSecurity do
74
70
  end
75
71
 
76
72
  it do
77
- pending "need an example with no 'maxAge' attribute"
78
-
79
73
  expect(subject.max_age).to be nil
80
74
  end
81
75
  end
@@ -98,8 +92,6 @@ describe SSLyze::XML::HTTPHeaders::HTTPStrictTransportSecurity do
98
92
  end
99
93
 
100
94
  it do
101
- pending "need an example with no 'preload' attribute"
102
-
103
95
  expect(subject.preload?).to be nil
104
96
  end
105
97
  end
@@ -5,29 +5,38 @@ require 'sslyze/xml/protocol/cipher_suite'
5
5
  describe SSLyze::XML::Protocol::CipherSuite do
6
6
  include_examples "XML specs"
7
7
 
8
- subject { described_class.new(xml.at('/document/results/target/tlsv1_2/preferredCipherSuite/cipherSuite')) }
8
+ let(:expected_name) { 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256' }
9
+
10
+ let(:xpath) { '/document/results/target/tlsv1_2/preferredCipherSuite/cipherSuite' }
9
11
 
10
12
  describe "#name" do
13
+ let(:xpath) { "#{super()}[@name='#{expected_name}']" }
14
+
11
15
  it "should parse the name attribute" do
12
- expect(subject.name).to be == 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256'
16
+ expect(subject.name).to be == expected_name
13
17
  end
14
18
  end
15
19
 
16
20
  describe "#rfc_name" do
21
+ let(:xpath) { "#{super()}[@name='#{expected_name}']" }
22
+
17
23
  it "should return the RFC cipher suite name" do
18
- expect(subject.rfc_name).to be == 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256'
24
+ expect(subject.rfc_name).to be == expected_name
19
25
  end
20
26
  end
21
27
 
22
28
  describe "#openssl_name" do
29
+ let(:openssl_name) { 'ECDHE-RSA-AES128-GCM-SHA256' }
30
+ let(:xpath) { "#{super()}[@name='#{expected_name}']" }
31
+
23
32
  it "should map the RFC name back to the OpenSSL name" do
24
- expect(subject.openssl_name).to be == 'ECDHE-RSA-AES128-GCM-SHA256'
33
+ expect(subject.openssl_name).to be == openssl_name
25
34
  end
26
35
  end
27
36
 
28
37
  describe "#connection_status" do
29
38
  it "should parse the connectionStatus attribute" do
30
- expect(subject.connection_status).to be == 'HTTP 200 OK'
39
+ expect(subject.connection_status).to be == node['connectionStatus']
31
40
  end
32
41
  end
33
42
 
@@ -44,10 +53,10 @@ describe SSLyze::XML::Protocol::CipherSuite do
44
53
  end
45
54
 
46
55
  describe "#key_exchange" do
56
+ let(:xpath) { '/document/results/target/tlsv1_2/acceptedCipherSuites/cipherSuite' }
57
+
47
58
  context "when the keyExchange child is present" do
48
- subject do
49
- described_class.new(xml.at('/document/results/target/tlsv1_2/acceptedCipherSuites/cipherSuite[keyExchange]'))
50
- end
59
+ let(:xpath) { "#{super()}[keyExchange]" }
51
60
 
52
61
  it do
53
62
  expect(subject.key_exchange).to be_kind_of(described_class::KeyExchange)
@@ -55,9 +64,7 @@ describe SSLyze::XML::Protocol::CipherSuite do
55
64
  end
56
65
 
57
66
  context "when the keyExchange object is missing" do
58
- subject do
59
- described_class.new(xml.at('/document/results/target/tlsv1_2/acceptedCipherSuites/cipherSuite[not(./keyExchange)]'))
60
- end
67
+ let(:xpath) { "#{super()}[not(./keyExchange)]" }
61
68
 
62
69
  it { expect(subject.key_exchange).to be nil }
63
70
  end
@@ -6,7 +6,7 @@ describe SSLyze::XML::Target do
6
6
  include_examples "XML specs"
7
7
 
8
8
  let(:xpath) { '/document/results/target' }
9
- let(:expected_ip) { '192.30.255.112' }
9
+ let(:expected_ip) { node['ip'] }
10
10
 
11
11
  subject { described_class.new(xml.at(xpath)) }
12
12
 
@@ -29,8 +29,6 @@ describe SSLyze::XML::Target do
29
29
  end
30
30
 
31
31
  describe "#ipaddr" do
32
- let(:xpath) { "#{super()}[@ip='#{expected_ip}']" }
33
-
34
32
  it "must parse the ip attribute" do
35
33
  expect(subject.ipaddr).to be == IPAddr.new(expected_ip)
36
34
  end
@@ -5,5 +5,8 @@ shared_examples_for "XML specs" do
5
5
  let(:path) { File.expand_path('spec/sslyze.xml') }
6
6
  let(:xml) { Nokogiri::XML(open(path)) }
7
7
 
8
- subject { SSLyze::XML.new(xml) }
8
+ let(:xpath) { '/' }
9
+ let(:node) { xml.at_xpath(xpath) }
10
+
11
+ subject { described_class.new(node) }
9
12
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-sslyze
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hal Brodigan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-12 00:00:00.000000000 Z
11
+ date: 2018-04-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rprogram
@@ -84,7 +84,6 @@ files:
84
84
  - lib/sslyze/x509/extensions/key_usage.rb
85
85
  - lib/sslyze/x509/extensions/subject_alt_name.rb
86
86
  - lib/sslyze/x509/name.rb
87
- - lib/sslyze/x509/public_key.rb
88
87
  - lib/sslyze/xml.rb
89
88
  - lib/sslyze/xml/attributes.rb
90
89
  - lib/sslyze/xml/attributes/error.rb
@@ -94,6 +93,7 @@ files:
94
93
  - lib/sslyze/xml/attributes/title.rb
95
94
  - lib/sslyze/xml/certinfo.rb
96
95
  - lib/sslyze/xml/certinfo/certificate.rb
96
+ - lib/sslyze/xml/certinfo/certificate/public_key.rb
97
97
  - lib/sslyze/xml/certinfo/certificate_validation.rb
98
98
  - lib/sslyze/xml/certinfo/certificate_validation/hostname_validation.rb
99
99
  - lib/sslyze/xml/certinfo/certificate_validation/path_validation.rb
@@ -140,7 +140,7 @@ files:
140
140
  - spec/x509/extensions/key_usage_spec.rb
141
141
  - spec/x509/extensions/subject_alt_name_spec.rb
142
142
  - spec/x509/name_spec.rb
143
- - spec/x509/public_key_spec.rb
143
+ - spec/xml/certinfo/certificate/public_key_spec.rb
144
144
  - spec/xml/certinfo/certificate_spec.rb
145
145
  - spec/xml/certinfo/certificate_validation/hostname_validation_spec.rb
146
146
  - spec/xml/certinfo/certificate_validation/path_validation_spec.rb
@@ -210,7 +210,7 @@ test_files:
210
210
  - spec/x509/extensions/key_usage_spec.rb
211
211
  - spec/x509/extensions/subject_alt_name_spec.rb
212
212
  - spec/x509/name_spec.rb
213
- - spec/x509/public_key_spec.rb
213
+ - spec/xml/certinfo/certificate/public_key_spec.rb
214
214
  - spec/xml/certinfo/certificate_spec.rb
215
215
  - spec/xml/certinfo/certificate_validation/hostname_validation_spec.rb
216
216
  - spec/xml/certinfo/certificate_validation/path_validation_spec.rb
@@ -1,53 +0,0 @@
1
- require 'delegate'
2
-
3
- module SSLyze
4
- module X509
5
- #
6
- # Wrapper class around [OpenSSL::PKey] classes that provide {#algorithm} and
7
- # {#size} methods.
8
- #
9
- # [OpenSSL::PKey]: http://www.rubydoc.info/stdlib/openssl/OpenSSL/PKey
10
- #
11
- # @since 1.0.0
12
- #
13
- class PublicKey < SimpleDelegator
14
-
15
- #
16
- # The algorithm that generated the public key.
17
- #
18
- # @return [:rsa, :dsa, :dh, :ec]
19
- #
20
- def algorithm
21
- case __getobj__
22
- when OpenSSL::PKey::RSA then :rsa
23
- when OpenSSL::PKey::DSA then :dsa
24
- when OpenSSL::PKey::DH then :dh
25
- when OpenSSL::PKey::EC then :ec
26
- end
27
- end
28
-
29
- #
30
- # The size of the public key.
31
- #
32
- # @return [Integer]
33
- # The number of bits in the public key.
34
- #
35
- # @raise [NotImplementedError]
36
- # Determining key size for `OpenSSL::PKey::EC` public keys is currently
37
- # not implemented.
38
- #
39
- def size
40
- pkey = __getobj__
41
-
42
- case pkey
43
- when OpenSSL::PKey::RSA then pkey.n.num_bits
44
- when OpenSSL::PKey::DSA then pkey.p.num_bits
45
- when OpenSSL::PKey::DH then pkey.p.num_bits
46
- when OpenSSL::PKey::EC
47
- raise(NotImplementedError,"key size for #{pkey.inspect} not implemented")
48
- end
49
- end
50
-
51
- end
52
- end
53
- end
@@ -1,113 +0,0 @@
1
- require 'spec_helper'
2
- require 'openssl'
3
-
4
- require 'sslyze/x509/public_key'
5
-
6
- describe SSLyze::X509::PublicKey do
7
- let(:key_size) { 1024 }
8
-
9
- let(:rsa_key) { OpenSSL::PKey::RSA.new(key_size) }
10
- let(:dsa_key) { OpenSSL::PKey::DSA.new(key_size) }
11
- let(:dh_key) { OpenSSL::PKey::DH.new(key_size) }
12
- let(:ec_key) { OpenSSL::PKey::EC.new }
13
-
14
- describe "#algorithm" do
15
- context "when the pkey is an OpenSSL::PKey::RSA key" do
16
- let(:pkey) { rsa_key }
17
-
18
- subject { described_class.new(pkey) }
19
-
20
- it { expect(subject.algorithm).to be :rsa }
21
- end
22
-
23
- context "when the pkey is an OpenSSL::PKey::DSA key" do
24
- let(:pkey) { dsa_key }
25
-
26
- subject { described_class.new(pkey) }
27
-
28
- it { expect(subject.algorithm).to be :dsa }
29
- end
30
-
31
- context "when the pkey is an OpenSSL::PKey::DH key" do
32
- let(:pkey) { dh_key }
33
-
34
- subject { described_class.new(pkey) }
35
-
36
- it { expect(subject.algorithm).to be :dh }
37
- end
38
-
39
- context "when the pkey is an OpenSSL::PKey::EC key" do
40
- let(:pkey) { ec_key }
41
-
42
- subject { described_class.new(pkey) }
43
-
44
- it { expect(subject.algorithm).to be :ec }
45
- end
46
- end
47
-
48
- describe "#size" do
49
- context "when the pkey is an OpenSSL::PKey::RSA key" do
50
- let(:pkey) { rsa_key }
51
-
52
- subject { described_class.new(pkey) }
53
-
54
- it "to infer the key size from pkey.n.num_bits" do
55
- expect(subject.size).to (be == pkey.n.num_bits).and(be == key_size)
56
- end
57
- end
58
-
59
- context "when the pkey is an OpenSSL::PKey::DSA key" do
60
- let(:pkey) { dsa_key }
61
-
62
- subject { described_class.new(pkey) }
63
-
64
- it "to infer the key size from pkey.p.num_bits" do
65
- expect(subject.size).to (be == pkey.p.num_bits).and(be == key_size)
66
- end
67
- end
68
-
69
- context "when the pkey is an OpenSSL::PKey::DH key" do
70
- let(:pkey) { dh_key }
71
-
72
- subject { described_class.new(pkey) }
73
-
74
- it "to infer the key size from pkey.p.num_bits" do
75
- expect(subject.size).to (be == pkey.p.num_bits).and(be == key_size)
76
- end
77
- end
78
-
79
- context "when the pkey is an OpenSSL::PKey::EC key" do
80
- let(:pkey) { ec_key }
81
-
82
- subject { described_class.new(pkey) }
83
-
84
- it do
85
- expect { subject.size }.to raise_error(NotImplementedError)
86
- end
87
- end
88
- end
89
-
90
- describe "#to_der" do
91
- let(:pkey) { rsa_key }
92
-
93
- subject { described_class.new(pkey) }
94
-
95
- it "should call the public key's #to_der method" do
96
- expect(pkey).to receive(:to_der)
97
-
98
- subject.to_der
99
- end
100
- end
101
-
102
- describe "#to_text" do
103
- let(:pkey) { rsa_key }
104
-
105
- subject { described_class.new(pkey) }
106
-
107
- it "should call the public key's #to_text method" do
108
- expect(pkey).to receive(:to_text)
109
-
110
- subject.to_text
111
- end
112
- end
113
- end