ruby-sslyze 0.1.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.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/.document +3 -0
  3. data/.gitignore +4 -0
  4. data/.rspec +1 -0
  5. data/.travis.yml +19 -0
  6. data/.yardopts +1 -0
  7. data/ChangeLog.md +8 -0
  8. data/Gemfile +18 -0
  9. data/LICENSE.txt +20 -0
  10. data/README.md +70 -0
  11. data/Rakefile +23 -0
  12. data/lib/sslyze.rb +3 -0
  13. data/lib/sslyze/cert_info.rb +55 -0
  14. data/lib/sslyze/certificate.rb +139 -0
  15. data/lib/sslyze/certificate/domain_name.rb +77 -0
  16. data/lib/sslyze/certificate/extensions.rb +127 -0
  17. data/lib/sslyze/certificate/extensions/authority_information_access.rb +38 -0
  18. data/lib/sslyze/certificate/extensions/extension.rb +26 -0
  19. data/lib/sslyze/certificate/extensions/x509v3_basic_constraints.rb +60 -0
  20. data/lib/sslyze/certificate/extensions/x509v3_certificate_policies.rb +50 -0
  21. data/lib/sslyze/certificate/extensions/x509v3_crl_distribution_points.rb +32 -0
  22. data/lib/sslyze/certificate/extensions/x509v3_extended_key_usage.rb +32 -0
  23. data/lib/sslyze/certificate/extensions/x509v3_key_usage.rb +50 -0
  24. data/lib/sslyze/certificate/extensions/x509v3_subject_alternative_name.rb +71 -0
  25. data/lib/sslyze/certificate/issuer.rb +56 -0
  26. data/lib/sslyze/certificate/public_key.rb +9 -0
  27. data/lib/sslyze/certificate/subject.rb +117 -0
  28. data/lib/sslyze/certificate/subject_public_key_info.rb +53 -0
  29. data/lib/sslyze/certificate/validity.rb +9 -0
  30. data/lib/sslyze/certificate_chain.rb +89 -0
  31. data/lib/sslyze/certificate_validation.rb +44 -0
  32. data/lib/sslyze/cipher_suite.rb +237 -0
  33. data/lib/sslyze/key_exchange.rb +106 -0
  34. data/lib/sslyze/ocsp_response.rb +87 -0
  35. data/lib/sslyze/program.rb +66 -0
  36. data/lib/sslyze/protocol.rb +133 -0
  37. data/lib/sslyze/target.rb +295 -0
  38. data/lib/sslyze/task.rb +65 -0
  39. data/lib/sslyze/types.rb +17 -0
  40. data/lib/sslyze/version.rb +4 -0
  41. data/lib/sslyze/xml.rb +139 -0
  42. data/ruby-sslyze.gemspec +24 -0
  43. data/spec/cert_info_spec.rb +29 -0
  44. data/spec/certificate/subject_name_spec.rb +72 -0
  45. data/spec/certificate_chain_spec.rb +61 -0
  46. data/spec/certificate_spec.rb +330 -0
  47. data/spec/certificate_validation_spec.rb +27 -0
  48. data/spec/cipher_suite_spec.rb +50 -0
  49. data/spec/issuer_spec.rb +33 -0
  50. data/spec/key_exchange_spec.rb +97 -0
  51. data/spec/ocsp_response_spec.rb +59 -0
  52. data/spec/protocol_spec.rb +99 -0
  53. data/spec/spec_helper.rb +9 -0
  54. data/spec/sslyze.xml +2798 -0
  55. data/spec/sslyze_spec.rb +8 -0
  56. data/spec/subject_public_key_info_spec.rb +35 -0
  57. data/spec/subject_spec.rb +67 -0
  58. data/spec/target_spec.rb +176 -0
  59. data/spec/xml_examples.rb +9 -0
  60. data/spec/xml_spec.rb +72 -0
  61. metadata +162 -0
