eassl3 3.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 975e8d4b5b91a9681f9b719d7bbd5db546433203
4
+ data.tar.gz: 0f421b863e64b983a436716b3242593c30e74313
5
+ SHA512:
6
+ metadata.gz: 4fe2c4f90e9ca7f5b4bf97d53a511d42b1fd2e6fa9549929a1d66f84e5b8250692a15039be41dce41b88d1fe873c76a7cfa97cacdbd28310973dac7fde365186
7
+ data.tar.gz: d84e442c0a7d8e64b6026312960379fc8e84baec3303d4f3bd63db01351db195c306b9eb27fefab183566e6a52f609f6ebbc7ebe4d3d8a735650e90569f54735
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.0
@@ -0,0 +1,13 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
+
5
+ We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion.
6
+
7
+ Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
+
9
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
+
11
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12
+
13
+ This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in eassl.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,32 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ eassl3 (3.0.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.2.5)
10
+ rake (10.4.2)
11
+ rspec (3.3.0)
12
+ rspec-core (~> 3.3.0)
13
+ rspec-expectations (~> 3.3.0)
14
+ rspec-mocks (~> 3.3.0)
15
+ rspec-core (3.3.1)
16
+ rspec-support (~> 3.3.0)
17
+ rspec-expectations (3.3.0)
18
+ diff-lcs (>= 1.2.0, < 2.0)
19
+ rspec-support (~> 3.3.0)
20
+ rspec-mocks (3.3.0)
21
+ diff-lcs (>= 1.2.0, < 2.0)
22
+ rspec-support (~> 3.3.0)
23
+ rspec-support (3.3.0)
24
+
25
+ PLATFORMS
26
+ ruby
27
+
28
+ DEPENDENCIES
29
+ bundler (~> 1.8)
30
+ eassl3!
31
+ rake (~> 10.0)
32
+ rspec
data/LICENSE.txt ADDED
@@ -0,0 +1,57 @@
1
+ Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.co.jp>.
2
+ You can redistribute it and/or modify it under either the terms of the GPL
3
+ (see COPYING.txt file), or the conditions below:
4
+
5
+ 1. You may make and give away verbatim copies of the source form of the
6
+ software without restriction, provided that you duplicate all of the
7
+ original copyright notices and associated disclaimers.
8
+
9
+ 2. You may modify your copy of the software in any way, provided that
10
+ you do at least ONE of the following:
11
+
12
+ a) place your modifications in the Public Domain or otherwise
13
+ make them Freely Available, such as by posting said
14
+ modifications to Usenet or an equivalent medium, or by allowing
15
+ the author to include your modifications in the software.
16
+
17
+ b) use the modified software only within your corporation or
18
+ organization.
19
+
20
+ c) rename any non-standard executables so the names do not conflict
21
+ with standard executables, which must also be provided.
22
+
23
+ d) make other distribution arrangements with the author.
24
+
25
+ 3. You may distribute the software in object code or executable
26
+ form, provided that you do at least ONE of the following:
27
+
28
+ a) distribute the executables and library files of the software,
29
+ together with instructions (in the manual page or equivalent)
30
+ on where to get the original distribution.
31
+
32
+ b) accompany the distribution with the machine-readable source of
33
+ the software.
34
+
35
+ c) give non-standard executables non-standard names, with
36
+ instructions on where to get the original software distribution.
37
+
38
+ d) make other distribution arrangements with the author.
39
+
40
+ 4. You may modify and include the part of the software into any other
41
+ software (possibly commercial). But some files in the distribution
42
+ are not written by the author, so that they are not under this terms.
43
+
44
+ They are gc.c(partly), utils.c(partly), regex.[ch], st.[ch] and some
45
+ files under the ./missing directory. See each file for the copying
46
+ condition.
47
+
48
+ 5. The scripts and library files supplied as input to or produced as
49
+ output from the software do not automatically fall under the
50
+ copyright of the software, but belong to whomever generated them,
51
+ and may be sold commercially, and may be aggregated with this
52
+ software.
53
+
54
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
55
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
56
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
57
+ PURPOSE.
data/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # Eassl
2
+
3
+ EaSSL is a library aimed at making openSSL certificate generation and management easier and more ruby-ish.
4
+
5
+ Forked from https://github.com/chrisa/eassl and patched using available pull requests for that project and additional development for better utilizing CSR details and using SHA512 for signing by default. Rcov and Jeweler were switched out in favor of Rspec and Bundler.
6
+
7
+ Ruby license, inherited from the rubyforge project.
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'eassl3'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install eassl3
24
+
25
+ ## Usage
26
+
27
+ Generating a CSR and private key:
28
+ options = {
29
+ :department => 'web sites',
30
+ :common_name => 'www.mydomain.com',
31
+ :organization, => 'My Org'
32
+ :email => 'test@test.com',
33
+ :city => 'Fargo',
34
+ :state => 'North Dakota',
35
+ :country => 'USA',
36
+ :subject_alt_name => ['www.mydomain.com', 'mydomain.com']
37
+ }
38
+
39
+ ea_key = EaSSL::Key.new
40
+ ea_name = EaSSL::CertificateName.new(options)
41
+ ea_csr = EaSSL::SigningRequest.new(:name => ea_name, :key => ea_key)
42
+
43
+ csr = ea_csr.ssl.to_s
44
+ key = ea_key.private_key.to_s
45
+
46
+ ## Development
47
+
48
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
49
+
50
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
51
+
52
+ ## Contributing
53
+
54
+ 1. Fork it ( https://github.com/[my-github-username]/eassl/fork )
55
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
56
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
57
+ 4. Push to the branch (`git push origin my-new-feature`)
58
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "eassl"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
data/eassl.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'eassl/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "eassl3"
8
+ spec.version = Eassl::VERSION
9
+ spec.authors = ["Peter Bell", "Paul Nicholson", "Paul Meserve", "Chris Andrews"]
10
+ spec.email = ["bellpeterm+github@gmail.com"]
11
+
12
+ # if spec.respond_to?(:metadata)
13
+ # spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com' to prevent pushes to rubygems.org, or delete to allow pushes to any server."
14
+ # end
15
+
16
+ spec.summary = %q{EaSSL is a library aimed at making openSSL certificate generation and management easier and more ruby-ish.}
17
+ spec.description = %q{This gem is a drop-in replacement for eassl 0.1.1643}
18
+ spec.homepage = "https://github.com/bellpeterm/eassl"
19
+ spec.license = "Ruby"
20
+
21
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
22
+ spec.bindir = "exe"
23
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.require_paths = ["lib"]
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.8"
27
+ spec.add_development_dependency "rake", "~> 10.0"
28
+ spec.add_development_dependency "rspec"
29
+ end
@@ -0,0 +1,59 @@
1
+ require 'openssl'
2
+ require 'eassl'
3
+ module EaSSL
4
+ # Author:: Paul Nicholson (mailto:paul@webpowerdesign.net)
5
+ # Co-Author:: Adam Williams (mailto:adam@thewilliams.ws)
6
+ # Copyright:: Copyright (c) 2006 WebPower Design
7
+ # License:: Distributes under the same terms as Ruby
8
+ class AuthorityCertificate
9
+ def initialize(options)
10
+ @options = {
11
+ :key => nil, #required
12
+ :name => {}, #required, CertificateName
13
+ }.update(options)
14
+ end
15
+
16
+ def ssl
17
+ unless @ssl
18
+ cert = OpenSSL::X509::Certificate.new
19
+ cert.not_before = Time.now
20
+ cert.subject = cert.issuer = CertificateName.new({ :common_name => "CA" }.update(@options[:name])).name
21
+ cert.not_after = cert.not_before + (365 * 5) * 24 * 60 * 60
22
+ cert.public_key = @options[:key].public_key
23
+ cert.serial = 1
24
+ cert.version = 2 # X509v3
25
+
26
+ ef = OpenSSL::X509::ExtensionFactory.new
27
+ ef.subject_certificate = cert
28
+ ef.issuer_certificate = cert
29
+ cert.extensions = [
30
+ ef.create_extension("basicConstraints","CA:TRUE"),
31
+ ef.create_extension("keyUsage", "cRLSign, keyCertSign"),
32
+ ef.create_extension("subjectKeyIdentifier", "hash"),
33
+ ef.create_extension("nsComment", "Ruby/OpenSSL/EaSSL Generated Certificate"),
34
+ ]
35
+ cert.add_extension(ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always"))
36
+ cert.sign(@options[:key].private_key, OpenSSL::Digest::SHA1.new)
37
+ @ssl = cert
38
+ end
39
+ @ssl
40
+ end
41
+
42
+ def method_missing(method)
43
+ ssl.send(method)
44
+ end
45
+
46
+ def load(pem_string)
47
+ begin
48
+ @ssl = OpenSSL::X509::Certificate.new(pem_string)
49
+ rescue
50
+ raise "CertificateLoader: Error loading certificate"
51
+ end
52
+ self
53
+ end
54
+
55
+ def self.load(pem_file_path)
56
+ new({}).load(File.read(pem_file_path))
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,109 @@
1
+ require 'openssl'
2
+ require 'eassl'
3
+ module EaSSL
4
+ # Author:: Paul Nicholson (mailto:paul@webpowerdesign.net)
5
+ # Co-Author:: Adam Williams (mailto:adam@thewilliams.ws)
6
+ # Copyright:: Copyright (c) 2006 WebPower Design
7
+ # License:: Distributes under the same terms as Ruby
8
+ class Certificate
9
+ def initialize(options)
10
+ @options = {
11
+ :days_valid => (365 * 5),
12
+ :signing_request => nil, #required
13
+ :ca_certificate => nil, #required
14
+ :comment => "Ruby/OpenSSL/EaSSL Generated Certificate",
15
+ :type => "server",
16
+ :subject_alt_name => nil, #optional e.g. [ "*.example.com", "example.com" ]
17
+ :override_req => true
18
+ }.update(options)
19
+ end
20
+
21
+ def ssl
22
+ unless @ssl
23
+ @ssl = OpenSSL::X509::Certificate.new
24
+ @ssl.not_before = Time.now
25
+ @ssl.subject = @options[:signing_request].subject
26
+ @ssl.issuer = @options[:ca_certificate]? @options[:ca_certificate].subject : @ssl.subject
27
+ @ssl.not_after = @ssl.not_before + @options[:days_valid] * 24 * 60 * 60
28
+ @ssl.public_key = @options[:signing_request].public_key
29
+ @ssl.serial = @options[:serial] || 2
30
+ @ssl.version = 2 # X509v3
31
+
32
+ ef = OpenSSL::X509::ExtensionFactory.new
33
+ ef.subject_certificate = @ssl
34
+ ef.issuer_certificate = @options[:ca_certificate]? @options[:ca_certificate].ssl : @ssl
35
+ @ssl.extensions = [ ef.create_extension("subjectKeyIdentifier", "hash") ]
36
+ @ssl.add_extension(ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always"))
37
+
38
+ extensions = Array.new
39
+
40
+ extensions << ef.create_extension("basicConstraints","CA:FALSE")
41
+ extensions << ef.create_extension("nsComment", @options[:comment])
42
+
43
+ case @options[:type]
44
+ when 'server'
45
+ extensions << ef.create_extension("keyUsage", "digitalSignature,keyEncipherment")
46
+ extensions << ef.create_extension("extendedKeyUsage", "serverAuth")
47
+ when 'client'
48
+ extensions << ef.create_extension("keyUsage", "nonRepudiation,digitalSignature,keyEncipherment")
49
+ extensions << ef.create_extension("extendedKeyUsage", "clientAuth,emailProtection")
50
+ end
51
+
52
+ #add subject alternate names
53
+ if @options[:subject_alt_name]
54
+ subjectAltName = @options[:subject_alt_name].map { |d| "DNS: #{d}" }.join(',')
55
+ extensions << ef.create_extension("subjectAltName", subjectAltName)
56
+ end
57
+
58
+ if sr = @options[:signing_request]
59
+ sr.extensions.each do |ext|
60
+ if @options[:override_req] # CA extensions take precedence in merge, default behavior
61
+ extensions << ext unless extensions.any? { |e| e.oid == ext.oid }
62
+ else # Req extensions take precedence in merge
63
+ extensions.delete_if { |e| e.oid == ext.oid }
64
+ extensions << ext
65
+ end
66
+ end
67
+ end
68
+
69
+ extensions.each do |ext|
70
+ @ssl.add_extension(ext)
71
+ end
72
+
73
+ end
74
+ @ssl
75
+ end
76
+
77
+ def sign(ca_key, digest=OpenSSL::Digest::SHA1.new)
78
+ ssl.sign(ca_key.private_key, digest)
79
+ end
80
+
81
+ def to_pem
82
+ ssl.to_pem
83
+ end
84
+
85
+ # Returns a SHA1 fingerprint of the certificate in the OpenSSL style
86
+ def sha1_fingerprint
87
+ Digest::SHA1.hexdigest(ssl.to_der).upcase.gsub(/(..)/, '\1:').chop
88
+ end
89
+
90
+ # This method is used to intercept and pass-thru calls to openSSL methods and instance
91
+ # variables.
92
+ def method_missing(method)
93
+ ssl.send(method)
94
+ end
95
+
96
+ def self.load(pem_file_path)
97
+ new({}).load(File.read(pem_file_path))
98
+ end
99
+
100
+ def load(pem_string)
101
+ begin
102
+ @ssl = OpenSSL::X509::Certificate.new(pem_string)
103
+ rescue
104
+ raise "CertificateLoader: Error loading certificate"
105
+ end
106
+ self
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,46 @@
1
+ require 'openssl'
2
+ require 'eassl'
3
+ module EaSSL
4
+ # Author:: Paul Nicholson (mailto:paul@webpowerdesign.net)
5
+ # Co-Author:: Adam Williams (mailto:adam@thewilliams.ws)
6
+ # Copyright:: Copyright (c) 2006 WebPower Design
7
+ # License:: Distributes under the same terms as Ruby
8
+ class CertificateAuthority
9
+ attr_reader :key, :certificate, :serial
10
+ def initialize(options = {})
11
+ if options[:key] && options[:certificate] && options[:serial]
12
+ @key = options[:key]
13
+ @certificate = options[:certificate]
14
+ @serial = options[:serial]
15
+ else
16
+ options[:name] ||= {}
17
+ @key = Key.new({:password => 'ca_ssl_password'}.update(options))
18
+ @certificate = AuthorityCertificate.new(:key => @key, :name => options[:name])
19
+ @serial = Serial.new(:next => 1)
20
+ end
21
+ end
22
+
23
+ def self.load(options)
24
+ key = Key.load(File.join(options[:ca_path], 'cakey.pem'), options[:ca_password])
25
+ certificate = AuthorityCertificate.load(File.join(options[:ca_path], 'cacert.pem'))
26
+ serial = Serial.load(File.join(options[:ca_path], 'serial.txt'))
27
+ self.new(:key => key, :certificate => certificate, :serial => serial)
28
+ end
29
+
30
+ def create_certificate(signing_request, type='server', days_valid=nil, digest=OpenSSL::Digest::SHA512.new)
31
+ options = {
32
+ :signing_request => signing_request,
33
+ :ca_certificate => @certificate,
34
+ :serial => @serial.issue_serial,
35
+ :type => type
36
+ }
37
+ if days_valid
38
+ options[:days_valid] = days_valid
39
+ end
40
+ cert = Certificate.new(options)
41
+ @serial.save!
42
+ cert.sign(@key, digest)
43
+ cert
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,40 @@
1
+ require 'openssl'
2
+ require 'eassl'
3
+ module EaSSL
4
+ # Author:: Paul Nicholson (mailto:paul@webpowerdesign.net)
5
+ # Co-Author:: Adam Williams (mailto:adam@thewilliams.ws)
6
+ # Copyright:: Copyright (c) 2006 WebPower Design
7
+ # License:: Distributes under the same terms as Ruby
8
+ class CertificateName
9
+ def initialize(options)
10
+ @options = options
11
+ end
12
+
13
+ def ssl
14
+ name_mapping = [
15
+ ['C', :country, OpenSSL::ASN1::PRINTABLESTRING],
16
+ ['ST', :state, OpenSSL::ASN1::PRINTABLESTRING],
17
+ ['L', :city, OpenSSL::ASN1::PRINTABLESTRING],
18
+ ['O', :organization, OpenSSL::ASN1::UTF8STRING],
19
+ ['OU', :department, OpenSSL::ASN1::UTF8STRING],
20
+ ['CN', :common_name, OpenSSL::ASN1::UTF8STRING],
21
+ ['emailAddress', :email, OpenSSL::ASN1::IA5STRING]
22
+ ]
23
+
24
+ name = []
25
+ name_mapping.each do |k|
26
+ name << [k[0], @options[k[1]], k[2]] if @options[k[1]]
27
+ end
28
+
29
+ OpenSSL::X509::Name.new(name)
30
+ end
31
+
32
+ def name
33
+ ssl
34
+ end
35
+
36
+ def options
37
+ @options
38
+ end
39
+ end
40
+ end
data/lib/eassl/key.rb ADDED
@@ -0,0 +1,70 @@
1
+ require 'openssl'
2
+ require 'eassl'
3
+ module EaSSL
4
+ # == EaSSL::Key creates and manages openSSL keys
5
+ #
6
+ # Author:: Paul Nicholson (mailto:paul@webpowerdesign.net)
7
+ # Co-Author:: Adam Williams (mailto:adam@thewilliams.ws)
8
+ # Copyright:: Copyright (c) 2006 WebPower Design
9
+ # License:: Distributes under the same terms as Ruby
10
+ #
11
+ # ==== Usage
12
+ #
13
+ # ===== Availible Methods - including methods provided by openSSL::PKey:
14
+ # * public_key
15
+ # * private_key
16
+ # * to_text
17
+ class Key
18
+ # Create new Key using the provided options or using the defaults
19
+ def initialize(options = {}) #:params: options
20
+ @options = {
21
+ :bits => 2048,
22
+ :password => 'ssl_password',
23
+ }.update(options)
24
+ end
25
+
26
+ def ssl
27
+ unless @ssl
28
+ # <Should use some kind of logger on this>
29
+ # $stderr.puts "Generating #{@options[:bits]} bit key\n"
30
+ @ssl = OpenSSL::PKey::RSA::new(@options[:bits])
31
+ end
32
+ @ssl
33
+ end
34
+
35
+ # This method is used to intercept and pass-thru calls to openSSL methods and instance
36
+ # variables.
37
+ def method_missing(method) # :nodoc:
38
+ ssl.send(method)
39
+ end
40
+
41
+ def private_key
42
+ ssl
43
+ end
44
+
45
+ # Returns the length of the key in bits
46
+ def length
47
+ ssl.n.num_bytes * 8
48
+ end
49
+
50
+ # Export the encrypted key, returns a string
51
+ def to_pem
52
+ ssl.export(OpenSSL::Cipher::DES.new('EDE3-CBC'), @options[:password])
53
+ end
54
+
55
+ # Decrypt and load a PEM encoded Key from the file system with the provided password.
56
+ def self.load(pem_file_path, password=nil)
57
+ new.load(File.read(pem_file_path), password)
58
+ end
59
+
60
+ # Decrypt and load a PEM encoded Key from provided string with the provided password.
61
+ def load(pem_string, password=nil)
62
+ begin
63
+ @ssl = OpenSSL::PKey::RSA::new(pem_string, password || @options[:password])
64
+ rescue
65
+ raise "KeyLoader: Error decrypting key with password"
66
+ end
67
+ self
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,33 @@
1
+ require 'eassl'
2
+ module EaSSL
3
+ # Author:: Chris Andrews (mailto:chris@nodnol.org)
4
+ # Copyright:: Copyright (c) 2011 Chris Andrews
5
+ # License:: Distributes under the same terms as Ruby
6
+ class Serial
7
+ attr_reader :next
8
+ def initialize(options = {})
9
+ @next = options[:next]
10
+ @path = options[:path]
11
+ end
12
+
13
+ def self.load(serial_file_path)
14
+ hex_string = (File.read(serial_file_path))
15
+ self.new(:next => Integer("0x#{hex_string}"), :path => serial_file_path)
16
+ end
17
+
18
+ def save!
19
+ if @path
20
+ hex_string = sprintf("%04X", @next)
21
+ File.open(@path, 'w') do |io|
22
+ io.write "#{hex_string}\n"
23
+ end
24
+ end
25
+ end
26
+
27
+ def issue_serial
28
+ @next = @next + 1
29
+ @next - 1
30
+ end
31
+ end
32
+ end
33
+
@@ -0,0 +1,91 @@
1
+ require 'openssl'
2
+ require 'eassl'
3
+ module EaSSL
4
+ # Author:: Paul Nicholson (mailto:paul@webpowerdesign.net)
5
+ # Co-Author:: Adam Williams (mailto:adam@thewilliams.ws)
6
+ # Copyright:: Copyright (c) 2006 WebPower Design
7
+ # License:: Distributes under the same terms as Ruby
8
+ class SigningRequest
9
+ attr_reader :extensions
10
+
11
+ def initialize(options = {})
12
+ @options = {
13
+ :name => {}, #required, CertificateName
14
+ :key => nil, #required
15
+ :digest => OpenSSL::Digest::SHA512.new,
16
+ }.update(options)
17
+ @options[:key] ||= Key.new(@options)
18
+ end
19
+
20
+ def ssl
21
+ unless @ssl
22
+ @ssl = OpenSSL::X509::Request.new
23
+ @ssl.version = 0
24
+ @ssl.subject = CertificateName.new(@options[:name].options).name
25
+ @ssl.public_key = key.public_key
26
+
27
+ @extensions = Array.new
28
+ ef = OpenSSL::X509::ExtensionFactory.new
29
+
30
+ case @options[:type]
31
+ when 'subordinate'
32
+ @extensions << ef.create_extension("basicConstraints","CA:TRUE")
33
+ when 'server'
34
+ @extensions << ef.create_extension("basicConstraints","CA:FALSE")
35
+ @extensions << ef.create_extension("keyUsage", "digitalSignature,keyEncipherment")
36
+ @extensions << ef.create_extension("extendedKeyUsage", "serverAuth")
37
+ when 'client'
38
+ @extensions << ef.create_extension("basicConstraints","CA:FALSE")
39
+ @extensions << ef.create_extension("keyUsage", "nonRepudiation,digitalSignature,keyEncipherment")
40
+ @extensions << ef.create_extension("extendedKeyUsage", "clientAuth,emailProtection")
41
+ end
42
+
43
+ if @options[:subject_alt_name]
44
+ subjectAltName = @options[:subject_alt_name].map { |d| "DNS: #{d}" }.join(',')
45
+ @extensions << ef.create_extension("subjectAltName", subjectAltName)
46
+ end
47
+
48
+ if @extensions.count > 0
49
+ seq = OpenSSL::ASN1::Sequence.new(extensions)
50
+ set = OpenSSL::ASN1::Set.new([seq])
51
+ attr = OpenSSL::X509::Attribute.new('extReq', set)
52
+ @ssl.add_attribute(attr)
53
+ end
54
+
55
+ @ssl.sign(key.private_key, @options[:digest])
56
+ end
57
+ @ssl
58
+ end
59
+
60
+ def key
61
+ @options[:key]
62
+ end
63
+
64
+ def options
65
+ @options
66
+ end
67
+
68
+ def to_pem
69
+ ssl.to_pem
70
+ end
71
+
72
+ # This method is used to intercept and pass-thru calls to openSSL methods and instance
73
+ # variables.
74
+ def method_missing(method)
75
+ ssl.send(method)
76
+ end
77
+
78
+ def self.load(pem_file_path)
79
+ new.load(File.read(pem_file_path))
80
+ end
81
+
82
+ def load(pem_string)
83
+ begin
84
+ @ssl = OpenSSL::X509::Request.new(pem_string)
85
+ rescue
86
+ raise "SigningRequestLoader: Error loading signing request"
87
+ end
88
+ self
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,3 @@
1
+ module Eassl
2
+ VERSION = "3.0.0"
3
+ end
data/lib/eassl.rb ADDED
@@ -0,0 +1,71 @@
1
+ require 'openssl'
2
+ require 'fileutils'
3
+ $:.unshift File.expand_path(File.dirname(__FILE__))
4
+ # = About EaSSL
5
+ #
6
+ # Author:: Paul Nicholson (mailto:paul@webpowerdesign.net)
7
+ # Co-Author:: Adam Williams (mailto:adam@thewilliams.ws)
8
+ # Copyright:: Copyright (c) 2006 WebPower Design
9
+ # License:: Distributes under the same terms as Ruby
10
+ #
11
+ # By requiring <tt>eassl</tt>, you can load the full set of EaSSL classes.
12
+ #
13
+ # For a full list of features and instructions, see the #README.
14
+ #
15
+ # EaSSL is a module containing all of the great EaSSL classes for creating
16
+ # and managing openSSL keys, signing request, and certificates.
17
+ #
18
+ # * EaSSL::Key: the class for loading and creating SSL keys
19
+ # * EaSSL::SigningRequest: the class for creating SSL signing requests
20
+
21
+ module EaSSL
22
+ VERSION = '2.0.0'
23
+
24
+ def self.generate_self_signed(options)
25
+ ca = CertificateAuthority.new({:bits => 1024}.update(options[:ca_options]||{}))
26
+ sr = SigningRequest.new(options)
27
+ cert = ca.create_certificate(sr)
28
+ [ca, sr, cert]
29
+ end
30
+
31
+ def self.config_webrick(webrick_config, options = {})
32
+ hostname = `hostname`.strip
33
+ eassl_host_dir = "#{File.expand_path('~')}/.eassl/#{hostname}"
34
+ ca_cert_file = "#{eassl_host_dir}/ca.crt"
35
+ ca_key_file = "#{eassl_host_dir}/ca.key"
36
+ server_key_file = "#{eassl_host_dir}/server.key"
37
+ server_cert_file = "#{eassl_host_dir}/server.crt"
38
+ FileUtils.rm_rf(eassl_host_dir) if options[:force_regeneration]
39
+
40
+ if File.exist?(server_cert_file)
41
+ key = Key.load(server_key_file, 'countinghouse1234')
42
+ cert = Certificate.load(server_cert_file)
43
+ else
44
+ ca, sr, cert = self.generate_self_signed({:name => {:common_name => hostname}, :bits => 1024}.update(options))
45
+ key = sr.key
46
+ FileUtils.makedirs(eassl_host_dir)
47
+ File.open(%(#{ca_cert_file}.pem), "w", 0777) {|f| f << ca.certificate.to_pem }
48
+ File.open(%(#{ca_cert_file}.der), "w", 0777) {|f| f << ca.certificate.to_der }
49
+ File.open(ca_key_file, "w", 0777) {|f| f << ca.key.to_pem }
50
+ File.open(server_key_file, "w", 0777) {|f| f << key.to_pem }
51
+ File.open(server_cert_file, "w", 0777) {|f| f << cert.to_pem }
52
+ end
53
+
54
+ webrick_config.update({
55
+ :SSLEnable => true,
56
+ :SSLPrivateKey => key.ssl,
57
+ :SSLCertificate => cert.ssl,
58
+ :SSLExtraChainCert => [Certificate.load(%(#{ca_cert_file}.pem)).ssl],
59
+ :SSLVerifyClient => OpenSSL::SSL::VERIFY_NONE,
60
+ :SSLStartImmediately => true,
61
+ })
62
+ end
63
+ end
64
+
65
+ require 'eassl/key'
66
+ require 'eassl/certificate_name'
67
+ require 'eassl/signing_request'
68
+ require 'eassl/certificate'
69
+ require 'eassl/authority_certificate'
70
+ require 'eassl/certificate_authority'
71
+ require 'eassl/serial'
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: eassl3
3
+ version: !ruby/object:Gem::Version
4
+ version: 3.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Peter Bell
8
+ - Paul Nicholson
9
+ - Paul Meserve
10
+ - Chris Andrews
11
+ autorequire:
12
+ bindir: exe
13
+ cert_chain: []
14
+ date: 2015-06-18 00:00:00.000000000 Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: bundler
18
+ requirement: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - "~>"
21
+ - !ruby/object:Gem::Version
22
+ version: '1.8'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '1.8'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - "~>"
35
+ - !ruby/object:Gem::Version
36
+ version: '10.0'
37
+ type: :development
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '10.0'
44
+ - !ruby/object:Gem::Dependency
45
+ name: rspec
46
+ requirement: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ type: :development
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ description: This gem is a drop-in replacement for eassl 0.1.1643
59
+ email:
60
+ - bellpeterm+github@gmail.com
61
+ executables: []
62
+ extensions: []
63
+ extra_rdoc_files: []
64
+ files:
65
+ - ".gitignore"
66
+ - ".rspec"
67
+ - ".travis.yml"
68
+ - CODE_OF_CONDUCT.md
69
+ - Gemfile
70
+ - Gemfile.lock
71
+ - LICENSE.txt
72
+ - README.md
73
+ - Rakefile
74
+ - bin/console
75
+ - bin/setup
76
+ - eassl.gemspec
77
+ - lib/eassl.rb
78
+ - lib/eassl/authority_certificate.rb
79
+ - lib/eassl/certificate.rb
80
+ - lib/eassl/certificate_authority.rb
81
+ - lib/eassl/certificate_name.rb
82
+ - lib/eassl/key.rb
83
+ - lib/eassl/serial.rb
84
+ - lib/eassl/signing_request.rb
85
+ - lib/eassl/version.rb
86
+ homepage: https://github.com/bellpeterm/eassl
87
+ licenses:
88
+ - Ruby
89
+ metadata: {}
90
+ post_install_message:
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubyforge_project:
106
+ rubygems_version: 2.4.5
107
+ signing_key:
108
+ specification_version: 4
109
+ summary: EaSSL is a library aimed at making openSSL certificate generation and management
110
+ easier and more ruby-ish.
111
+ test_files: []