ruby-sslyze 0.2.1 → 1.0.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 (146) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -4
  3. data/.travis.yml +15 -7
  4. data/ChangeLog.md +29 -12
  5. data/Gemfile +3 -2
  6. data/LICENSE.txt +1 -1
  7. data/README.md +5 -5
  8. data/Rakefile +1 -1
  9. data/lib/sslyze/cipher_suites.rb +176 -0
  10. data/lib/sslyze/program.rb +8 -8
  11. data/lib/sslyze/task.rb +40 -33
  12. data/lib/sslyze/version.rb +1 -1
  13. data/lib/sslyze/{certificate/domain_name.rb → x509/domain.rb} +5 -3
  14. data/lib/sslyze/x509/extension.rb +15 -0
  15. data/lib/sslyze/x509/extension_set.rb +140 -0
  16. data/lib/sslyze/x509/extensions.rb +6 -0
  17. data/lib/sslyze/x509/extensions/basic_constraints.rb +41 -0
  18. data/lib/sslyze/x509/extensions/certificate_policies.rb +108 -0
  19. data/lib/sslyze/x509/extensions/crl_distribution_points.rb +47 -0
  20. data/lib/sslyze/x509/extensions/extended_key_usage.rb +58 -0
  21. data/lib/sslyze/x509/extensions/key_usage.rb +66 -0
  22. data/lib/sslyze/x509/extensions/subject_alt_name.rb +144 -0
  23. data/lib/sslyze/x509/name.rb +194 -0
  24. data/lib/sslyze/x509/public_key.rb +53 -0
  25. data/lib/sslyze/xml.rb +26 -37
  26. data/lib/sslyze/xml/attributes.rb +5 -0
  27. data/lib/sslyze/xml/attributes/error.rb +30 -0
  28. data/lib/sslyze/xml/attributes/exception.rb +30 -0
  29. data/lib/sslyze/xml/attributes/is_supported.rb +29 -0
  30. data/lib/sslyze/xml/attributes/is_vulnerable.rb +29 -0
  31. data/lib/sslyze/xml/attributes/title.rb +31 -0
  32. data/lib/sslyze/xml/certinfo.rb +67 -0
  33. data/lib/sslyze/xml/certinfo/certificate.rb +202 -0
  34. data/lib/sslyze/xml/certinfo/certificate_validation.rb +69 -0
  35. data/lib/sslyze/xml/certinfo/certificate_validation/hostname_validation.rb +54 -0
  36. data/lib/sslyze/xml/certinfo/certificate_validation/path_validation.rb +84 -0
  37. data/lib/sslyze/xml/certinfo/certificate_validation/verified_certificate_chain.rb +41 -0
  38. data/lib/sslyze/xml/certinfo/has_certificates.rb +102 -0
  39. data/lib/sslyze/xml/certinfo/ocsp_stapling.rb +45 -0
  40. data/lib/sslyze/xml/certinfo/ocsp_stapling/ocsp_response.rb +87 -0
  41. data/lib/sslyze/xml/certinfo/received_certificate_chain.rb +48 -0
  42. data/lib/sslyze/xml/compression.rb +33 -0
  43. data/lib/sslyze/xml/compression/compression_method.rb +38 -0
  44. data/lib/sslyze/xml/fallback.rb +34 -0
  45. data/lib/sslyze/xml/fallback/tls_fallback_scsv.rb +27 -0
  46. data/lib/sslyze/xml/heartbleed.rb +38 -0
  47. data/lib/sslyze/xml/heartbleed/openssl_heartbleed.rb +29 -0
  48. data/lib/sslyze/xml/http_headers.rb +42 -0
  49. data/lib/sslyze/xml/http_headers/http_public_key_pinning.rb +121 -0
  50. data/lib/sslyze/xml/http_headers/http_strict_transport_security.rb +59 -0
  51. data/lib/sslyze/xml/invalid_target.rb +33 -0
  52. data/lib/sslyze/xml/openssl_ccs.rb +34 -0
  53. data/lib/sslyze/xml/openssl_ccs/openssl_ccs_injection.rb +26 -0
  54. data/lib/sslyze/xml/plugin.rb +27 -0
  55. data/lib/sslyze/xml/protocol.rb +143 -0
  56. data/lib/sslyze/xml/protocol/cipher_suite.rb +93 -0
  57. data/lib/sslyze/xml/protocol/cipher_suite/key_exchange.rb +127 -0
  58. data/lib/sslyze/xml/reneg.rb +28 -0
  59. data/lib/sslyze/xml/reneg/session_renegotiation.rb +51 -0
  60. data/lib/sslyze/xml/resum.rb +42 -0
  61. data/lib/sslyze/xml/resum/session_resumption_with_session_ids.rb +94 -0
  62. data/lib/sslyze/xml/resum/session_resumption_with_tls_tickets.rb +69 -0
  63. data/lib/sslyze/xml/resum_rate.rb +30 -0
  64. data/lib/sslyze/xml/target.rb +371 -0
  65. data/lib/sslyze/xml/types.rb +19 -0
  66. data/ruby-sslyze.gemspec +3 -3
  67. data/spec/spec_helper.rb +2 -4
  68. data/spec/sslyze.xml +2356 -2580
  69. data/spec/x509/domain_spec.rb +125 -0
  70. data/spec/x509/extension_set_spec.rb +208 -0
  71. data/spec/x509/extension_spec.rb +58 -0
  72. data/spec/x509/extensions/basic_constraints_spec.rb +41 -0
  73. data/spec/x509/extensions/certificate_policies_spec.rb +38 -0
  74. data/spec/x509/extensions/crl_distribution_points_spec.rb +38 -0
  75. data/spec/x509/extensions/extended_key_usage_spec.rb +58 -0
  76. data/spec/x509/extensions/key_usage_spec.rb +84 -0
  77. data/spec/x509/extensions/subject_alt_name_spec.rb +146 -0
  78. data/spec/x509/name_spec.rb +85 -0
  79. data/spec/x509/public_key_spec.rb +113 -0
  80. data/spec/xml/certinfo/certificate_spec.rb +166 -0
  81. data/spec/xml/certinfo/certificate_validation/hostname_validation_spec.rb +23 -0
  82. data/spec/xml/certinfo/certificate_validation/path_validation_spec.rb +107 -0
  83. data/spec/xml/certinfo/certificate_validation/verified_certificate_chain_spec.rb +163 -0
  84. data/spec/xml/certinfo/certificate_validation_spec.rb +40 -0
  85. data/spec/xml/certinfo/ocsp_stapling/ocsp_response_spec.rb +61 -0
  86. data/spec/xml/certinfo/ocsp_stapling_spec.rb +31 -0
  87. data/spec/xml/certinfo/received_certificate_chain_spec.rb +165 -0
  88. data/spec/xml/certinfo_spec.rb +45 -0
  89. data/spec/xml/compression/compression_method_spec.rb +23 -0
  90. data/spec/xml/compression_spec.rb +23 -0
  91. data/spec/xml/heartbleed/openssl_heartbleed_spec.rb +17 -0
  92. data/spec/xml/heartbleed_spec.rb +37 -0
  93. data/spec/xml/http_headers/http_public_key_pinning_spec.rb +73 -0
  94. data/spec/xml/http_headers/http_strict_transport_security_spec.rb +107 -0
  95. data/spec/xml/http_headers_spec.rb +63 -0
  96. data/spec/xml/invalid_target_spec.rb +23 -0
  97. data/spec/xml/plugin_examples.rb +14 -0
  98. data/spec/{key_exchange_spec.rb → xml/protocol/cipher_suite/key_exchange_spec.rb} +9 -3
  99. data/spec/xml/protocol/cipher_suite_spec.rb +66 -0
  100. data/spec/xml/protocol_spec.rb +115 -0
  101. data/spec/xml/reneg/session_renegotiation_spec.rb +23 -0
  102. data/spec/xml/reneg_spec.rb +35 -0
  103. data/spec/xml/resum/session_resumption_with_session_ids_spec.rb +103 -0
  104. data/spec/xml/resum/session_resumption_with_tls_tickets_spec.rb +121 -0
  105. data/spec/xml/resum_rate_spec.rb +30 -0
  106. data/spec/xml/resum_spec.rb +47 -0
  107. data/spec/{target_spec.rb → xml/target_spec.rb} +73 -27
  108. data/spec/xml_spec.rb +13 -21
  109. metadata +138 -61
  110. data/lib/sslyze/cert_info.rb +0 -57
  111. data/lib/sslyze/certificate.rb +0 -139
  112. data/lib/sslyze/certificate/extensions.rb +0 -127
  113. data/lib/sslyze/certificate/extensions/authority_information_access.rb +0 -38
  114. data/lib/sslyze/certificate/extensions/extension.rb +0 -26
  115. data/lib/sslyze/certificate/extensions/x509v3_basic_constraints.rb +0 -60
  116. data/lib/sslyze/certificate/extensions/x509v3_certificate_policies.rb +0 -50
  117. data/lib/sslyze/certificate/extensions/x509v3_crl_distribution_points.rb +0 -32
  118. data/lib/sslyze/certificate/extensions/x509v3_extended_key_usage.rb +0 -32
  119. data/lib/sslyze/certificate/extensions/x509v3_key_usage.rb +0 -50
  120. data/lib/sslyze/certificate/extensions/x509v3_subject_alternative_name.rb +0 -71
  121. data/lib/sslyze/certificate/issuer.rb +0 -56
  122. data/lib/sslyze/certificate/public_key.rb +0 -9
  123. data/lib/sslyze/certificate/subject.rb +0 -117
  124. data/lib/sslyze/certificate/subject_public_key_info.rb +0 -53
  125. data/lib/sslyze/certificate/validity.rb +0 -9
  126. data/lib/sslyze/certificate_chain.rb +0 -89
  127. data/lib/sslyze/certificate_validation.rb +0 -70
  128. data/lib/sslyze/cipher_suite.rb +0 -237
  129. data/lib/sslyze/invalid_target.rb +0 -35
  130. data/lib/sslyze/key_exchange.rb +0 -106
  131. data/lib/sslyze/ocsp_response.rb +0 -87
  132. data/lib/sslyze/protocol.rb +0 -133
  133. data/lib/sslyze/target.rb +0 -312
  134. data/lib/sslyze/types.rb +0 -17
  135. data/spec/cert_info_spec.rb +0 -29
  136. data/spec/certificate/subject_name_spec.rb +0 -72
  137. data/spec/certificate_chain_spec.rb +0 -61
  138. data/spec/certificate_spec.rb +0 -330
  139. data/spec/certificate_validation_spec.rb +0 -39
  140. data/spec/cipher_suite_spec.rb +0 -50
  141. data/spec/invalid_target_spec.rb +0 -21
  142. data/spec/issuer_spec.rb +0 -33
  143. data/spec/ocsp_response_spec.rb +0 -59
  144. data/spec/protocol_spec.rb +0 -99
  145. data/spec/subject_public_key_info_spec.rb +0 -35
  146. data/spec/subject_spec.rb +0 -69