@@ -0,0 +1,65 @@
1
+ require 'rprogram/task'
2
+
3
+ module SSLyze
4
+ #
5
+ # Represents options for {Program}.
6
+ #
7
+ class Task < RProgram::Task
8
+
9
+ # Options:
10
+ long_option flag: '--version'
11
+ long_option flag: '--help'
12
+ long_option flag: '--xml_out'
13
+ long_option flag: '--targets_in'
14
+ long_option flag: '--timeout'
15
+ long_option flag: '--nb_retries'
16
+ long_option flag: '--https_tunnel'
17
+ long_option flag: '--starttls'
18
+ long_option flag: '--xmpp_to'
19
+ long_option flag: '--sni'
20
+ long_option flag: '--regular'
21
+
22
+ # Client certificate support:
23
+ long_option flag: '--cert'
24
+ long_option flag: '--certfrom'
25
+ long_option flag: '--key'
26
+ long_option flag: '--keyfrom'
27
+ long_option flag: '--pass'
28
+
29
+ # PluginHeartbleed:
30
+ long_option flag: '--heartbleed'
31
+
32
+ # PluginOpenSSLCipherSuites:
33
+ # Scans the server(s) for supported OpenSSL cipher suites.
34
+ long_option flag: '--sslv2'
35
+ long_option flag: '--sslv3'
36
+ long_option flag: '--tlsv1'
37
+ long_option flag: '--tlsv1_1'
38
+ long_option flag: '--tlsv1_2'
39
+ long_option flag: '--http_get'
40
+ long_option flag: '--hide_rejected_ciphers'
41
+
42
+ # PluginSessionRenegotiation:
43
+ long_option flag: '--reneg'
44
+
45
+ # PluginCertInfo:
46
+ long_option flag: '--certinfo'
47
+
48
+ # PluginHSTS:
49
+ long_option flag: '--hsts'
50
+
51
+ # PluginSessionResumption:
52
+ # Analyzes the target server's SSL session resumption capabilities.
53
+ long_option flag: '--resum'
54
+ long_option flag: '--resum_rate'
55
+
56
+ # PluginChromeSha1Deprecation:
57
+ long_option flag: '--chrome_sha1'
58
+
59
+ # PluginCompression:
60
+ long_option flag: '--compression'
61
+
62
+ non_option name: :targets, tailing: true
63
+
64
+ end
65
+ end
@@ -0,0 +1,17 @@
1
+ module SSLyze
2
+ module Types
3
+ # Maps `"True"` and `"False"` to boolean values.
4
+ Boolean = {
5
+ 'True' => true,
6
+ 'False' => false
7
+ }
8
+
9
+ # Maps `"None"` to `nil`
10
+ None = proc { |value|
11
+ case value
12
+ when 'None' then nil
13
+ else value
14
+ end
15
+ }
16
+ end
17
+ end
@@ -0,0 +1,4 @@
1
+ module SSLyze
2
+ # ruby-sslyze version
3
+ VERSION = "0.1.0"
4
+ end
data/lib/sslyze/xml.rb ADDED
@@ -0,0 +1,139 @@
1
+ require 'sslyze/target'
2
+ require 'sslyze/types'
3
+ require 'nokogiri'
4
+
5
+ module SSLyze
6
+ #
7
+ # Represents the XML output from sslyze.
8
+ #
9
+ class XML
10
+
11
+ include Types
12
+
13
+ #
14
+ # Initializes the XML.
15
+ #
16
+ # @param [Nokogiri::XML::Document] doc
17
+ # The XML document.
18
+ #
19
+ def initialize(doc)
20
+ @doc = doc
21
+ end
22
+
23
+ #
24
+ # Parses the XML.
25
+ #
26
+ # @param [String] xml
27
+ # The raw XML.
28
+ #
29
+ # @return [XML]
30
+ #
31
+ def self.parse(xml)
32
+ new(Nokogiri::XML.parse(xml))
33
+ end
34
+
35
+ #
36
+ # Opens the XML file.
37
+ #
38
+ # @param [String] path
39
+ # Path to the XML file.
40
+ #
41
+ # @return [XML]
42
+ #
43
+ def self.open(path)
44
+ new(Nokogiri::XML(File.open(path)))
45
+ end
46
+
47
+ #
48
+ # The version of the XML output.
49
+ #
50
+ # @return [String]
51
+ #
52
+ def version
53
+ @version ||= @doc.at('/document/@SSLyzeVersion').value.split(' ',2).last
54
+ end
55
+
56
+ #
57
+ # The default timeout used.
58
+ #
59
+ # @return [Integer]
60
+ #
61
+ def default_timeout
62
+ @default_time ||= @doc.at('/document/results/@defaultTimeout').value.to_i
63
+ end
64
+
65
+ #
66
+ # Whether an HTTPS tunnel was used.
67
+ #
68
+ # @return [Boolean]
69
+ #
70
+ def https_tunnel
71
+ @https_tunnel ||= Boolean[@doc.at('/document/results/@httpsTunnel').value]
72
+ end
73
+
74
+ #
75
+ # Specifies whether STARTTLS was enabled.
76
+ #
77
+ # @return [Boolean]
78
+ #
79
+ def start_tls
80
+ @start_tls ||= Boolean[@doc.at('/document/results/@startTLS').value]
81
+ end
82
+
83
+ #
84
+ # Duration of the scan.
85
+ #
86
+ # @return [Float]
87
+ #
88
+ def total_scan_time
89
+ @start_tls ||= @doc.at('/document/results/@totalScanTime').value.to_f
90
+ end
91
+
92
+ #
93
+ # The invalid targets.
94
+ #
95
+ # @raise [NotImplementedError]
96
+ #
97
+ def invalid_targets
98
+ raise(NotImplementedError,"#{self.class}##{__method__} not implemented")
99
+ end
100
+
101
+ #
102
+ # Enumerates over each target.
103
+ #
104
+ # @yield [target]
105
+ #
106
+ # @yieldparam [Target] target
107
+ #
108
+ # @return [Enumerator]
109
+ #
110
+ def each_target
111
+ return enum_for(__method__) unless block_given?
112
+
113
+ @doc.search('/document/results/target').each do |target|
114
+ yield Target.new(target)
115
+ end
116
+ end
117
+
118
+ alias each each_target
119
+
120
+ #
121
+ # @return [Array<Target>]
122
+ #
123
+ # @see #each_target
124
+ #
125
+ def targets
126
+ each_target.to_a
127
+ end
128
+
129
+ #
130
+ # The first target.
131
+ #
132
+ # @return [Target, nil]
133
+ #
134
+ def target
135
+ each_target.first
136
+ end
137
+
138
+ end
139
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require File.expand_path('../lib/sslyze/version', __FILE__)
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = "ruby-sslyze"
7
+ gem.version = SSLyze::VERSION
8
+ gem.summary = %q{Ruby interface to sslyze}
9
+ gem.description = %q{A ruby interface to the sslyze python utility}
10
+ gem.license = "MIT"
11
+ gem.authors = ["Hal Brodigan"]
12
+ gem.email = "hal@trailofbits.com"
13
+ gem.homepage = "https://github.com/trailofbits/ruby-sslyze#readme"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ['lib']
19
+
20
+ gem.add_dependency 'rprogram', '~> 0.3'
21
+ gem.add_dependency 'nokogiri', '~> 1.0'
22
+
23
+ gem.add_development_dependency 'bundler', '~> 1.0'
24
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+ require 'xml_examples'
3
+ require 'sslyze/cert_info'
4
+
5
+ describe SSLyze::CertInfo do
6
+ include_examples "XML specs"
7
+
8
+ subject { described_class.new(xml.at('/document/results/target/certinfo')) }
9
+
10
+ describe "#chain" do
11
+ it "should return a CertificateChain object" do
12
+ expect(subject.chain).to be_a(CertificateChain)
13
+ end
14
+ end
15
+
16
+ describe "#validation" do
17
+ it "should return a CertificateValidation element" do
18
+ expect(subject.validation).to be_kind_of(CertificateValidation)
19
+ end
20
+ end
21
+
22
+ describe "#ocsp_response" do
23
+ subject { described_class.new(xml.at('/document/results/target/certinfo[ocspStapling/ocspResponse]')) }
24
+
25
+ it "should return a OCSPResponse object" do
26
+ expect(subject.ocsp_response).to be_kind_of(OCSPResponse)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+ require 'sslyze/certificate/domain_name'
3
+
4
+ describe SSLyze::Certificate::DomainName do
5
+ let(:name) { 'twitter.com' }
6
+
7
+ subject { described_class.new(name) }
8
+
9
+ describe "#==" do
10
+ context "when the domain names are the same" do
11
+ let(:other) { described_class.new(name) }
12
+
13
+ it "should return true" do
14
+ expect(subject == other).to be true
15
+ end
16
+ end
17
+
18
+ context "when the domain names are different" do
19
+ let(:other) { described_class.new(name + 'XXX') }
20
+
21
+ it "should return true" do
22
+ expect(subject == other).to be false
23
+ end
24
+ end
25
+ end
26
+
27
+ describe "#include?" do
28
+ context "when the domain name is literal" do
29
+ it "should compare the given domain to the domain name" do
30
+ expect(subject.include?(name)).to be true
31
+ end
32
+ end
33
+
34
+ context "when the domain name has a wildcard" do
35
+ let(:wildcard) { "*.#{name}" }
36
+
37
+ subject { described_class.new(wildcard) }
38
+
39
+ it "should match the domain" do
40
+ expect(subject.include?(name)).to be true
41
+ end
42
+
43
+ it "should match any sub-domain" do
44
+ expect(subject.include?("foo.#{name}")).to be true
45
+ end
46
+ end
47
+ end
48
+
49
+ describe "#to_s" do
50
+ it "should return the domain name" do
51
+ expect(subject.to_s).to be name
52
+ end
53
+ end
54
+
55
+ describe "#to_str" do
56
+ it "should return the domain name" do
57
+ expect(subject.to_str).to be name
58
+ end
59
+ end
60
+
61
+ describe "#inspect" do
62
+ subject { super().inspect }
63
+
64
+ it "should include the class name" do
65
+ expect(subject).to include(described_class.name)
66
+ end
67
+
68
+ it "should include the domain name" do
69
+ expect(subject).to include(name)
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+ require 'xml_examples'
3
+ require 'sslyze/certificate_chain'
4
+
5
+ describe SSLyze::CertificateChain do
6
+ include_examples "XML specs"
7
+
8
+ subject { described_class.new(xml.at('/document/results/target/certinfo/certificateChain')) }
9
+
10
+ describe "#each" do
11
+ context "when given a block" do
12
+ it "should yield Certificate objects" do
13
+ expect { |b|
14
+ subject.each(&b)
15
+ }.to yield_successive_args(Certificate, Certificate)
16
+ end
17
+ end
18
+
19
+ context "when not given a block" do
20
+ it "should return an Enumerator" do
21
+ expect(subject.each).to be_kind_of(Enumerator)
22
+ end
23
+ end
24
+ end
25
+
26
+ describe "#leaf" do
27
+ it "should return a Certificate with position leaf" do
28
+ expect(subject.leaf).to be_a(Certificate)
29
+ expect(subject.leaf.position).to be :leaf
30
+ end
31
+ end
32
+
33
+ describe "#each_intermediate" do
34
+ context "when given a block" do
35
+ it "should return Certificates with position intermediate" do
36
+ expect { |b|
37
+ subject.each_intermediate(&b)
38
+ }.to yield_successive_args(Certificate)
39
+ end
40
+ end
41
+
42
+ context "when not given a block" do
43
+ it "should return an Enumerator" do
44
+ expect(subject.each_intermediate).to be_kind_of(Enumerator)
45
+ end
46
+ end
47
+ end
48
+
49
+ describe "#intermediate" do
50
+ it "should return all intermediate certificates" do
51
+ expect(subject.intermediate).to all(be_kind_of(Certificate))
52
+ end
53
+ end
54
+
55
+ describe "#root" do
56
+ it "should find the last intermediate certificate" do
57
+ expect(subject.root.sha1_fingerprint).to be == subject.intermediate.to_a.last.sha1_fingerprint
58
+ end
59
+ end
60
+
61
+ end
@@ -0,0 +1,330 @@
1
+ require 'spec_helper'
2
+ require 'xml_examples'
3
+ require 'sslyze/certificate'
4
+
5
+ describe SSLyze::Certificate do
6
+ include_examples "XML specs"
7
+
8
+ subject { described_class.new(xml.at('/document/results/target/certinfo/certificateChain/certificate')) }
9
+
10
+ describe "#position" do
11
+ it "should parse the position attribute" do
12
+ expect(subject.position).to be :leaf
13
+ end
14
+ end
15
+
16
+ describe "#sha1_fingerprint" do
17
+ it "should parse the sha1Fingerprint attribute" do
18
+ expect(subject.sha1_fingerprint).to be == 'a0c4a74600eda72dc0becb9a8cb607ca58ee745e'
19
+ end
20
+ end
21
+
22
+ describe "#as_pem" do
23
+ it "should parse the asPEM element" do
24
+ expect(subject.as_pem).to be == %{
25
+ -----BEGIN CERTIFICATE-----
26
+ MIIF4DCCBMigAwIBAgIQDACTENIG2+M3VTWAEY3chzANBgkqhkiG9w0BAQsFADB1
27
+ MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
28
+ d3cuZGlnaWNlcnQuY29tMTQwMgYDVQQDEytEaWdpQ2VydCBTSEEyIEV4dGVuZGVk
29
+ IFZhbGlkYXRpb24gU2VydmVyIENBMB4XDTE0MDQwODAwMDAwMFoXDTE2MDQxMjEy
30
+ MDAwMFowgfAxHTAbBgNVBA8MFFByaXZhdGUgT3JnYW5pemF0aW9uMRMwEQYLKwYB
31
+ BAGCNzwCAQMTAlVTMRkwFwYLKwYBBAGCNzwCAQITCERlbGF3YXJlMRAwDgYDVQQF
32
+ Ewc1MTU3NTUwMRcwFQYDVQQJEw41NDggNHRoIFN0cmVldDEOMAwGA1UEERMFOTQx
33
+ MDcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
34
+ YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxHaXRIdWIsIEluYy4xEzARBgNVBAMTCmdp
35
+ dGh1Yi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx1Nw8r/3z
36
+ Tu3BZ63myyLot+KrKPL33GJwCNEMr9YWaiGwNksXDTZjBK6/6iBRlWVm8r+5TaQM
37
+ Kev1FbHoNbNwEJTVG1m0Jg/Wg1dZneF8Cd3gE8pNb0Obzc+HOhWnhd1mg+2TDP4r
38
+ bTgceYiQz61YGC1R0cKj8keMbzgJubjvTJMLy4OUh+rgo7XZe5trD0P5yu6ADSin
39
+ dvEl9ME1PPZ0rd5qM4J73P1LdqfC7vJqv6kkpl/nLnwO28N0c/p+xtjPYOs2ViG2
40
+ wYq4JIJNeCS66R2hiqeHvmYlab++O3JuT+DkhSUIsZGJuNZ0ZXabLE9iH6H6Or6c
41
+ JL+fyrDFwGeNAgMBAAGjggHuMIIB6jAfBgNVHSMEGDAWgBQ901Cl1qCt7vNKYApl
42
+ 0yHU+PjWDzAdBgNVHQ4EFgQUakOQfTuYFHJSlTqqKApD+FF+06YwJQYDVR0RBB4w
43
+ HIIKZ2l0aHViLmNvbYIOd3d3LmdpdGh1Yi5jb20wDgYDVR0PAQH/BAQDAgWgMB0G
44
+ A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5o
45
+ dHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1ldi1zZXJ2ZXItZzEuY3JsMDSg
46
+ MqAwhi5odHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1ldi1zZXJ2ZXItZzEu
47
+ Y3JsMEIGA1UdIAQ7MDkwNwYJYIZIAYb9bAIBMCowKAYIKwYBBQUHAgEWHGh0dHBz
48
+ Oi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgYgGCCsGAQUFBwEBBHwwejAkBggrBgEF
49
+ BQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMFIGCCsGAQUFBzAChkZodHRw
50
+ Oi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEyRXh0ZW5kZWRWYWxp
51
+ ZGF0aW9uU2VydmVyQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD
52
+ ggEBAG/nbcuC8++QhwnXDxUiLIz+06scipbbXRJd0XjAMbD/RciJ9wiYUhcfTEsg
53
+ ZGpt21DXEL5+q/4vgNipSlhBaYFyGQiDm5IQTmIte0ZwQ26jUxMf4pOmI1v3kj43
54
+ FHU7uUskQS6lPUgND5nqHkKXxv6V2qtHmssrA9YNQMEK93ga2rWDpK21mUkgLviT
55
+ PB5sPdE7IzprOCp+Ynpf3RcFddAkXb6NqJoQRPrStMrv19C1dqUmJRwIQdhkkqev
56
+ ff6IQDlhC8BIMKmCNK33cEYDfDWROtW7JNgBvBTwww8jO1gyug8SbGZ6bZ3k8OV8
57
+ XX4C2NesiZcLYbc2n7B9O+63M2k=
58
+ -----END CERTIFICATE-----
59
+ }.strip
60
+ end
61
+ end
62
+
63
+ describe "#subject_public_key_info" do
64
+ it "must return a Certificate::SubjectPublicKeyInfo object" do
65
+ expect(subject.subject_public_key_info).to be_kind_of(described_class::SubjectPublicKeyInfo)
66
+ end
67
+ end
68
+
69
+ describe "#version" do
70
+ it "should parse the version element" do
71
+ expect(subject.version).to be == 2
72
+ end
73
+ end
74
+
75
+ describe "#extensions" do
76
+ subject { super().extensions }
77
+
78
+ it "should return an Extensions object" do
79
+ expect(subject).to be_kind_of(described_class::Extensions)
80
+ end
81
+
82
+ describe "#x509v3_subject_key_identifier" do
83
+ subject { super().x509v3_subject_key_identifier }
84
+
85
+ it "should parse the X509v3SubjectKeyIdentifier element" do
86
+ expect(subject).to be == '6A:43:90:7D:3B:98:14:72:52:95:3A:AA:28:0A:43:F8:51:7E:D3:A6'
87
+ end
88
+ end
89
+
90
+ describe "#x509v3_extended_key_usage" do
91
+ subject { super().x509v3_extended_key_usage }
92
+
93
+ it "should return a X509v3ExtendedKeyUsage object" do
94
+ expect(subject).to be_kind_of(described_class::Extensions::X509v3ExtendedKeyUsage)
95
+ end
96
+
97
+ describe "#tls_web_client_authentication" do
98
+ subject { super().tls_web_client_authentication }
99
+
100
+ it "should parse the TLSWebClientAuthentication element" do
101
+ expect(subject).to be == ''
102
+ end
103
+ end
104
+
105
+ describe "#tls_web_server_authentication" do
106
+ subject { super().tls_web_server_authentication }
107
+
108
+ it "should parse the TLSWebServerAuthentication element" do
109
+ expect(subject).to be == ''
110
+ end
111
+ end
112
+ end
113
+
114
+ describe "#authority_information_access" do
115
+ subject { super().authority_information_access }
116
+
117
+ it "should return an AuthorityInformationAccess object" do
118
+ expect(subject).to be_kind_of(described_class::Extensions::AuthorityInformationAccess)
119
+ end
120
+
121
+ describe "#ca_issuers" do
122
+ subject { super().ca_issuers }
123
+
124
+ it "should parse the CAIssuers element" do
125
+ expect(subject).to be == [
126
+ URI('http://cacerts.digicert.com/DigiCertSHA2ExtendedValidationServerCA.crt')
127
+ ]
128
+ end
129
+ end
130
+
131
+ describe "#ocsp" do
132
+ subject { super().ocsp }
133
+
134
+ it "should parse the OCSP element" do
135
+ expect(subject).to be == [
136
+ URI('http://ocsp.digicert.com')
137
+ ]
138
+ end
139
+ end
140
+ end
141
+
142
+ describe "#x509v3_crl_distribution_points" do
143
+ subject { super().x509v3_crl_distribution_points }
144
+
145
+ it "should return a X509v3CRLDistributionPoints object" do
146
+ expect(subject).to be_kind_of(described_class::Extensions::X509v3CRLDistributionPoints)
147
+ end
148
+
149
+ describe "#full_name" do
150
+ subject { super().full_name }
151
+
152
+ it "should parse the FullName element" do
153
+ expect(subject).to be == ['', '']
154
+ end
155
+ end
156
+
157
+ describe "#uri" do
158
+ subject { super().uri }
159
+
160
+ it "should parse the URI element" do
161
+ expect(subject).to be == [
162
+ URI('http://crl3.digicert.com/sha2-ev-server-g1.crl'),
163
+ URI('http://crl4.digicert.com/sha2-ev-server-g1.crl')
164
+ ]
165
+ end
166
+ end
167
+ end
168
+
169
+ describe "#x509v3_basic_constraints" do
170
+ subject { super().x509v3_basic_constraints }
171
+
172
+ it "should parse the X509v3BasicConstraints element" do
173
+ expect(subject).to be_kind_of(described_class::Extensions::X509v3BasicConstraints)
174
+ end
175
+
176
+ describe "#ca?" do
177
+ subject { super().ca? }
178
+
179
+ it "should parse the 'CA:' constraint" do
180
+ expect(subject).to be false
181
+ end
182
+ end
183
+
184
+ describe "#path_length" do
185
+ subject { super().path_length }
186
+
187
+ pending "need data" do
188
+ it "should parse the 'pathLen:' constraint" do
189
+ expect(subject).to be == 0
190
+ end
191
+ end
192
+ end
193
+ end
194
+
195
+ describe "#x509v3_key_usage" do
196
+ subject { super().x509v3_key_usage }
197
+
198
+ it "should return a X509v3KeyUsage object" do
199
+ expect(subject).to be_kind_of(described_class::Extensions::X509v3KeyUsage)
200
+ end
201
+
202
+ describe "#key_encipherment" do
203
+ subject { super().key_encipherment }
204
+
205
+ it "should parse the KeyEncipherment element" do
206
+ expect(subject).to be == ''
207
+ end
208
+ end
209
+
210
+ describe "#digital_signature" do
211
+ subject { super().digital_signature }
212
+
213
+ it "should parse the DigitalSignature element" do
214
+ expect(subject).to be == ''
215
+ end
216
+ end
217
+ end
218
+
219
+ describe "#x509v3_subject_alternative_name" do
220
+ subject { super().x509v3_subject_alternative_name }
221
+
222
+ it "should parse the X509v3SubjectAlternativeName elements" do
223
+ expect(subject).to be_kind_of(described_class::Extensions::X509v3SubjectAlternativeName)
224
+ end
225
+
226
+ describe "#dns" do
227
+ subject { super().dns }
228
+
229
+ it "should parse the DNS/listEntry elements" do
230
+ expect(subject).to be == [
231
+ described_class::DomainName.new('github.com'),
232
+ described_class::DomainName.new('www.github.com')
233
+ ]
234
+ end
235
+ end
236
+ end
237
+
238
+ describe "#x509v3_authority_key_identifier" do
239
+ subject { super().x509v3_authority_key_identifier }
240
+
241
+ it "should parse the X509v3AuthorityKeyIdentifier element" do
242
+ expect(subject).to be == 'keyid:3D:D3:50:A5:D6:A0:AD:EE:F3:4A:60:0A:65:D3:21:D4:F8:F8:D6:0F'
243
+ end
244
+ end
245
+
246
+ describe "#x509v3_certificate_policies" do
247
+ subject { super().x509v3_certificate_policies }
248
+
249
+ it "should return a X509v3CertificatePolicies object" do
250
+ expect(subject).to be_kind_of(described_class::Extensions::X509v3CertificatePolicies)
251
+ end
252
+
253
+ describe "#policy" do
254
+ subject { super().policy }
255
+
256
+ it "should parse the Policy element" do
257
+ expect(subject).to be == ['2.16.840.1.114412.2.1']
258
+ end
259
+ end
260
+
261
+ describe "#explicit_text" do
262
+ subject { super().explicit_text }
263
+
264
+ it "should parse the ExplicitText element" do
265
+ expect(subject).to be == []
266
+ end
267
+ end
268
+
269
+ describe "#cps" do
270
+ subject { super().cps }
271
+
272
+ it "should parse the CPS element" do
273
+ expect(subject).to be == ['https://www.digicert.com/CPS']
274
+ end
275
+ end
276
+
277
+ describe "#user_notice" do
278
+ subject { super().user_notice }
279
+
280
+ it "should parse the UserNotice element" do
281
+ expect(subject).to be == []
282
+ end
283
+ end
284
+ end
285
+ end
286
+
287
+ describe "#signature_value" do
288
+ it "should parse the signatureValue element" do
289
+ expect(subject.signature_value).to be == %{6f:e7:6d:cb:82:f3:ef:90:87:09:d7:0f:15:22:2c:8c:fe:d3:ab:1c:8a:96:db:5d:12:5d:d1:78:c0:31:b0:ff:45:c8:89:f7:08:98:52:17:1f:4c:4b:20:64:6a:6d:db:50:d7:10:be:7e:ab:fe:2f:80:d8:a9:4a:58:41:69:81:72:19:08:83:9b:92:10:4e:62:2d:7b:46:70:43:6e:a3:53:13:1f:e2:93:a6:23:5b:f7:92:3e:37:14:75:3b:b9:4b:24:41:2e:a5:3d:48:0d:0f:99:ea:1e:42:97:c6:fe:95:da:ab:47:9a:cb:2b:03:d6:0d:40:c1:0a:f7:78:1a:da:b5:83:a4:ad:b5:99:49:20:2e:f8:93:3c:1e:6c:3d:d1:3b:23:3a:6b:38:2a:7e:62:7a:5f:dd:17:05:75:d0:24:5d:be:8d:a8:9a:10:44:fa:d2:b4:ca:ef:d7:d0:b5:76:a5:26:25:1c:08:41:d8:64:92:a7:af:7d:fe:88:40:39:61:0b:c0:48:30:a9:82:34:ad:f7:70:46:03:7c:35:91:3a:d5:bb:24:d8:01:bc:14:f0:c3:0f:23:3b:58:32:ba:0f:12:6c:66:7a:6d:9d:e4:f0:e5:7c:5d:7e:02:d8:d7:ac:89:97:0b:61:b7:36:9f:b0:7d:3b:ee:b7:33:69}
290
+ end
291
+ end
292
+
293
+ describe "#signature_algorithm" do
294
+ it "should parse the signatureAlgorithm element" do
295
+ expect(subject.signature_algorithm).to be == 'sha256WithRSAEncryption'
296
+ end
297
+ end
298
+
299
+ describe "#serial_number" do
300
+ it "should parse the serialNumber element" do
301
+ expect(subject.serial_number).to be == '0C009310D206DBE337553580118DDC87'
302
+ end
303
+ end
304
+
305
+ describe "#subject" do
306
+ it "should return a Subject object" do
307
+ expect(subject.subject).to be_kind_of(described_class::Subject)
308
+ end
309
+ end
310
+
311
+ describe "#validity" do
312
+ it "should return a Validity object" do
313
+ expect(subject.validity).to be_kind_of(described_class::Validity)
314
+ end
315
+
316
+ it "should parse the validity/notAfter element" do
317
+ expect(subject.validity.not_after).to be == Date.parse('Apr 12 12:00:00 2016 GMT')
318
+ end
319
+
320
+ it "should parse the validity/notBefore element" do
321
+ expect(subject.validity.not_before).to be == Date.parse('Apr 8 00:00:00 2014 GMT')
322
+ end
323
+ end
324
+
325
+ describe "#issuer" do
326
+ it "should return an Issuer object" do
327
+ expect(subject.issuer).to be_kind_of(described_class::Issuer)
328
+ end
329
+ end
330
+ end