certutil 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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