@@ -0,0 +1,166 @@
1
+ require 'spec_helper'
2
+ require 'xml_examples'
3
+ require 'sslyze/xml/certinfo/certificate'
4
+
5
+ describe SSLyze::XML::Certinfo::Certificate do
6
+ include_examples "XML specs"
7
+
8
+ let(:xpath) { '/document/results/target/certinfo/receivedCertificateChain/certificate' }
9
+
10
+ subject { described_class.new(xml.at(xpath)) }
11
+
12
+ describe "#sha1_fingerprint" do
13
+ let(:expected_sha1) { 'd79f076110b39293e349ac89845b0380c19e2f8b' }
14
+
15
+ let(:xpath) { "#{super()}[@sha1Fingerprint='#{expected_sha1}']" }
16
+
17
+ it "should parse the 'sha1Fingerprint' attribute" do
18
+ expect(subject.sha1_fingerprint).to be == expected_sha1
19
+ end
20
+ end
21
+
22
+ describe "#hpkp_sha256_pin" do
23
+ let(:expected_hpkp_sha256) { 'pL1+qb9HTMRZJmuC/bB/ZI9d302BYrrqiVuRyW+DGrU=' }
24
+
25
+ let(:xpath) { "#{super()}[@hpkpSha256Pin='#{expected_hpkp_sha256}']" }
26
+
27
+ it "should parse the 'hpkpSha256Pin' attribute" do
28
+ expect(subject.hpkp_sha256_pin).to be == expected_hpkp_sha256
29
+ end
30
+ end
31
+
32
+ describe "#as_pem" do
33
+ let(:host) { 'github.com' }
34
+ let(:host_pem) do
35
+ %{-----BEGIN CERTIFICATE-----
36
+ MIIHeTCCBmGgAwIBAgIQC/20CQrXteZAwwsWyVKaJzANBgkqhkiG9w0BAQsFADB1
37
+ MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
38
+ d3cuZGlnaWNlcnQuY29tMTQwMgYDVQQDEytEaWdpQ2VydCBTSEEyIEV4dGVuZGVk
39
+ IFZhbGlkYXRpb24gU2VydmVyIENBMB4XDTE2MDMxMDAwMDAwMFoXDTE4MDUxNzEy
40
+ MDAwMFowgf0xHTAbBgNVBA8MFFByaXZhdGUgT3JnYW5pemF0aW9uMRMwEQYLKwYB
41
+ BAGCNzwCAQMTAlVTMRkwFwYLKwYBBAGCNzwCAQITCERlbGF3YXJlMRAwDgYDVQQF
42
+ Ewc1MTU3NTUwMSQwIgYDVQQJExs4OCBDb2xpbiBQIEtlbGx5LCBKciBTdHJlZXQx
43
+ DjAMBgNVBBETBTk0MTA3MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5p
44
+ YTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEVMBMGA1UEChMMR2l0SHViLCBJbmMu
45
+ MRMwEQYDVQQDEwpnaXRodWIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
46
+ CgKCAQEA54hc8pZclxgcupjiA/F/OZGRwm/ZlucoQGTNTKmBEgNsrn/mxhngWmPw
47
+ bAvUaLP//T79Jc+1WXMpxMiz9PK6yZRRFuIo0d2bx423NA6hOL2RTtbnfs+y0PFS
48
+ /YTpQSelTuq+Fuwts5v6aAweNyMcYD0HBybkkdosFoDccBNzJ92Ac8I5EVDUc3Or
49
+ /4jSyZwzxu9kdmBlBzeHMvsqdH8SX9mNahXtXxRpwZnBiUjw36PgN+s9GLWGrafd
50
+ 02T0ux9Yzd5ezkMxukqEAQ7AKIIijvaWPAJbK/52XLhIy2vpGNylyni/DQD18bBP
51
+ T+ZG1uv0QQP9LuY/joO+FKDOTler4wIDAQABo4IDejCCA3YwHwYDVR0jBBgwFoAU
52
+ PdNQpdagre7zSmAKZdMh1Pj41g8wHQYDVR0OBBYEFIhcSGcZzKB2WS0RecO+oqyH
53
+ IidbMCUGA1UdEQQeMByCCmdpdGh1Yi5jb22CDnd3dy5naXRodWIuY29tMA4GA1Ud
54
+ DwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdQYDVR0f
55
+ BG4wbDA0oDKgMIYuaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItZXYtc2Vy
56
+ dmVyLWcxLmNybDA0oDKgMIYuaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTIt
57
+ ZXYtc2VydmVyLWcxLmNybDBLBgNVHSAERDBCMDcGCWCGSAGG/WwCATAqMCgGCCsG
58
+ AQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAcGBWeBDAEBMIGI
59
+ BggrBgEFBQcBAQR8MHowJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0
60
+ LmNvbTBSBggrBgEFBQcwAoZGaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0Rp
61
+ Z2lDZXJ0U0hBMkV4dGVuZGVkVmFsaWRhdGlvblNlcnZlckNBLmNydDAMBgNVHRMB
62
+ Af8EAjAAMIIBfwYKKwYBBAHWeQIEAgSCAW8EggFrAWkAdgCkuQmQtBhYFIe7E6LM
63
+ Z3AKPDWYBPkb37jjd80OyA3cEAAAAVNhieoeAAAEAwBHMEUCIQCHHSEY/ROK2/sO
64
+ ljbKaNEcKWz6BxHJNPOtjSyuVnSn4QIgJ6RqvYbSX1vKLeX7vpnOfCAfS2Y8lB5R
65
+ NMwk6us2QiAAdgBo9pj4H2SCvjqM7rkoHUz8cVFdZ5PURNEKZ6y7T0/7xAAAAVNh
66
+ iennAAAEAwBHMEUCIQDZpd5S+3to8k7lcDeWBhiJASiYTk2rNAT26lVaM3xhWwIg
67
+ NUqrkIODZpRg+khhp8ag65B8mu0p4JUAmkRDbiYnRvYAdwBWFAaaL9fC7NP14b1E
68
+ sj7HRna5vJkRXMDvlJhV1onQ3QAAAVNhieqZAAAEAwBIMEYCIQDnm3WStlvE99GC
69
+ izSx+UGtGmQk2WTokoPgo1hfiv8zIAIhAPrYeXrBgseA9jUWWoB4IvmcZtshjXso
70
+ nT8MIG1u1zF8MA0GCSqGSIb3DQEBCwUAA4IBAQCLbNtkxuspqycq8h1EpbmAX0wM
71
+ 5DoW7hM/FVdz4LJ3Kmftyk1yd8j/PSxRrAQN2Mr/frKeK8NE1cMji32mJbBqpWtK
72
+ /+wC+avPplBUbNpzP53cuTMF/QssxItPGNP5/OT9Aj1BxA/NofWZKh4ufV7cz3pY
73
+ RDS4BF+EEFQ4l5GY+yp4WJA/xSvYsTHWeWxRD1/nl62/Rd9FN2NkacRVozCxRVle
74
+ FrBHTFxqIP6kDnxiLElBrZngtY07ietaYZVLQN/ETyqLQftsf8TecwTklbjvm8NT
75
+ JqbaIVifYwqwNN+4lRxS3F5lNlA/il12IOgbRioLI62o8G0DaEUQgHNf8vSG
76
+ -----END CERTIFICATE-----
77
+ }
78
+ end
79
+
80
+ let(:xpath) { "/document/results/target[@host='#{host}']/certinfo/receivedCertificateChain/certificate" }
81
+
82
+ it "should parse the asPEM element" do
83
+ expect(subject.as_pem).to be == host_pem
84
+ end
85
+ end
86
+
87
+ describe "#x509" do
88
+ it do
89
+ expect(subject.x509).to be_kind_of(OpenSSL::X509::Certificate)
90
+ end
91
+ end
92
+
93
+ describe "#extensions" do
94
+ it do
95
+ expect(subject.extensions).to be_kind_of(SSLyze::X509::ExtensionSet)
96
+ end
97
+ end
98
+
99
+ describe "#issuer" do
100
+ it do
101
+ expect(subject.issuer).to be_a(SSLyze::X509::Name)
102
+ end
103
+ end
104
+
105
+ describe "#not_after" do
106
+ it do
107
+ expect(subject.not_after).to be_kind_of(Time)
108
+ end
109
+ end
110
+
111
+ describe "#not_before" do
112
+ it do
113
+ expect(subject.not_before).to be_kind_of(Time)
114
+ end
115
+ end
116
+
117
+ describe "#public_key" do
118
+ it do
119
+ expect(subject.public_key).to be_a(SSLyze::X509::PublicKey)
120
+ end
121
+ end
122
+
123
+ describe "#serial" do
124
+ it do
125
+ expect(subject.serial).to be_a(OpenSSL::BN)
126
+ end
127
+ end
128
+
129
+ describe "#signature_algorithm" do
130
+ it do
131
+ expect(subject.signature_algorithm).to be == 'sha256WithRSAEncryption'
132
+ end
133
+ end
134
+
135
+ describe "#subject" do
136
+ it do
137
+ expect(subject.subject).to be_a(SSLyze::X509::Name)
138
+ end
139
+ end
140
+
141
+ describe "#version" do
142
+ it do
143
+ expect(subject.version).to be 2
144
+ end
145
+ end
146
+
147
+ describe "#==" do
148
+ context "when the #as_pem matches" do
149
+ let(:other) { described_class.new(xml.at("#{xpath}[1]")) }
150
+
151
+ it { expect(subject == other).to be true }
152
+ end
153
+
154
+ context "when the #as_pem do not match" do
155
+ let(:other) { described_class.new(xml.at("#{xpath}[2]")) }
156
+
157
+ it { expect(subject == other).to be false }
158
+ end
159
+
160
+ context "when the classes do not match" do
161
+ let(:other) { Object.new }
162
+
163
+ it { expect(subject == other).to be false }
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+ require 'xml_examples'
3
+ require 'sslyze/xml/certinfo/certificate_validation/hostname_validation'
4
+
5
+ describe SSLyze::XML::Certinfo::CertificateValidation::HostnameValidation do
6
+ include_examples "XML specs"
7
+
8
+ subject do
9
+ described_class.new(xml.at('/document/results/target/certinfo/certificateValidation/hostnameValidation'))
10
+ end
11
+
12
+ describe "#certificate_matches_server_hostname?" do
13
+ it "should return a Boolean value" do
14
+ expect(subject.certificate_matches_server_hostname?).to be true
15
+ end
16
+ end
17
+
18
+ describe "#server_hostname" do
19
+ it "should return the serverHostname attribute" do
20
+ expect(subject.server_hostname).to match(/^(?:\w+\.)?\w+\.com$/)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,107 @@
1
+ require 'spec_helper'
2
+ require 'xml_examples'
3
+ require 'sslyze/xml/certinfo/certificate_validation/path_validation'
4
+
5
+ describe SSLyze::XML::Certinfo::CertificateValidation::PathValidation do
6
+ include_examples "XML specs"
7
+
8
+ let(:xpath) { '/document/results/target/certinfo/certificateValidation/pathValidation' }
9
+
10
+ subject do
11
+ described_class.new(xml.at(xpath))
12
+ end
13
+
14
+ describe "#is_extended_validation_certificate?" do
15
+ context "when the 'isExtendedValidationCertificate' XML attribute is present" do
16
+ subject do
17
+ described_class.new(xml.at("#{xpath}[@isExtendedValidationCertificate]"))
18
+ end
19
+
20
+ it "should return a Boolean type" do
21
+ expect(subject.is_extended_validation_certificate?).to be(false).or(be(true))
22
+ end
23
+ end
24
+
25
+ context "when the 'isExtendedValidationCertificate' XML attribute is omitted" do
26
+ subject do
27
+ described_class.new(xml.at("#{xpath}[not(@isExtendedValidationCertificate)]"))
28
+ end
29
+
30
+ it { expect(subject.is_extended_validation_certificate?).to be nil }
31
+ end
32
+ end
33
+
34
+ describe "#trust_store_version" do
35
+ it "must return the 'trustStoreVersion' XML attribute" do
36
+ expect(subject.trust_store_version).to_not be_empty
37
+ end
38
+ end
39
+
40
+ describe "#using_trust_store" do
41
+ let(:trust_stores) { %w[Android iOS macOS Mozilla Windows] }
42
+
43
+ it "must return the 'usingTrustStore' XML attribute" do
44
+ expect(trust_stores).to include(subject.using_trust_store)
45
+ end
46
+ end
47
+
48
+ describe "#validation_result" do
49
+ context "when the 'validationResult' attribute is set" do
50
+ subject do
51
+ described_class.new(xml.at("#{xpath}[@validationResult]"))
52
+ end
53
+
54
+ it "must return the 'validationResult' XML element" do
55
+ expect(subject.validation_result).to be == :ok
56
+ end
57
+ end
58
+
59
+ context "when the 'validationResult' attribute is not set" do
60
+ subject do
61
+ described_class.new(xml.at("#{xpath}[not(@validationResult)]"))
62
+ end
63
+
64
+ it "must return the 'validationResult' XML element" do
65
+ pending "need an example without the 'validationResult' XML attribute"
66
+
67
+ expect(subject.validation_result).to be nil
68
+ end
69
+ end
70
+ end
71
+
72
+ describe "#ok?" do
73
+ context "when the 'validationResult' attribute is set" do
74
+ context "and is 'ok'" do
75
+ subject do
76
+ described_class.new(xml.at("#{xpath}[@validationResult=\"ok\"]"))
77
+ end
78
+
79
+ it { expect(subject.ok?).to be true }
80
+ end
81
+
82
+ context "but is not 'ok'" do
83
+ subject do
84
+ described_class.new(xml.at("#{xpath}[not(@validationResult=\"ok\")]"))
85
+ end
86
+
87
+ it do
88
+ pending "need an example where the 'validationResult' isn't 'ok'"
89
+
90
+ expect(subject.ok?).to be false
91
+ end
92
+ end
93
+ end
94
+
95
+ context "when the 'validationResult' attribute is not set" do
96
+ subject do
97
+ described_class.new(xml.at("#{xpath}[not(@validationResult)]"))
98
+ end
99
+
100
+ it "must return the 'validationResult' XML element" do
101
+ pending "need an example without the 'validationResult' XML attribute"
102
+
103
+ expect(subject.ok?).to be nil
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,163 @@
1
+ require 'spec_helper'
2
+ require 'xml_examples'
3
+ require 'sslyze/xml/certinfo/certificate_validation/verified_certificate_chain'
4
+
5
+ describe SSLyze::XML::Certinfo::CertificateValidation::VerifiedCertificateChain do
6
+ include_examples "XML specs"
7
+
8
+ let(:xpath) { '/document/results/target/certinfo/certificateValidation/verifiedCertificateChain' }
9
+
10
+ subject { described_class.new(xml.at(xpath)) }
11
+
12
+ describe "#has_sha1_signed_certificate?" do
13
+ it "should return a Boolean value" do
14
+ expect(subject.has_sha1_signed_certificate?).to be(true).or(be(false))
15
+ end
16
+ end
17
+
18
+ describe "#each_certificate" do
19
+ context "when at least one 'certificate' XML child exists" do
20
+ let(:xpath) { "#{super()}[certificate]" }
21
+ let(:xpath_count) { xml.at(xpath).xpath('certificate').count }
22
+
23
+ it "should yield successive Certificate objects" do
24
+ expect { |b|
25
+ subject.each_certificate(&b)
26
+ }.to yield_successive_args(
27
+ *Array.new(xpath_count,SSLyze::XML::Certinfo::Certificate)
28
+ )
29
+ end
30
+ end
31
+
32
+ context "when no 'certificate' XML children exist" do
33
+ let(:xpath) { "#{super()}[not(./certificate)]" }
34
+
35
+ it "should not yield control" do
36
+ pending "need an example with no 'certificate' XML children"
37
+
38
+ expect { |b|
39
+ subject.each_certificate(&b)
40
+ }.to_not yield_control
41
+ end
42
+ end
43
+ end
44
+
45
+ describe "#certificates" do
46
+ context "when at least one 'certificate' XML child exists" do
47
+ let(:xpath) { "#{super()}[certificate]" }
48
+ let(:xpath_count) { xml.at(xpath).xpath('certificate').count }
49
+
50
+ it do
51
+ expect(subject.certificates).to be_a(Array).and(
52
+ all(be_kind_of(SSLyze::XML::Certinfo::Certificate))
53
+ )
54
+ end
55
+ end
56
+
57
+ context "when no 'certificate' XML children exist" do
58
+ let(:xpath) { "#{super()}[not(./certificate)]" }
59
+
60
+ it do
61
+ pending "need an example with no 'certificate' XML children"
62
+
63
+ expect(subject.certificates).to be_empty
64
+ end
65
+ end
66
+ end
67
+
68
+ describe "#leaf" do
69
+ context "when at least one 'certificate' XML child exists" do
70
+ let(:xpath) { "#{super()}[certificate]" }
71
+
72
+ it do
73
+ expect(subject.leaf).to be_a(SSLyze::XML::Certinfo::Certificate)
74
+ end
75
+
76
+ it "should select the first 'certificate' XML child" do
77
+ expect(subject.leaf).to be == \
78
+ SSLyze::XML::Certinfo::Certificate.new(xml.at("#{xpath}/certificate[1]"))
79
+ end
80
+ end
81
+
82
+ context "when no 'certificate' XML children exist" do
83
+ let(:xpath) { "#{super()}[not(./certificate)]" }
84
+
85
+ it do
86
+ pending "need an example with no 'certificate' XML children"
87
+
88
+ expect(subject.leaf).to be nil
89
+ end
90
+ end
91
+ end
92
+
93
+ describe "#each_intermediate" do
94
+ context "when there are more than two 'certificate' XML children" do
95
+ let(:xpath) { "#{super()}[count(certificate) > 2]" }
96
+
97
+ it "should yield the intermediate certificates" do
98
+ expect { |b|
99
+ subject.each_intermediate(&b)
100
+ }.to yield_successive_args(
101
+ SSLyze::XML::Certinfo::Certificate
102
+ )
103
+ end
104
+ end
105
+
106
+ context "when there are two or fewer 'certificate' XML children" do
107
+ let(:xpath) { "#{super()}[count(certificate) <= 2]" }
108
+
109
+ it "should not yield anything" do
110
+ pending "<vertifiedCertificateChain/> does not appear to ever have two or fewer <certificate/> children"
111
+
112
+ expect { |b|
113
+ subject.each_intermediate(&b)
114
+ }.to_not yield_control
115
+ end
116
+ end
117
+ end
118
+
119
+ describe "#intermediates" do
120
+ context "when there are more than two 'certificate' XML children" do
121
+ let(:xpath) { "#{super()}[count(certificate) > 2]" }
122
+
123
+ it "should yield the intermediate certificates" do
124
+ expect(subject.intermediates).to be_a(Array).and(all(be_kind_of(SSLyze::XML::Certinfo::Certificate)))
125
+ end
126
+ end
127
+
128
+ context "when there are two or fewer 'certificate' XML children" do
129
+ let(:xpath) { "#{super()}[count(certificate) <= 2]" }
130
+
131
+ it "should not yield anything" do
132
+ pending "<vertifiedCertificateChain/> does not appear to ever have two or fewer <certificate/> children"
133
+
134
+ expect(subject.intermediates).to be_empty
135
+ end
136
+ end
137
+ end
138
+
139
+ describe "#root" do
140
+ context "when at least one 'certificate' XML child exists" do
141
+ let(:xpath) { "#{super()}[certificate]" }
142
+
143
+ it do
144
+ expect(subject.root).to be_a(SSLyze::XML::Certinfo::Certificate)
145
+ end
146
+
147
+ it "should select the last 'certificate' XML child" do
148
+ expect(subject.root).to be == \
149
+ SSLyze::XML::Certinfo::Certificate.new(xml.at("#{xpath}/certificate[last()]"))
150
+ end
151
+ end
152
+
153
+ context "when no 'certificate' XML children exist" do
154
+ let(:xpath) { "#{super()}[not(./certificate)]" }
155
+
156
+ it do
157
+ pending "need an example with no 'certificate' XML children"
158
+
159
+ expect(subject.root).to be nil
160
+ end
161
+ end
162
+ end
163
+ end