ruby-sslyze 1.1.0 → 1.2.0

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