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,66 @@
1
+ require 'sslyze/x509/extension'
2
+
3
+ module SSLyze
4
+ module X509
5
+ module Extensions
6
+ #
7
+ # Represents the `keyUsage` X509v3 extension.
8
+ #
9
+ # @since 1.0.0
10
+ #
11
+ class KeyUsage < Extension
12
+
13
+ include Enumerable
14
+
15
+ #
16
+ # The various permitted key uses.
17
+ #
18
+ # @return [Array<String>]
19
+ #
20
+ def uses
21
+ @uses ||= value.split(', ')
22
+ end
23
+
24
+ #
25
+ # @yield [use]
26
+ #
27
+ # @yieldparam [String] use
28
+ #
29
+ # @return [Enumerator]
30
+ #
31
+ def each(&block)
32
+ uses.each(&block)
33
+ end
34
+
35
+ #
36
+ # @return [Boolean]
37
+ #
38
+ def key_encipherment?
39
+ uses.include?('Key Encipherment')
40
+ end
41
+
42
+ #
43
+ # @return [Boolean]
44
+ #
45
+ def digital_signature?
46
+ uses.include?('Digital Signature')
47
+ end
48
+
49
+ #
50
+ # @return [Boolean]
51
+ #
52
+ def crl_sign?
53
+ uses.include?('CRL Sign')
54
+ end
55
+
56
+ #
57
+ # @return [Boolean]
58
+ #
59
+ def certificate_sign?
60
+ uses.include?('Certificate Sign')
61
+ end
62
+
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,144 @@
1
+ require 'sslyze/x509/extension'
2
+ require 'sslyze/x509/domain'
3
+
4
+ require 'uri'
5
+ require 'ipaddr'
6
+
7
+ module SSLyze
8
+ module X509
9
+ module Extensions
10
+ #
11
+ # Represents the `subjectAltName` X509v3 extension.
12
+ #
13
+ # @since 1.0.0
14
+ #
15
+ class SubjectAltName < Extension
16
+
17
+ include Enumerable
18
+
19
+ # Known subject name types.
20
+ TYPES = {
21
+ 'DNS' => :dns,
22
+ 'IP' => :ip,
23
+ 'URI' => :uri,
24
+ 'RID' => :rid,
25
+
26
+ 'email' => :email,
27
+ 'dirName' => :dir_name,
28
+ 'otherName' => :other_name
29
+ }
30
+
31
+ #
32
+ # Enumerates over every alternative name within the extension's value.
33
+ #
34
+ # @yield [type, name]
35
+ # The given block will be passed each
36
+ #
37
+ # @yieldparam [:dns, :ip, :uri, :rid, :email, :dir_name, :other_name] type
38
+ # The type of the alternative name being yielded.
39
+ #
40
+ # @yieldparam [String] name
41
+ # An alternative name within the extension's value.
42
+ #
43
+ # @return [Enumerator]
44
+ # If no block is given, an Enumerator will be returned.
45
+ #
46
+ # @raise [NotImplementedError]
47
+ # An unknown name type was encountered while parsing the extension's
48
+ # value.
49
+ #
50
+ def each
51
+ return enum_for unless block_given?
52
+
53
+ value.split(', ').each do |type_value|
54
+ type, value = type_value.split(':',2)
55
+
56
+ unless TYPES.has_key?(type)
57
+ raise(NotImplementedError,"unsupported subjectAltName type: #{type}")
58
+ end
59
+
60
+ yield TYPES[type], value
61
+ end
62
+ end
63
+
64
+ #
65
+ # All `DNS:` alternative names within the extension's value.
66
+ #
67
+ # @return [Array<String>]
68
+ #
69
+ def dns
70
+ @dns ||= select { |type,value| type == :dns }.map do |(type,value)|
71
+ value
72
+ end
73
+ end
74
+
75
+ #
76
+ # All `IP:` alternative names within the extension's value.
77
+ #
78
+ # @return [Array<IPAddr>]
79
+ #
80
+ def ip
81
+ @ip ||= select { |type,value| type == :ip }.map do |(type,value)|
82
+ IPAddr.new(value)
83
+ end
84
+ end
85
+
86
+ #
87
+ # All `URI:` alternative names within the extension's value.
88
+ #
89
+ # @return [Array<URI::Generic>]
90
+ #
91
+ def uri
92
+ @uri ||= select { |type,value| type == :uri }.map do |(type,value)|
93
+ URI.parse(value)
94
+ end
95
+ end
96
+
97
+ #
98
+ # All `email:` alternative names within the extension's value.
99
+ #
100
+ # @return [Array<String>]
101
+ #
102
+ def email
103
+ @email ||= select { |type,value| type == :email }.map do |(type,value)|
104
+ value
105
+ end
106
+ end
107
+
108
+ #
109
+ # All `RID:` alternative names within the extension's value.
110
+ #
111
+ # @return [Array<String>]
112
+ #
113
+ def rid
114
+ @rid ||= select { |type,value| type == :rid }.map do |(type,value)|
115
+ value
116
+ end
117
+ end
118
+
119
+ #
120
+ # All `dirName:` alternative names within the extension's value.
121
+ #
122
+ # @return [Array<String>]
123
+ #
124
+ def dir_name
125
+ @dir_name ||= select { |type,value| type == :dir_name }.map do |(type,value)|
126
+ value
127
+ end
128
+ end
129
+
130
+ #
131
+ # All `otherName:` alternative names within the extension's value.
132
+ #
133
+ # @return [Array<String>]
134
+ #
135
+ def other_name
136
+ @other_name ||= select { |type,value| type == :other_name }.map do |(type,value)|
137
+ value
138
+ end
139
+ end
140
+
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,194 @@
1
+ require 'sslyze/x509/domain'
2
+
3
+ require 'openssl'
4
+
5
+ module SSLyze
6
+ module X509
7
+ #
8
+ # Wrapper object for [OpenSSL::X509::Name][1].
9
+ #
10
+ # [1]: http://www.rubydoc.info/stdlib/openssl/OpenSSL/X509/Name
11
+ #
12
+ # @since 1.0.0
13
+ #
14
+ class Name
15
+
16
+ include Enumerable
17
+
18
+ #
19
+ # The parsed entries of the name.
20
+ #
21
+ # @return [Array<(String, String, Integer)>]
22
+ #
23
+ attr_reader :entries
24
+
25
+ #
26
+ # @param [OpenSSL::X509::Name] name
27
+ # The OpenSSL X509 name object.
28
+ #
29
+ def initialize(name)
30
+ @name = name
31
+ @entries = name.to_a
32
+ end
33
+
34
+ #
35
+ # Enumerates over the entries.
36
+ #
37
+ # @yield [oid, value, type]
38
+ #
39
+ # @yieldparam [String] oid
40
+ # The Object IDentifier.
41
+ #
42
+ # @yieldparam [String] value
43
+ # The entry's value.
44
+ #
45
+ # @yieldparam [Integer] type
46
+ # The entry type.
47
+ #
48
+ def each(&block)
49
+ @entries.each do |(oid,value,type)|
50
+ yield oid, value, type
51
+ end
52
+ end
53
+
54
+ #
55
+ # Finds the entry with the matcing OID (Object IDentifier).
56
+ #
57
+ # @param [String] key
58
+ #
59
+ # @return [String, nil]
60
+ #
61
+ def [](key)
62
+ each do |oid,value,type|
63
+ return value if oid == key
64
+ end
65
+
66
+ return nil
67
+ end
68
+
69
+ #
70
+ # The Country (`C`) entry.
71
+ #
72
+ # @return [String]
73
+ #
74
+ def country_name
75
+ @country_name ||= self['C']
76
+ end
77
+
78
+ alias country country_name
79
+ alias c country_name
80
+
81
+ #
82
+ # The Common Name (`CN`) entry.
83
+ #
84
+ # @return [Domain]
85
+ #
86
+ def common_name
87
+ @common_name ||= Domain.new(self['CN'])
88
+ end
89
+
90
+ alias cn common_name
91
+
92
+ #
93
+ # The Domain Component (`DC`) entry.
94
+ #
95
+ # @return [String, nil]
96
+ #
97
+ def domain_component
98
+ @domain_component ||= self['DC']
99
+ end
100
+
101
+ alias dc domain_component
102
+
103
+ #
104
+ # The Organization Name (`O`) entry.
105
+ #
106
+ # @return [String]
107
+ #
108
+ def organization_name
109
+ @organization_name ||= self['O']
110
+ end
111
+
112
+ alias organization organization_name
113
+ alias o organization_name
114
+
115
+ #
116
+ # The Organization Unit Name (`OU`) entry.
117
+ #
118
+ # @return [String]
119
+ #
120
+ def organizational_unit_name
121
+ @organizational_unit_name ||= self['OU']
122
+ end
123
+
124
+ alias organizational_unit organizational_unit_name
125
+ alias ou organizational_unit_name
126
+
127
+ #
128
+ # The State/Province Name (`ST`) entry.
129
+ #
130
+ # @return [String, nil]
131
+ #
132
+ def state_name
133
+ @state_name ||= self['ST']
134
+ end
135
+
136
+ alias state state_name
137
+ alias province_name state_name
138
+ alias province province_name
139
+ alias st state_name
140
+
141
+ #
142
+ # The Location (`L`) entry.
143
+ #
144
+ # @return [String, nil]
145
+ #
146
+ def location_name
147
+ @location ||= self['L']
148
+ end
149
+
150
+ alias location location_name
151
+ alias l location_name
152
+
153
+ #
154
+ # @see http://www.rubydoc.info/stdlib/openssl/OpenSSL/X509/Name#cmp-instance_method
155
+ #
156
+ def cmp(other)
157
+ @name.cmp(other.name)
158
+ end
159
+
160
+ #
161
+ # @see http://www.rubydoc.info/stdlib/openssl/OpenSSL/X509/Name#eql%3F-instance_method
162
+ #
163
+ def eql?(other)
164
+ @name.eql?(other.name)
165
+ end
166
+
167
+ #
168
+ # @see http://www.rubydoc.info/stdlib/openssl/OpenSSL/X509/Name#to_a-instance_method
169
+ #
170
+ def to_a
171
+ @name.to_a
172
+ end
173
+
174
+ #
175
+ # @see http://www.rubydoc.info/stdlib/openssl/OpenSSL/X509/Name#to_der-instance_method
176
+ #
177
+ def to_der
178
+ @name.to_der
179
+ end
180
+
181
+ #
182
+ # @see http://www.rubydoc.info/stdlib/openssl/OpenSSL/X509/Name#to_s-instance_method
183
+ #
184
+ def to_s(*args)
185
+ @name.to_s(*args)
186
+ end
187
+
188
+ protected
189
+
190
+ attr_reader :name
191
+
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,53 @@
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