certutil 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 337ac9e815212f52c227e2b4d3ac7da2fda87640
4
+ data.tar.gz: 022b56ab7537b0a0e167d129ac07cc9a5cba9f75
5
+ SHA512:
6
+ metadata.gz: 99f5d062fa56b786613779a8d8d5b5dc8a9c8d8757c45316d2944367999327abc21ca87b1b6a7dc41695fa41727c2715b759f9ed1147d87762431e4809152995
7
+ data.tar.gz: 3f51c62de7017d20340ec87733eef9a92f16ea30f8ca1d1b9c610c986fc50d6217544a6160c5977b9ff3cdd221602dd759e6a8b285f075f739ddf3dd690805ba
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ .DS_Store
2
+ results.html
3
+ pkg
4
+ html
5
+ tmp/*
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format doc
2
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in certutil.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,53 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ certutil (0.1.0)
5
+ methadone (~> 1.3.2)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ aruba (0.5.4)
11
+ childprocess (>= 0.3.6)
12
+ cucumber (>= 1.1.1)
13
+ rspec-expectations (>= 2.7.0)
14
+ builder (3.2.2)
15
+ childprocess (0.5.1)
16
+ ffi (~> 1.0, >= 1.0.11)
17
+ cucumber (1.3.12)
18
+ builder (>= 2.1.2)
19
+ diff-lcs (>= 1.1.3)
20
+ gherkin (~> 2.12)
21
+ multi_json (>= 1.7.5, < 2.0)
22
+ multi_test (>= 0.1.1)
23
+ diff-lcs (1.2.5)
24
+ ffi (1.9.3)
25
+ gherkin (2.12.2)
26
+ multi_json (~> 1.3)
27
+ json (1.8.1)
28
+ methadone (1.3.2)
29
+ bundler
30
+ multi_json (1.9.2)
31
+ multi_test (0.1.1)
32
+ rake (0.9.6)
33
+ rdoc (4.1.1)
34
+ json (~> 1.4)
35
+ rspec (2.14.1)
36
+ rspec-core (~> 2.14.0)
37
+ rspec-expectations (~> 2.14.0)
38
+ rspec-mocks (~> 2.14.0)
39
+ rspec-core (2.14.8)
40
+ rspec-expectations (2.14.5)
41
+ diff-lcs (>= 1.1.3, < 2.0)
42
+ rspec-mocks (2.14.6)
43
+
44
+ PLATFORMS
45
+ ruby
46
+
47
+ DEPENDENCIES
48
+ aruba
49
+ bundler (~> 1.5)
50
+ certutil!
51
+ rake (~> 0.9.2)
52
+ rdoc
53
+ rspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Chad Bailey
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,18 @@
1
+ # Certutil
2
+
3
+ This is a tool I developed after dealing with a lot of SSL certificates in Heroku Support.
4
+
5
+ ## Installation
6
+
7
+ Just `gem install certutil` to install it.
8
+
9
+ `rbenv rehash` if you're using rbenv. You might have to do something to RVM to get it to show up there; honestly I can't remember.
10
+
11
+ ## Usage
12
+
13
+ This app uses locally saved certificate files (ones that look like `---BEGIN CERTIFICATE---`), or it can fetch them from a live site directly.
14
+
15
+ Just run `certutil file.crt` for a local file, or `certutil google.com` to get the cert from the web.
16
+
17
+ By default, the app parses the cert chain and displays a decoded version of the entire chain. See `certutil --help` for more options, or `rake features` to see some example use cases.
18
+
data/README.rdoc ADDED
@@ -0,0 +1,19 @@
1
+ = certutil - DESCRIBE YOUR GEM
2
+
3
+ Author:: YOUR NAME (YOUR EMAIL)
4
+ Copyright:: Copyright (c) 2014 YOUR NAME
5
+
6
+
7
+ DESCRIBE YOUR GEM HERE
8
+
9
+ == Links
10
+
11
+ * {Source on Github}[LINK TO GITHUB]
12
+ * RDoc[LINK TO RDOC.INFO]
13
+
14
+ == Install
15
+
16
+ == Examples
17
+
18
+ == Contributing
19
+
data/Rakefile ADDED
@@ -0,0 +1,61 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ RSpec::Core::RakeTask.new('spec')
4
+
5
+ def dump_load_path
6
+ puts $LOAD_PATH.join("\n")
7
+ found = nil
8
+ $LOAD_PATH.each do |path|
9
+ if File.exists?(File.join(path,"rspec"))
10
+ puts "Found rspec in #{path}"
11
+ if File.exists?(File.join(path,"rspec","core"))
12
+ puts "Found core"
13
+ if File.exists?(File.join(path,"rspec","core","rake_task"))
14
+ puts "Found rake_task"
15
+ found = path
16
+ else
17
+ puts "!! no rake_task"
18
+ end
19
+ else
20
+ puts "!!! no core"
21
+ end
22
+ end
23
+ end
24
+ if found.nil?
25
+ puts "Didn't find rspec/core/rake_task anywhere"
26
+ else
27
+ puts "Found in #{path}"
28
+ end
29
+ end
30
+ require 'bundler'
31
+ require 'rake/clean'
32
+
33
+ require 'rake/testtask'
34
+
35
+ require 'cucumber'
36
+ require 'cucumber/rake/task'
37
+ gem 'rdoc' # we need the installed RDoc gem, not the system one
38
+ require 'rdoc/task'
39
+
40
+ include Rake::DSL
41
+
42
+ Bundler::GemHelper.install_tasks
43
+
44
+
45
+
46
+ CUKE_RESULTS = 'results.html'
47
+ CLEAN << CUKE_RESULTS
48
+ Cucumber::Rake::Task.new(:features) do |t|
49
+ t.cucumber_opts = "features --format html -o #{CUKE_RESULTS} --format pretty --no-source -x"
50
+ t.fork = false
51
+ end
52
+
53
+ Rake::RDocTask.new do |rd|
54
+
55
+ rd.main = "README.rdoc"
56
+
57
+ rd.rdoc_files.include("README.rdoc","lib/**/*.rb","bin/**/*")
58
+ end
59
+
60
+ task :default => [:spec,:features]
61
+
data/bin/certutil ADDED
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'methadone'
5
+ require 'certutil.rb'
6
+
7
+ class App
8
+ include Methadone::Main
9
+ include Methadone::CLILogging
10
+
11
+ main do |source| # Add args you want: |like,so|
12
+ # your program code here
13
+ # You can access CLI options via
14
+ # the options Hash
15
+
16
+ debug "from bin, wd is #{Dir.pwd}"
17
+
18
+ @cp = CertificateParser.new_from_input(source)
19
+ #if options["input"]
20
+ #@cp = CertificateParser.new_from_file(File.expand_path(options["input"]))
21
+ #elsif options["hostname"]
22
+ #@cp = CertificateParser.new_from_hostname(options["hostname"])
23
+ #else
24
+ #error "You must include a cert file with -i or a hostname with -h."
25
+ #end
26
+
27
+ if @cp.certs.count == 0
28
+ error "!! Couldn't find any valid certificates. Make sure your input contains -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- blocks."
29
+ elsif @cp.certs.count == 1
30
+ info "Found 1 certificate."
31
+ else
32
+ info "Found #{@cp.certs.count} certificates."
33
+ end
34
+
35
+ if options[:split]
36
+ @cp.write_crt_files! if options[:output] == "crt"
37
+ @cp.write_txt_files! if options[:output] == "txt"
38
+ else
39
+ @cp.write_crt_file! if options[:output] == "crt"
40
+ @cp.write_txt_file! if options[:output] == "txt"
41
+ end
42
+
43
+ info @cp.decoded.join("\n-----\n\n") unless options[:mute]
44
+ end
45
+
46
+ # supplemental methods here
47
+
48
+ # Declare command-line interface here
49
+
50
+ # description "one line description of your app"
51
+ #
52
+ # Accept flags via:
53
+ # on("--flag VAL","Some flag")
54
+ #on("--input FILE", "-i FILE", "Input .crt/.pem file")
55
+ #on("--hostname HOSTNAME", "-h HOSTNAME", "Hostname from which to fetch certificate")
56
+ on("--output FORMAT", "-o", "Write out results to the current directory (formats are crt or txt (decoded)")
57
+ on("--split", "-s", "Split multiple certs into separate files for writing")
58
+ on("--mute", "-m", "Mute output")
59
+
60
+ # options[flag] will contain VAL
61
+ #
62
+ # Specify switches via:
63
+ # on("--[no-]switch","Some switch")
64
+ arg :source, "The cert(s) on which to operate (filename, hostname or gist link)"
65
+
66
+ #
67
+ # Or, just call OptionParser methods on opts
68
+ #
69
+ # Require an argument
70
+ # arg :some_arg
71
+ #
72
+ # # Make an argument optional
73
+ # arg :optional_arg, :optional
74
+
75
+ version Certutil::VERSION
76
+
77
+ use_log_level_option
78
+
79
+ go!
80
+ end
data/certutil.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'certutil/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "certutil"
8
+ spec.version = Certutil::VERSION
9
+ spec.authors = ["Chad Bailey"]
10
+ spec.email = ["chad@heroku.com"]
11
+ spec.summary = %q{A tool for decoding and analyzing SSL certificates.}
12
+ spec.description = %q{A tool for decoding and analyzing SSL certificates.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rspec"
23
+ spec.add_development_dependency('rdoc')
24
+ spec.add_development_dependency('aruba')
25
+ spec.add_development_dependency('rake', '~> 0.9.2')
26
+ spec.add_dependency('methadone', '~> 1.3.2')
27
+ end
@@ -0,0 +1,75 @@
1
+ Feature: My bootstrapped app kinda works
2
+ In order to get going on coding my awesome app
3
+ I want to have aruba and cucumber setup
4
+ So I don't have to do it myself
5
+
6
+ Scenario: App just runs
7
+ When I get help for "certutil"
8
+ Then the exit status should be 0
9
+ And the banner should be present
10
+ And the banner should document that this app takes options
11
+ And the following options should be documented:
12
+ |--version|
13
+ |--output|
14
+ |--split|
15
+ |--mute|
16
+ And the banner should document that this app's arguments are:
17
+ |source|which is required|
18
+
19
+ Scenario: Parse full file
20
+ When I run `certutil ../../features/google-full.crt --log-level debug`
21
+ Then the output should contain "google-full"
22
+ And the output should contain "Found 3 certificates."
23
+ And the output should contain "Google Internet Authority"
24
+
25
+ Scenario: Parse abbreviated file
26
+ When I run `certutil ../../features/google-short.crt`
27
+ Then the output should contain "google-short"
28
+ And the output should contain "Found 3 certificates."
29
+ And the output should contain "Google Internet Authority"
30
+
31
+ Scenario: Silent mode (mute)
32
+ When I run `certutil ../../features/google-short.crt -m`
33
+ Then the output should contain "google-short"
34
+ And the output should contain "Found 3 certificates."
35
+ And the output should not contain "Google Internet Authority"
36
+
37
+ Scenario: Parse URL
38
+ When I run `certutil google.com`
39
+ Then the output should contain "google.com"
40
+ And the output should contain "Found 3 certificates."
41
+ And the output should contain "Google Internet Authority"
42
+
43
+ Scenario: No cert
44
+ When I run `certutil`
45
+ Then the output should contain "parse error: 'source' is required"
46
+
47
+
48
+ Scenario: Write split CRT files
49
+ When I run `certutil ../../features/google-full.crt -s -o crt`
50
+ Then the output should contain "google-full"
51
+ And a file named "google-full-0.crt" should exist in my current directory
52
+ And a file named "google-full-1.crt" should exist in my current directory
53
+ And a file named "google-full-2.crt" should exist in my current directory
54
+ And the file named "google-full-0.crt" should contain "MIIHPzCCBiegAwIBAgII"
55
+
56
+
57
+ Scenario: Write split TXT files
58
+ When I run `certutil ../../features/google-full.crt -s -o txt`
59
+ Then the output should contain "google-full"
60
+ And a file named "google-full-0-decoded.txt" should exist in my current directory
61
+ And a file named "google-full-1-decoded.txt" should exist in my current directory
62
+ And a file named "google-full-2-decoded.txt" should exist in my current directory
63
+ And the file named "google-full-0-decoded.txt" should contain "Google Internet Authority"
64
+
65
+ Scenario: Write a single CRT file
66
+ When I run `certutil google.com --log-level debug -o crt`
67
+ Then the output should contain "google.com"
68
+ And a file named "google.com.crt" should exist in my current directory
69
+ And the file named "google.com.crt" should contain "MIIHPzCCBiegAwIBAgII"
70
+
71
+ Scenario: Write a single TXT file
72
+ When I run `certutil google.com -o txt`
73
+ Then the output should contain "google.com"
74
+ And a file named "google.com-decoded.txt" should exist in my current directory
75
+ And the file named "google.com-decoded.txt" should contain "Google Internet Authority"
@@ -0,0 +1,120 @@
1
+ CONNECTED(00000003)
2
+ ---
3
+ Certificate chain
4
+ 0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=*.google.com
5
+ i:/C=US/O=Google Inc/CN=Google Internet Authority G2
6
+ -----BEGIN CERTIFICATE-----
7
+ MIIHPzCCBiegAwIBAgIIXg768qmYVL0wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
8
+ BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
9
+ cm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwMzEyMDk1MzQwWhcNMTQwNjEwMDAwMDAw
10
+ WjBmMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN
11
+ TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEVMBMGA1UEAwwMKi5n
12
+ b29nbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkDR4dXYy
13
+ +W5fPMG03Tuhsj0lVJKRKob7rUC4yuIeoPuNaEvBzD6nB6OVbBFZfAPpHAvphTw0
14
+ SWZXHEO2CSTtz7gz1S3pIqeMyJC04xd/oWuokT/NpGjeQAkAidTkeedPNu9Ix5EL
15
+ RVKGAQhxXuABth8uvoMrzT5Kx/mrq+YC4kxFevwfaePW88JO+rmb/VVeqmGnzgqU
16
+ dJV/B2euk2X0LX+lzcYw2xgIIBEICI0w3EJNBLzT7WIHbVjK/35owB6f9ni39wsu
17
+ xwCq1J9zTxcgbuSOg3REYtKHxHsMdwIHiuDa80s1Xc1TcMTKsp/aPjAWR/zEiIdB
18
+ niAZhJB2Tmp9FwIDAQABo4IEDDCCBAgwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG
19
+ AQUFBwMCMIIC4gYDVR0RBIIC2TCCAtWCDCouZ29vZ2xlLmNvbYINKi5hbmRyb2lk
20
+ LmNvbYIWKi5hcHBlbmdpbmUuZ29vZ2xlLmNvbYISKi5jbG91ZC5nb29nbGUuY29t
21
+ ghYqLmdvb2dsZS1hbmFseXRpY3MuY29tggsqLmdvb2dsZS5jYYILKi5nb29nbGUu
22
+ Y2yCDiouZ29vZ2xlLmNvLmlugg4qLmdvb2dsZS5jby5qcIIOKi5nb29nbGUuY28u
23
+ dWuCDyouZ29vZ2xlLmNvbS5hcoIPKi5nb29nbGUuY29tLmF1gg8qLmdvb2dsZS5j
24
+ b20uYnKCDyouZ29vZ2xlLmNvbS5jb4IPKi5nb29nbGUuY29tLm14gg8qLmdvb2ds
25
+ ZS5jb20udHKCDyouZ29vZ2xlLmNvbS52boILKi5nb29nbGUuZGWCCyouZ29vZ2xl
26
+ LmVzggsqLmdvb2dsZS5mcoILKi5nb29nbGUuaHWCCyouZ29vZ2xlLml0ggsqLmdv
27
+ b2dsZS5ubIILKi5nb29nbGUucGyCCyouZ29vZ2xlLnB0gg8qLmdvb2dsZWFwaXMu
28
+ Y26CFCouZ29vZ2xlY29tbWVyY2UuY29tghEqLmdvb2dsZXZpZGVvLmNvbYINKi5n
29
+ c3RhdGljLmNvbYIKKi5ndnQxLmNvbYIMKi51cmNoaW4uY29tghAqLnVybC5nb29n
30
+ bGUuY29tghYqLnlvdXR1YmUtbm9jb29raWUuY29tgg0qLnlvdXR1YmUuY29tghYq
31
+ LnlvdXR1YmVlZHVjYXRpb24uY29tggsqLnl0aW1nLmNvbYILYW5kcm9pZC5jb22C
32
+ BGcuY2+CBmdvby5nbIIUZ29vZ2xlLWFuYWx5dGljcy5jb22CCmdvb2dsZS5jb22C
33
+ Emdvb2dsZWNvbW1lcmNlLmNvbYIKdXJjaGluLmNvbYIIeW91dHUuYmWCC3lvdXR1
34
+ YmUuY29tghR5b3V0dWJlZWR1Y2F0aW9uLmNvbTBoBggrBgEFBQcBAQRcMFowKwYI
35
+ KwYBBQUHMAKGH2h0dHA6Ly9wa2kuZ29vZ2xlLmNvbS9HSUFHMi5jcnQwKwYIKwYB
36
+ BQUHMAGGH2h0dHA6Ly9jbGllbnRzMS5nb29nbGUuY29tL29jc3AwHQYDVR0OBBYE
37
+ FGdKaoHIMQ7lHCrxueGq7sgmqowwMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAU
38
+ St0GFhu89mi1dvWBtrtiGrpagS8wFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMDAG
39
+ A1UdHwQpMCcwJaAjoCGGH2h0dHA6Ly9wa2kuZ29vZ2xlLmNvbS9HSUFHMi5jcmww
40
+ DQYJKoZIhvcNAQEFBQADggEBAES1P4XqtSjXyGCuEw0CBJpDSdUCpF/t0hEMPd4+
41
+ VpJPrVlhUkcTRiLUi9PtneA6qkqbkFNtB3rj0TsoEq2AsMfw576zS8YSDYcXqDzX
42
+ S1VsXykK2YnlVapMGXVVZFeXxCSCpb1fMknE/3Y80St5Pyj+Gtl8m2wRmdGX6Hw/
43
+ 6GSs1WsSq0dn7w1nqZKIm9FSlzofCPOyhMpM8GyrygqyBKoQcl0nJbnEiNzQAOum
44
+ YlOlLCmXhf3LyxUhjcaYMulPiXrzsdCikVotfAhPF0BDCDF8/6SQ2y0RYw1NionU
45
+ G6VANTpbplIlpqm+47cjO7VZv55GfZ3hJswfrdrWKIm/1mA=
46
+ -----END CERTIFICATE-----
47
+ 1 s:/C=US/O=Google Inc/CN=Google Internet Authority G2
48
+ i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
49
+ -----BEGIN CERTIFICATE-----
50
+ MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
51
+ MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
52
+ YWwgQ0EwHhcNMTMwNDA1MTUxNTU1WhcNMTUwNDA0MTUxNTU1WjBJMQswCQYDVQQG
53
+ EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy
54
+ bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
55
+ AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP
56
+ VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv
57
+ h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE
58
+ ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ
59
+ EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC
60
+ DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB+zCB+DAfBgNVHSMEGDAWgBTAephojYn7
61
+ qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wEgYD
62
+ VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2g
63
+ K4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwPQYI
64
+ KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vZ3RnbG9iYWwtb2NzcC5n
65
+ ZW90cnVzdC5jb20wFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMA0GCSqGSIb3DQEB
66
+ BQUAA4IBAQA21waAESetKhSbOHezI6B1WLuxfoNCunLaHtiONgaX4PCVOzf9G0JY
67
+ /iLIa704XtE7JW4S615ndkZAkNoUyHgN7ZVm2o6Gb4ChulYylYbc3GrKBIxbf/a/
68
+ zG+FA1jDaFETzf3I93k9mTXwVqO94FntT0QJo544evZG0R0SnU++0ED8Vf4GXjza
69
+ HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto
70
+ WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6
71
+ yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx
72
+ -----END CERTIFICATE-----
73
+ 2 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
74
+ i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority
75
+ -----BEGIN CERTIFICATE-----
76
+ MIIDfTCCAuagAwIBAgIDErvmMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT
77
+ MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0
78
+ aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDIwNTIxMDQwMDAwWhcNMTgwODIxMDQwMDAw
79
+ WjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE
80
+ AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
81
+ CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9m
82
+ OSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIu
83
+ T8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6c
84
+ JmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmR
85
+ Cw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5asz
86
+ PeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo4HwMIHtMB8GA1UdIwQYMBaAFEjm
87
+ aPkr0rKV10fYIyAQTzOYkJ/UMB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrM
88
+ TjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjA6BgNVHR8EMzAxMC+g
89
+ LaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxzL3NlY3VyZWNhLmNybDBO
90
+ BgNVHSAERzBFMEMGBFUdIAAwOzA5BggrBgEFBQcCARYtaHR0cHM6Ly93d3cuZ2Vv
91
+ dHJ1c3QuY29tL3Jlc291cmNlcy9yZXBvc2l0b3J5MA0GCSqGSIb3DQEBBQUAA4GB
92
+ AHbhEm5OSxYShjAGsoEIz/AIx8dxfmbuwu3UOx//8PDITtZDOLC5MH0Y0FWDomrL
93
+ NhGc6Ehmo21/uBPUR/6LWlxz/K7ZGzIZOKuXNBSqltLroxwUCEm2u+WR74M26x1W
94
+ b8ravHNjkOR/ez4iyz0H7V84dJzjA1BOoa+Y7mHyhD8S
95
+ -----END CERTIFICATE-----
96
+ ---
97
+ Server certificate
98
+ subject=/C=US/ST=California/L=Mountain View/O=Google Inc/CN=*.google.com
99
+ issuer=/C=US/O=Google Inc/CN=Google Internet Authority G2
100
+ ---
101
+ No client certificate CA names sent
102
+ ---
103
+ SSL handshake has read 3951 bytes and written 444 bytes
104
+ ---
105
+ New, TLSv1/SSLv3, Cipher is RC4-SHA
106
+ Server public key is 2048 bit
107
+ Secure Renegotiation IS supported
108
+ Compression: NONE
109
+ Expansion: NONE
110
+ SSL-Session:
111
+ Protocol : TLSv1
112
+ Cipher : RC4-SHA
113
+ Session-ID: 188ED57889943028AEC5FA0251A329DD1EFB203C74A204916ABF23D8C2D5446F
114
+ Session-ID-ctx:
115
+ Master-Key: 4F2518953BAADC2221CF08C4BD49B75096820BA7DBD2F002041DEC72EEAFDC73DC684D5FEE509563E80D8126430346A2
116
+ Key-Arg : None
117
+ Start Time: 1395678805
118
+ Timeout : 300 (sec)
119
+ Verify return code: 0 (ok)
120
+ ---
@@ -0,0 +1,87 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIHPzCCBiegAwIBAgIIXg768qmYVL0wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
3
+ BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
4
+ cm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwMzEyMDk1MzQwWhcNMTQwNjEwMDAwMDAw
5
+ WjBmMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN
6
+ TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEVMBMGA1UEAwwMKi5n
7
+ b29nbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkDR4dXYy
8
+ +W5fPMG03Tuhsj0lVJKRKob7rUC4yuIeoPuNaEvBzD6nB6OVbBFZfAPpHAvphTw0
9
+ SWZXHEO2CSTtz7gz1S3pIqeMyJC04xd/oWuokT/NpGjeQAkAidTkeedPNu9Ix5EL
10
+ RVKGAQhxXuABth8uvoMrzT5Kx/mrq+YC4kxFevwfaePW88JO+rmb/VVeqmGnzgqU
11
+ dJV/B2euk2X0LX+lzcYw2xgIIBEICI0w3EJNBLzT7WIHbVjK/35owB6f9ni39wsu
12
+ xwCq1J9zTxcgbuSOg3REYtKHxHsMdwIHiuDa80s1Xc1TcMTKsp/aPjAWR/zEiIdB
13
+ niAZhJB2Tmp9FwIDAQABo4IEDDCCBAgwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG
14
+ AQUFBwMCMIIC4gYDVR0RBIIC2TCCAtWCDCouZ29vZ2xlLmNvbYINKi5hbmRyb2lk
15
+ LmNvbYIWKi5hcHBlbmdpbmUuZ29vZ2xlLmNvbYISKi5jbG91ZC5nb29nbGUuY29t
16
+ ghYqLmdvb2dsZS1hbmFseXRpY3MuY29tggsqLmdvb2dsZS5jYYILKi5nb29nbGUu
17
+ Y2yCDiouZ29vZ2xlLmNvLmlugg4qLmdvb2dsZS5jby5qcIIOKi5nb29nbGUuY28u
18
+ dWuCDyouZ29vZ2xlLmNvbS5hcoIPKi5nb29nbGUuY29tLmF1gg8qLmdvb2dsZS5j
19
+ b20uYnKCDyouZ29vZ2xlLmNvbS5jb4IPKi5nb29nbGUuY29tLm14gg8qLmdvb2ds
20
+ ZS5jb20udHKCDyouZ29vZ2xlLmNvbS52boILKi5nb29nbGUuZGWCCyouZ29vZ2xl
21
+ LmVzggsqLmdvb2dsZS5mcoILKi5nb29nbGUuaHWCCyouZ29vZ2xlLml0ggsqLmdv
22
+ b2dsZS5ubIILKi5nb29nbGUucGyCCyouZ29vZ2xlLnB0gg8qLmdvb2dsZWFwaXMu
23
+ Y26CFCouZ29vZ2xlY29tbWVyY2UuY29tghEqLmdvb2dsZXZpZGVvLmNvbYINKi5n
24
+ c3RhdGljLmNvbYIKKi5ndnQxLmNvbYIMKi51cmNoaW4uY29tghAqLnVybC5nb29n
25
+ bGUuY29tghYqLnlvdXR1YmUtbm9jb29raWUuY29tgg0qLnlvdXR1YmUuY29tghYq
26
+ LnlvdXR1YmVlZHVjYXRpb24uY29tggsqLnl0aW1nLmNvbYILYW5kcm9pZC5jb22C
27
+ BGcuY2+CBmdvby5nbIIUZ29vZ2xlLWFuYWx5dGljcy5jb22CCmdvb2dsZS5jb22C
28
+ Emdvb2dsZWNvbW1lcmNlLmNvbYIKdXJjaGluLmNvbYIIeW91dHUuYmWCC3lvdXR1
29
+ YmUuY29tghR5b3V0dWJlZWR1Y2F0aW9uLmNvbTBoBggrBgEFBQcBAQRcMFowKwYI
30
+ KwYBBQUHMAKGH2h0dHA6Ly9wa2kuZ29vZ2xlLmNvbS9HSUFHMi5jcnQwKwYIKwYB
31
+ BQUHMAGGH2h0dHA6Ly9jbGllbnRzMS5nb29nbGUuY29tL29jc3AwHQYDVR0OBBYE
32
+ FGdKaoHIMQ7lHCrxueGq7sgmqowwMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAU
33
+ St0GFhu89mi1dvWBtrtiGrpagS8wFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMDAG
34
+ A1UdHwQpMCcwJaAjoCGGH2h0dHA6Ly9wa2kuZ29vZ2xlLmNvbS9HSUFHMi5jcmww
35
+ DQYJKoZIhvcNAQEFBQADggEBAES1P4XqtSjXyGCuEw0CBJpDSdUCpF/t0hEMPd4+
36
+ VpJPrVlhUkcTRiLUi9PtneA6qkqbkFNtB3rj0TsoEq2AsMfw576zS8YSDYcXqDzX
37
+ S1VsXykK2YnlVapMGXVVZFeXxCSCpb1fMknE/3Y80St5Pyj+Gtl8m2wRmdGX6Hw/
38
+ 6GSs1WsSq0dn7w1nqZKIm9FSlzofCPOyhMpM8GyrygqyBKoQcl0nJbnEiNzQAOum
39
+ YlOlLCmXhf3LyxUhjcaYMulPiXrzsdCikVotfAhPF0BDCDF8/6SQ2y0RYw1NionU
40
+ G6VANTpbplIlpqm+47cjO7VZv55GfZ3hJswfrdrWKIm/1mA=
41
+ -----END CERTIFICATE-----
42
+ -----BEGIN CERTIFICATE-----
43
+ MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
44
+ MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
45
+ YWwgQ0EwHhcNMTMwNDA1MTUxNTU1WhcNMTUwNDA0MTUxNTU1WjBJMQswCQYDVQQG
46
+ EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy
47
+ bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
48
+ AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP
49
+ VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv
50
+ h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE
51
+ ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ
52
+ EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC
53
+ DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB+zCB+DAfBgNVHSMEGDAWgBTAephojYn7
54
+ qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wEgYD
55
+ VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2g
56
+ K4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwPQYI
57
+ KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vZ3RnbG9iYWwtb2NzcC5n
58
+ ZW90cnVzdC5jb20wFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMA0GCSqGSIb3DQEB
59
+ BQUAA4IBAQA21waAESetKhSbOHezI6B1WLuxfoNCunLaHtiONgaX4PCVOzf9G0JY
60
+ /iLIa704XtE7JW4S615ndkZAkNoUyHgN7ZVm2o6Gb4ChulYylYbc3GrKBIxbf/a/
61
+ zG+FA1jDaFETzf3I93k9mTXwVqO94FntT0QJo544evZG0R0SnU++0ED8Vf4GXjza
62
+ HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto
63
+ WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6
64
+ yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx
65
+ -----END CERTIFICATE-----
66
+ -----BEGIN CERTIFICATE-----
67
+ MIIDfTCCAuagAwIBAgIDErvmMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT
68
+ MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0
69
+ aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDIwNTIxMDQwMDAwWhcNMTgwODIxMDQwMDAw
70
+ WjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE
71
+ AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
72
+ CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9m
73
+ OSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIu
74
+ T8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6c
75
+ JmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmR
76
+ Cw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5asz
77
+ PeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo4HwMIHtMB8GA1UdIwQYMBaAFEjm
78
+ aPkr0rKV10fYIyAQTzOYkJ/UMB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrM
79
+ TjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjA6BgNVHR8EMzAxMC+g
80
+ LaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxzL3NlY3VyZWNhLmNybDBO
81
+ BgNVHSAERzBFMEMGBFUdIAAwOzA5BggrBgEFBQcCARYtaHR0cHM6Ly93d3cuZ2Vv
82
+ dHJ1c3QuY29tL3Jlc291cmNlcy9yZXBvc2l0b3J5MA0GCSqGSIb3DQEBBQUAA4GB
83
+ AHbhEm5OSxYShjAGsoEIz/AIx8dxfmbuwu3UOx//8PDITtZDOLC5MH0Y0FWDomrL
84
+ NhGc6Ehmo21/uBPUR/6LWlxz/K7ZGzIZOKuXNBSqltLroxwUCEm2u+WR74M26x1W
85
+ b8ravHNjkOR/ez4iyz0H7V84dJzjA1BOoa+Y7mHyhD8S
86
+ -----END CERTIFICATE-----
87
+
@@ -0,0 +1,12 @@
1
+ # Put your step definitions here
2
+ Then(/^a file named "(.*?)" should exist in my current directory$/) do |filename|
3
+ # Aruba cd's to tmp/aruba before it runs things, ugh
4
+ path = File.join(Dir.pwd, "tmp", "aruba", filename)
5
+ expect(File.exist?(path)).to be_true
6
+ end
7
+
8
+ Then(/^the file named "(.*?)" should contain "(.*?)"$/) do |filename, content|
9
+ # Aruba cd's to tmp/aruba before it runs things, ugh
10
+ path = File.join(Dir.pwd, "tmp", "aruba", filename)
11
+ expect(File.read(path)).to include(content)
12
+ end
@@ -0,0 +1,16 @@
1
+ require 'aruba/cucumber'
2
+ require 'methadone/cucumber'
3
+
4
+ ENV['PATH'] = "#{File.expand_path(File.dirname(__FILE__) + '/../../bin')}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
5
+ LIB_DIR = File.join(File.expand_path(File.dirname(__FILE__)),'..','..','lib')
6
+
7
+ Before do
8
+ # Using "announce" causes massive warnings on 1.9.2
9
+ @puts = true
10
+ @original_rubylib = ENV['RUBYLIB']
11
+ ENV['RUBYLIB'] = LIB_DIR + File::PATH_SEPARATOR + ENV['RUBYLIB'].to_s
12
+ end
13
+
14
+ After do
15
+ ENV['RUBYLIB'] = @original_rubylib
16
+ end
data/lib/certutil.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "certutil/version"
2
+ require "certutil/certificate_parser"
3
+
4
+ module Certutil
5
+ # Your code goes here...
6
+ end
@@ -0,0 +1,124 @@
1
+ require 'open3'
2
+
3
+ class CertificateParser
4
+ include Methadone::CLILogging
5
+ include Methadone::SH
6
+
7
+
8
+ def self.new_from_input(input)
9
+ new_from_file(File.expand_path(input)) || new_from_hostname(input)
10
+ end
11
+
12
+ def self.new_from_file(path)
13
+ # should return nil if it's not a valid cert
14
+
15
+ debug "Parsing #{path}..."
16
+ begin
17
+ string = File.read(path)
18
+ if string
19
+ path_array = path.split(File::SEPARATOR)
20
+ debug "Creating..."
21
+ self.new(string: string, name: path_array.last.gsub(/(\.crt)|(.pem)/, ""), source: :file)
22
+ end
23
+ rescue
24
+ nil
25
+ end
26
+ end
27
+
28
+ def self.new_from_hostname(hostname)
29
+ debug "Fetching certificate from #{hostname}..."
30
+ debug "Creating..."
31
+ string = `openssl s_client -connect #{hostname}:443 -showcerts </dev/null`
32
+ self.new(string: string, name: hostname, source: :hostname) unless string == ""
33
+ end
34
+
35
+ def self.new_from_gist(gist_link)
36
+ # not yet
37
+ end
38
+
39
+ def self.new_from_string(string, opts = {})
40
+ self.new(string: string, name: (opts[:name] || "temp"))
41
+ end
42
+
43
+ def certs
44
+ @certs ||= split_input
45
+ end
46
+
47
+ def decoded
48
+ debug "lazy loading decoded..."
49
+ @decoded ||= decode
50
+ debug "lazy loading done."
51
+
52
+ @decoded
53
+ end
54
+
55
+ def initialize(attrs = {})
56
+ @input = attrs[:string]
57
+ @name = attrs[:name]
58
+ @path = Dir.pwd
59
+ info "Certificate loaded#{' from ' + attrs[:source].to_s if attrs[:source]}: #{@name}."
60
+ end
61
+
62
+ def write_crt_files!
63
+ info "Writing separate .crt files..."
64
+ certs.each_with_index do |cert, i|
65
+ debug "right now, wd is #{Dir.pwd}"
66
+ File.open(File.join(@path, "#{@name}-#{i}.crt"), "w") { |f| f.write(cert) }
67
+ debug "--> Wrote #{@path} -- #{@name}-#{i}.crt."
68
+ end
69
+ end
70
+
71
+ def write_crt_file!
72
+ info "Writing .crt file..."
73
+ joined = certs.join("\n") + "\n"
74
+ File.open(File.join(@path, "#{@name}.crt"), "w") { |f| f.write(joined) }
75
+ debug "--> Wrote #{@path} -- #{@name}.crt."
76
+ end
77
+
78
+ def write_txt_files!
79
+ info "Writing separate .txt files..."
80
+ decoded.each_with_index do |cert, i|
81
+ File.open(File.join(@path, "#{@name}-#{i}-decoded.txt"), "w") { |f| f.write(cert) }
82
+ debug "--> Wrote #{@path}/#{@name}-#{i}-decoded.txt."
83
+ end
84
+ end
85
+
86
+ def write_txt_file!
87
+ info "Writing .txt file..."
88
+ joined = decoded.join("\n-----\n") + "\n"
89
+ File.open(File.join(@path, "#{@name}-decoded.txt"), "w") { |f| f.write(joined) }
90
+ debug "--> Wrote #{@path}/#{@name}-decoded.txt."
91
+ end
92
+
93
+ private
94
+
95
+ def split_input
96
+ debug "splitting..."
97
+ matches = @input.scan(/-+BEGIN CERTIFICATE-----.*?-+END CERTIFICATE-+/m)
98
+ matches = matches.map do |cert|
99
+ # cert.gsub!(/-----BEGIN CERTIFICATE-----\n?/, "")
100
+ # cert.gsub!(/-----END CERTIFICATE-----\n?/, "")
101
+ # cert.chomp
102
+ cert
103
+ end
104
+
105
+ debug "Found #{matches.count} matches."
106
+ matches
107
+ end
108
+
109
+ def decode
110
+ debug "Decoding..."
111
+ output = self.certs.map do |cert|
112
+ Open3.popen3("openssl x509 -text -noout") do |stdin, stdout, stderr|
113
+ stdin.write(cert)
114
+ stdin.close_write
115
+ out = stdout.read
116
+ debug "stdout: #{out}"
117
+ out
118
+ end
119
+ end
120
+
121
+ debug "decode output is #{output}."
122
+ output
123
+ end
124
+ end
@@ -0,0 +1,3 @@
1
+ module Certutil
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ describe CertificateParser do
4
+ before :all do
5
+ @string_data = <<-doc
6
+ -----BEGIN CERTIFICATE-----
7
+ abcdef
8
+ -----END CERTIFICATE-----
9
+ -----BEGIN CERTIFICATE-----
10
+ 123456
11
+ -----END CERTIFICATE-----
12
+ doc
13
+ end
14
+
15
+ describe ".new_from_hostname" do
16
+ it "creates a CertificateParser from a valid file" do
17
+ @cp = CertificateParser.new_from_file(File.join(Dir.pwd, "features/google-full.crt"))
18
+ expect(@cp).to be_a CertificateParser
19
+ expect(@cp.certs).to be_a Array
20
+ end
21
+
22
+ it "returns nil if the file doesn't exist" do
23
+ @cp = CertificateParser.new_from_file(File.join(Dir.pwd, "nil.crt"))
24
+ expect(@cp).to be_nil
25
+ end
26
+ end
27
+
28
+ describe ".new_from_file" do
29
+ it "creates a CertificateParser from a valid hostname" do
30
+ @cp = CertificateParser.new_from_hostname("google.com")
31
+ expect(@cp).to be_a CertificateParser
32
+ expect(@cp.certs).to be_a Array
33
+ end
34
+
35
+ it "returns nil if it can't find a certificate" do
36
+ @cp = CertificateParser.new_from_hostname("fake.domain")
37
+ expect(@cp).to be_nil
38
+ end
39
+ end
40
+
41
+ describe ".new_from_input" do
42
+ it "creates a CertificateParser from hostname" do
43
+ expect(CertificateParser.new_from_hostname("google.com")).to be_a CertificateParser
44
+ end
45
+
46
+ it "creates a CertificateParser from a file" do
47
+ expect(CertificateParser.new_from_file(File.join(Dir.pwd, "features/google-full.crt"))).to be_a CertificateParser
48
+ end
49
+ end
50
+
51
+ describe "#certs" do
52
+ it "splits a cert string into an array" do
53
+ @cp = CertificateParser.new_from_string(@string_data)
54
+ expect(@cp.certs.count).to eq(2)
55
+ expect(@cp.certs[0]).to include("abcdef")
56
+ expect(@cp.certs[1]).to include("123456")
57
+ end
58
+ end
59
+
60
+ describe "decoded" do
61
+ it "decodes certificates" do
62
+ @cp = CertificateParser.new_from_file("features/google-full.crt")
63
+ @cp.decoded.first.should include("Google")
64
+ end
65
+ end
66
+ end
67
+
@@ -0,0 +1,10 @@
1
+ require 'bundler/setup'
2
+ require 'methadone'
3
+ Bundler.setup
4
+
5
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
6
+ require File.join(APP_ROOT, 'lib/certutil') # so rspec knows where your file could be
7
+
8
+ RSpec.configure do |config|
9
+ # some (optional) config here
10
+ end
metadata ADDED
@@ -0,0 +1,156 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: certutil
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Chad Bailey
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rdoc
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: aruba
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.9.2
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.9.2
83
+ - !ruby/object:Gem::Dependency
84
+ name: methadone
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 1.3.2
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 1.3.2
97
+ description: A tool for decoding and analyzing SSL certificates.
98
+ email:
99
+ - chad@heroku.com
100
+ executables:
101
+ - certutil
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - ".rspec"
107
+ - Gemfile
108
+ - Gemfile.lock
109
+ - LICENSE.txt
110
+ - README.md
111
+ - README.rdoc
112
+ - Rakefile
113
+ - bin/certutil
114
+ - certutil.gemspec
115
+ - features/certutil.feature
116
+ - features/google-full.crt
117
+ - features/google-short.crt
118
+ - features/step_definitions/certdecoder_steps.rb
119
+ - features/support/env.rb
120
+ - lib/certutil.rb
121
+ - lib/certutil/certificate_parser.rb
122
+ - lib/certutil/version.rb
123
+ - spec/certificate_parser_spec.rb
124
+ - spec/spec_helper.rb
125
+ homepage: ''
126
+ licenses:
127
+ - MIT
128
+ metadata: {}
129
+ post_install_message:
130
+ rdoc_options: []
131
+ require_paths:
132
+ - lib
133
+ required_ruby_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ required_rubygems_version: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ requirements: []
144
+ rubyforge_project:
145
+ rubygems_version: 2.2.2
146
+ signing_key:
147
+ specification_version: 4
148
+ summary: A tool for decoding and analyzing SSL certificates.
149
+ test_files:
150
+ - features/certutil.feature
151
+ - features/google-full.crt
152
+ - features/google-short.crt
153
+ - features/step_definitions/certdecoder_steps.rb
154
+ - features/support/env.rb
155
+ - spec/certificate_parser_spec.rb
156
+ - spec/spec_helper.rb