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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c4013d128b21d94004ca8c15715b85531acfe46f
4
+ data.tar.gz: bfcbc3a8309309dbc5e03986f153fdd1792174a3
5
+ SHA512:
6
+ metadata.gz: ce2fd295c02224d87157bedfec3cf4d63f4b0d9f9558a12fa00063c104c3eef986bfae25c2ec1378136a17db1fb4ff24589a0ad902df1591e80b95559a134662
7
+ data.tar.gz: 9d5cf5e4dca31f544e6cae4cdad4a7b09ba4a2c80350bdac8094e793f2626622d30c42489ae6baec63749ab7729ba66b11af36fa079a95b633b117425b21092f
data/.document ADDED
@@ -0,0 +1,3 @@
1
+ -
2
+ ChangeLog.md
3
+ LICENSE.txt
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ Gemfile.lock
2
+ doc/
3
+ pkg/
4
+ vendor/cache/*.gem
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format documentation
data/.travis.yml ADDED
@@ -0,0 +1,19 @@
1
+ language: ruby
2
+ sudo: false
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0
6
+ - 2.1
7
+ - ruby-head
8
+ - jruby-19mode
9
+ - jruby-head
10
+ - rbx-2
11
+ matrix:
12
+ allow_failures:
13
+ - rvm: rbx-2
14
+ addons:
15
+ code_climate:
16
+ repo_token: 2a03fa37ce5a5cb21bb117a736be5d83dcf9f1c3ea2b248f7af4c0a7b330d8c8
17
+ notifications:
18
+ slack:
19
+ secure: IfKhtia5nM6KA9nK8jiSkNnVOLN96er6gK5jgjYKFNrVyWAKRUJZ0TB9L+igjUWDq7t+tRvj8yGT2k61xVJgF+ZDlQiWvyazTsgQeqbjieCxCrj/BTGZLyD1hhOLg7vqpyeQvp/34hDahx6XNp6XPvkxeofjc0H6STv2UjJkpQk=
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --markup markdown --title "ruby-sslyze Documentation" --protected
data/ChangeLog.md ADDED
@@ -0,0 +1,8 @@
1
+ ### 0.1.0 / 2015-10-13
2
+
3
+ * Initial release:
4
+ * Provides a Ruby interface to `sslyze.py`.
5
+ * Provides a Parser for consuming the sslyze XML output.
6
+ * [sslyze] >= 0.12
7
+
8
+ [sslyze]: https://github.com/nabla-c0d3/sslyze#readme
data/Gemfile ADDED
@@ -0,0 +1,18 @@
1
+ source 'https://rubygems.org/'
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'rake'
7
+ gem 'rubygems-tasks', '~> 0.2'
8
+
9
+ gem 'rspec', '~> 3.0'
10
+
11
+ gem 'yard', '~> 0.8'
12
+ gem 'kramdown'
13
+ end
14
+
15
+ group :test do
16
+ gem 'json'
17
+ gem 'codeclimate-test-reporter', require: nil
18
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2014-2015 Hal Brodigan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # ruby-sslyze
2
+
3
+ [![Code Climate](https://codeclimate.com/github/trailofbits/ruby-sslyze/badges/gpa.svg)](https://codeclimate.com/github/trailofbits/ruby-sslyze)
4
+ [![Test Coverage](https://codeclimate.com/github/trailofbits/ruby-sslyze/badges/coverage.svg)](https://codeclimate.com/github/trailofbits/ruby-sslyze)
5
+ [![Build Status](https://travis-ci.org/trailofbits/ruby-sslyze.svg)](https://travis-ci.org/trailofbits/ruby-sslyze)
6
+
7
+ * [Homepage](https://github.com/trailofbits/ruby-sslyze#readme)
8
+ * [Issues](https://github.com/trailofbits/ruby-sslyze/issues)
9
+ * [Documentation](http://rubydoc.info/gems/ruby-sslyze/frames)
10
+ * [Email](mailto:hal at trailofbits.com)
11
+
12
+ ## Description
13
+
14
+ A Ruby interface to [sslyze] python utility.
15
+
16
+ ## Features
17
+
18
+ * Provides a Ruby interface to `sslyze.py`.
19
+ * Provides a Parser for consuming the sslyze XML output.
20
+ * [sslyze] >= 0.12
21
+
22
+ ## Examples
23
+
24
+ Analyze a domain:
25
+
26
+ require 'sslyze'
27
+
28
+ SSLyze::Program.analyze(targets: 'twitter.com', regular: true, timeout: 5)
29
+
30
+ Analyze multiple domains:
31
+
32
+ SSLyze::Program.analyze(
33
+ targets: ['twitter.com', 'github.com'],
34
+ regular: true,
35
+ timeout: 5
36
+ )
37
+
38
+ Output to XML:
39
+
40
+ SSLyze::Program.analyze(
41
+ targets: 'twitter.com',
42
+ regular: true,
43
+ timeout: 5,
44
+ xml_out: 'path/to/xml'
45
+ )
46
+
47
+ Parsing sslyze XML output:
48
+
49
+ xml = SSLyze::XML.open('path/to/xml')
50
+
51
+ ## Requirements
52
+
53
+ * [rprogram] ~> 0.3
54
+ * [nokogiri] ~> 1.0
55
+ * [sslyze] >= 0.12
56
+
57
+ ## Install
58
+
59
+ $ gem install ruby-sslyze
60
+
61
+ ## Copyright
62
+
63
+ Copyright (c) 2014 Hal Brodigan
64
+
65
+ See {file:LICENSE.txt} for details.
66
+
67
+ [sslyze]: https://github.com/nabla-c0d3/sslyze#readme
68
+
69
+ [rpgoram]: https://github.com/postmodern/rprogram#readme
70
+ [nokogiri]: http://www.nokogiri.org/
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError => e
4
+ abort e.message
5
+ end
6
+
7
+ require 'rake'
8
+ require 'rubygems/tasks'
9
+ Gem::Tasks.new
10
+
11
+ require 'rspec/core/rake_task'
12
+ RSpec::Core::RakeTask.new
13
+
14
+ task :test => :spec
15
+ task :default => :spec
16
+
17
+ require 'yard'
18
+ YARD::Rake::YardocTask.new
19
+ task :doc => :yard
20
+
21
+ file 'spec/sslyze.xml' do
22
+ sh 'sslyze.py --xml_out spec/sslyze.xml --regular --timeout 5 twitter.com github.com:443 yahoo.com:443'
23
+ end
data/lib/sslyze.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'sslyze/program'
2
+ require 'sslyze/xml'
3
+ require 'sslyze/version'
@@ -0,0 +1,55 @@
1
+ require 'sslyze/certificate_chain'
2
+ require 'sslyze/certificate_validation'
3
+ require 'sslyze/ocsp_response'
4
+
5
+ module SSLyze
6
+ #
7
+ # Represents the `<certinfo>` element.
8
+ #
9
+ class CertInfo
10
+
11
+ #
12
+ # Initializes the cert info.
13
+ #
14
+ # @param [Nokogiri::XML::Node] node
15
+ # The `<certinfo>` element.
16
+ #
17
+ def initialize(node)
18
+ @node = node
19
+ end
20
+
21
+ #
22
+ # Certificate chain.
23
+ #
24
+ # @return [CertificateChain, nil]
25
+ #
26
+ def chain
27
+ @chain ||= if (cert_chain = @node.at('certificateChain'))
28
+ CertificateChain.new(cert_chain)
29
+ end
30
+ end
31
+
32
+ #
33
+ # Certificate validation information.
34
+ #
35
+ # @return [CertificateValidation]
36
+ #
37
+ def validation
38
+ @validation ||= CertificateValidation.new(@node.at('certificateValidation'))
39
+ end
40
+
41
+ #
42
+ # OCSP response stapling information.
43
+ #
44
+ # @return [OCSPResponse, nil]
45
+ #
46
+ def ocsp_response
47
+ @ocsp_response ||= if (ocsp_response = @node.at('ocspStapling/ocspResponse'))
48
+ OCSPResponse.new(ocsp_response)
49
+ end
50
+ end
51
+
52
+ alias ocsp_stapling ocsp_response
53
+
54
+ end
55
+ end
@@ -0,0 +1,139 @@
1
+ require 'sslyze/certificate/subject_public_key_info'
2
+ require 'sslyze/certificate/extensions'
3
+ require 'sslyze/certificate/subject'
4
+ require 'sslyze/certificate/validity'
5
+ require 'sslyze/certificate/issuer'
6
+
7
+ require 'date'
8
+
9
+ module SSLyze
10
+ #
11
+ # Represents the `<certificate>` XML element.
12
+ #
13
+ class Certificate
14
+
15
+ #
16
+ # Initializes the certificate.
17
+ #
18
+ # @param [Nokogiri::XML::Node] node
19
+ # The `<certificate>` XML element.
20
+ #
21
+ def initialize(node)
22
+ @node = node
23
+ end
24
+
25
+ #
26
+ # The position of the certificate within the cert chain.
27
+ #
28
+ # @return [:leaf, :intermediate]
29
+ #
30
+ def position
31
+ @position ||= @node['position'].to_sym
32
+ end
33
+
34
+ #
35
+ # The SHA1 fingerprint of the cert.
36
+ #
37
+ # @return [String]
38
+ #
39
+ def sha1_fingerprint
40
+ @sha1_fingerprint ||= @node['sha1Fingerprint']
41
+ end
42
+
43
+ #
44
+ # The AS PEM information.
45
+ #
46
+ # @return [String]
47
+ #
48
+ def as_pem
49
+ @as_pem ||= @node.at('asPEM').inner_text
50
+ end
51
+
52
+ #
53
+ # The subject public key information.
54
+ #
55
+ # @return [SubjectPublicKeyInfo]
56
+ #
57
+ def subject_public_key_info
58
+ @subject_public_key_info ||= SubjectPublicKeyInfo.new(
59
+ @node.at('subjectPublicKeyInfo')
60
+ )
61
+ end
62
+
63
+ #
64
+ # The certificate SSL version.
65
+ #
66
+ # @return [Integer]
67
+ #
68
+ def version
69
+ @version ||= @node.at('version').inner_text.to_i
70
+ end
71
+
72
+ #
73
+ # The SSL extensions.
74
+ #
75
+ # @return [Extensions]
76
+ #
77
+ def extensions
78
+ @extensions ||= Extensions.new(@node.at('extensions'))
79
+ end
80
+
81
+ #
82
+ # The certificate signature.
83
+ #
84
+ # @return [String]
85
+ #
86
+ def signature_value
87
+ @signature_value ||= @node.at('signatureValue').inner_text
88
+ end
89
+
90
+ #
91
+ # The certificate signature algorithm.
92
+ #
93
+ # @return [String]
94
+ #
95
+ def signature_algorithm
96
+ @signature_algorithm ||= @node.at('signatureAlgorithm').inner_text
97
+ end
98
+
99
+ #
100
+ # The certificate serial number.
101
+ #
102
+ # @return [String]
103
+ #
104
+ def serial_number
105
+ @serial_number ||= @node.at('serialNumber').inner_text
106
+ end
107
+
108
+ #
109
+ # The certificate subject information.
110
+ #
111
+ # @return [Subject]
112
+ #
113
+ def subject
114
+ @subject ||= Subject.new(@node.at('subject'))
115
+ end
116
+
117
+ #
118
+ # The certificate validity.
119
+ #
120
+ # @return [Validity]
121
+ #
122
+ def validity
123
+ @validity ||= Validity.new(
124
+ Date.parse(@node.at('validity/notAfter').inner_text),
125
+ Date.parse(@node.at('validity/notBefore').inner_text)
126
+ )
127
+ end
128
+
129
+ #
130
+ # The certificate issuer.
131
+ #
132
+ # @return [Issuer]
133
+ #
134
+ def issuer
135
+ @issuer ||= Issuer.new(@node.at('issuer'))
136
+ end
137
+
138
+ end
139
+ end
@@ -0,0 +1,77 @@
1
+ module SSLyze
2
+ class Certificate
3
+ #
4
+ # Represents a domain name pattern.
5
+ #
6
+ class DomainName
7
+
8
+ # The subject name.
9
+ #
10
+ # @return [String]
11
+ attr_reader :name
12
+
13
+ # The domain part of the subject name.
14
+ #
15
+ # @return [String]
16
+ attr_reader :domain
17
+
18
+ # The literal suffix of the subject name.
19
+ #
20
+ # @return [String]
21
+ attr_reader :suffix
22
+
23
+ #
24
+ # Initializes the subject name.
25
+ #
26
+ # @param [String] name
27
+ # The subject name.
28
+ #
29
+ def initialize(name)
30
+ @name = name
31
+
32
+ if @name.start_with?('*.')
33
+ @suffix = @name[1..-1]
34
+ @domain = @name[2..-1]
35
+ else
36
+ @domain = @name
37
+ end
38
+ end
39
+
40
+ #
41
+ # Compares two subject names.
42
+ #
43
+ # @return [Boolean]
44
+ #
45
+ def ==(other)
46
+ @name == other.name
47
+ end
48
+
49
+ #
50
+ # Tests whether the domain is matched by the subject name.
51
+ #
52
+ def include?(domain)
53
+ if @name.start_with?('*.') # wildcard
54
+ domain.end_with?(@suffix) || # does the domain share the suffix
55
+ domain == @domain # does the domain match the suffix
56
+ else # exact match
57
+ domain == @name
58
+ end
59
+ end
60
+
61
+ alias === include?
62
+
63
+ alias to_s name
64
+ alias to_str name
65
+
66
+ #
67
+ # Inspects the subject name.
68
+ #
69
+ # @return [String]
70
+ #
71
+ def inspect
72
+ "#<#{self.class}: #{self}>"
73
+ end
74
+
75
+ end
76
+ end
77
+ end