certificate_authority 0.1.6 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +11 -0
  5. data/Gemfile +2 -8
  6. data/Gemfile.lock +71 -31
  7. data/README.rdoc +91 -2
  8. data/Rakefile +6 -41
  9. data/certificate_authority.gemspec +22 -66
  10. data/lib/certificate_authority.rb +6 -5
  11. data/lib/certificate_authority/certificate.rb +91 -36
  12. data/lib/certificate_authority/certificate_revocation_list.rb +34 -14
  13. data/lib/certificate_authority/core_extensions.rb +46 -0
  14. data/lib/certificate_authority/distinguished_name.rb +64 -16
  15. data/lib/certificate_authority/extensions.rb +417 -45
  16. data/lib/certificate_authority/key_material.rb +30 -9
  17. data/lib/certificate_authority/ocsp_handler.rb +75 -5
  18. data/lib/certificate_authority/pkcs11_key_material.rb +0 -2
  19. data/lib/certificate_authority/revocable.rb +14 -0
  20. data/lib/certificate_authority/serial_number.rb +15 -2
  21. data/lib/certificate_authority/signing_request.rb +91 -0
  22. data/lib/certificate_authority/validations.rb +31 -0
  23. data/lib/certificate_authority/version.rb +3 -0
  24. metadata +76 -48
  25. data/VERSION.yml +0 -5
  26. data/spec/spec_helper.rb +0 -4
  27. data/spec/units/certificate_authority_spec.rb +0 -4
  28. data/spec/units/certificate_revocation_list_spec.rb +0 -68
  29. data/spec/units/certificate_spec.rb +0 -428
  30. data/spec/units/distinguished_name_spec.rb +0 -59
  31. data/spec/units/extensions_spec.rb +0 -115
  32. data/spec/units/key_material_spec.rb +0 -100
  33. data/spec/units/ocsp_handler_spec.rb +0 -104
  34. data/spec/units/pkcs11_key_material_spec.rb +0 -41
  35. data/spec/units/serial_number_spec.rb +0 -20
  36. data/spec/units/signing_entity_spec.rb +0 -4
  37. data/spec/units/units_helper.rb +0 -1
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e413d44d788e07a95a90b5849298f41796dbd57dce8fe08a0713191ae812798c
4
+ data.tar.gz: '059b6bee928fdcc1cebd04c6dff6890f7179d66094d6af17c549db7ef1811e56'
5
+ SHA512:
6
+ metadata.gz: 718978b7b52352cee16da1e555a0b0e71d0c68543bc627ef94869b45ff43dd259ce49a19b194105f96700848535a5397e039e86fd8733de899e5b61865eac2a8
7
+ data.tar.gz: b5998a5cfe29679198f4d57995e3f3e03f0694cc238e5fbc6f75a3a65b2ab80bfe3f86caac09616cb27f64832c0b83cddd87f3aaaa8e642e817429e3ecad0b7d
@@ -0,0 +1,6 @@
1
+ pkg
2
+ development
3
+ .bundle
4
+ .rvmrc
5
+ coverage
6
+ doc
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --require spec_helper
2
+ --color
3
+ --format documentation
@@ -0,0 +1,11 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.5
7
+ - 2.6
8
+ - 2.7
9
+ before_install: gem install bundler
10
+ script:
11
+ - bundle exec rake
data/Gemfile CHANGED
@@ -1,9 +1,3 @@
1
- source 'http://rubygems.org'
1
+ source 'https://rubygems.org'
2
2
 
3
- gem 'activemodel', ">= 3.0.6"
4
-
5
- group :development do
6
- gem 'rspec'
7
- gem "jeweler", ">= 1.5.2"
8
- #gem "rcov", ">= 0"
9
- end
3
+ gemspec
@@ -1,39 +1,79 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ certificate_authority (1.0.0)
5
+
1
6
  GEM
2
- remote: http://rubygems.org/
7
+ remote: https://rubygems.org/
3
8
  specs:
4
- activemodel (3.2.8)
5
- activesupport (= 3.2.8)
6
- builder (~> 3.0.0)
7
- activesupport (3.2.8)
8
- i18n (~> 0.6)
9
- multi_json (~> 1.0)
10
- builder (3.0.0)
11
- diff-lcs (1.1.3)
12
- git (1.2.5)
13
- i18n (0.6.0)
14
- jeweler (1.8.4)
15
- bundler (~> 1.0)
16
- git (>= 1.2.5)
17
- rake
18
- rdoc
19
- json (1.7.4)
20
- multi_json (1.3.6)
21
- rake (0.9.2.2)
22
- rdoc (3.12)
23
- json (~> 1.4)
24
- rspec (2.11.0)
25
- rspec-core (~> 2.11.0)
26
- rspec-expectations (~> 2.11.0)
27
- rspec-mocks (~> 2.11.0)
28
- rspec-core (2.11.1)
29
- rspec-expectations (2.11.2)
30
- diff-lcs (~> 1.1.3)
31
- rspec-mocks (2.11.2)
9
+ ast (2.4.0)
10
+ coderay (1.1.2)
11
+ coveralls (0.8.23)
12
+ json (>= 1.8, < 3)
13
+ simplecov (~> 0.16.1)
14
+ term-ansicolor (~> 1.3)
15
+ thor (>= 0.19.4, < 2.0)
16
+ tins (~> 1.6)
17
+ diff-lcs (1.3)
18
+ docile (1.3.2)
19
+ json (2.3.0)
20
+ method_source (1.0.0)
21
+ parallel (1.19.1)
22
+ parser (2.7.1.3)
23
+ ast (~> 2.4.0)
24
+ pry (0.13.1)
25
+ coderay (~> 1.1)
26
+ method_source (~> 1.0)
27
+ rainbow (3.0.0)
28
+ rake (13.0.1)
29
+ rexml (3.2.4)
30
+ rspec (3.9.0)
31
+ rspec-core (~> 3.9.0)
32
+ rspec-expectations (~> 3.9.0)
33
+ rspec-mocks (~> 3.9.0)
34
+ rspec-core (3.9.2)
35
+ rspec-support (~> 3.9.3)
36
+ rspec-expectations (3.9.2)
37
+ diff-lcs (>= 1.2.0, < 2.0)
38
+ rspec-support (~> 3.9.0)
39
+ rspec-mocks (3.9.1)
40
+ diff-lcs (>= 1.2.0, < 2.0)
41
+ rspec-support (~> 3.9.0)
42
+ rspec-support (3.9.3)
43
+ rubocop (0.84.0)
44
+ parallel (~> 1.10)
45
+ parser (>= 2.7.0.1)
46
+ rainbow (>= 2.2.2, < 4.0)
47
+ rexml
48
+ rubocop-ast (>= 0.0.3)
49
+ ruby-progressbar (~> 1.7)
50
+ unicode-display_width (>= 1.4.0, < 2.0)
51
+ rubocop-ast (0.0.3)
52
+ parser (>= 2.7.0.1)
53
+ ruby-progressbar (1.10.1)
54
+ simplecov (0.16.1)
55
+ docile (~> 1.1)
56
+ json (>= 1.8, < 3)
57
+ simplecov-html (~> 0.10.0)
58
+ simplecov-html (0.10.2)
59
+ sync (0.5.0)
60
+ term-ansicolor (1.7.1)
61
+ tins (~> 1.0)
62
+ thor (1.0.1)
63
+ tins (1.25.0)
64
+ sync
65
+ unicode-display_width (1.7.0)
32
66
 
33
67
  PLATFORMS
34
68
  ruby
35
69
 
36
70
  DEPENDENCIES
37
- activemodel (>= 3.0.6)
38
- jeweler (>= 1.5.2)
71
+ certificate_authority!
72
+ coveralls
73
+ pry
74
+ rake
39
75
  rspec
76
+ rubocop
77
+
78
+ BUNDLED WITH
79
+ 2.1.4
@@ -1,5 +1,9 @@
1
1
  = CertificateAuthority - Because it shouldn't be this damned complicated
2
2
 
3
+ {<img src="https://travis-ci.org/cchandler/certificate_authority.png?branch=master" alt="Build Status" />}[https://travis-ci.org/cchandler/certificate_authority]
4
+ {<img src="https://codeclimate.com/github/cchandler/certificate_authority.png" alt="Code Climate" />}[https://codeclimate.com/github/cchandler/certificate_authority]
5
+ {<img src="https://coveralls.io/repos/cchandler/certificate_authority/badge.png?branch=master" alt="Code Coverage" />}[https://coveralls.io/r/cchandler/certificate_authority]
6
+
3
7
  This is meant to provide a (more) programmer-friendly implementation of all the basic functionality contained in RFC-3280 to implement your own certificate authority.
4
8
 
5
9
  You can generate root certificates, intermediate certificates, and terminal certificates. You can also generate/manage Certificate Revocation Lists (CRLs) and Online Certificate Status Protocol (OCSP) messages.
@@ -60,7 +64,7 @@ Maybe you don't want to actually sign certificates with your super-secret root c
60
64
  signing_profile = {"extensions" => {"keyUsage" => {"usage" => ["critical", "keyCertSign"] }} }
61
65
  intermediate.sign!(signing_profile)
62
66
 
63
- All we have to do is create another certificate like we did with the root. In this example we gave it the next available serial number which for us, was 2. We then generate (and save!) key material for this new entity. Even the +signing_entity+ is set to true so this certificate can sign other certificates. The difference here is that the +parent+ field is set to the root. Going forward, whatever entity you want to sign a certificate, you set that entity to be the parent. In this case, our root will be responsible for signing this intermediate when we call +sign!+.
67
+ All we have to do is create another certificate like we did with the root. In this example we gave it the next available serial number, which for us, was 2. We then generate (and save!) key material for this new entity. Even the +signing_entity+ is set to true so this certificate can sign other certificates. The difference here is that the +parent+ field is set to the root. Going forward, whatever entity you want to sign a certificate, you set that entity to be the parent. In this case, our root will be responsible for signing this intermediate when we call +sign!+.
64
68
 
65
69
  = Creating new certificates (in general)
66
70
 
@@ -193,6 +197,78 @@ These CPSs define what vetting criteria and maintenance practices are required t
193
197
 
194
198
  [user_notice] This is a nested field containing explicit human readable text if you want to embed a notice in the certificate body related to certification practices. It contains nested attributes of +explicit_text+ for the notice, +organization+ and +notice_numbers+. Refer to the RFC for specific implications of how these are set, but whether or not browsers implement the correct specified behavior for their presence is another issue.
195
199
 
200
+ = Certificate Signing Requests (CSRs)
201
+
202
+ If you want certificate requestors to be able to request certificates without moving the private key you'll need to generate a CSR and submit it to the certificate authority.
203
+
204
+ Here's an example of using +certificate_authority+ to generate a CSR.
205
+
206
+ csr = CertificateAuthority::SigningRequest.new
207
+ dn = CertificateAuthority::DistinguishedName.new
208
+ dn.common_name = "localhost"
209
+ csr.distinguished_name = dn
210
+ k = CertificateAuthority::MemoryKeyMaterial.new
211
+ k.generate_key(2048)
212
+ csr.key_material = k
213
+ csr.digest = "SHA256"
214
+ csr.to_x509_csr.to_pem
215
+
216
+ Similarly, reading a CSR in is as simple as providing the PEM formatted version to +SigningRequest.from_x509_csr+.
217
+
218
+ csr = CertificateAuthority::SigningRequest.from_x509_csr(@pem_csr)
219
+
220
+ Once you have the CSR in the form of a +SigningRequest+ you can transform it to a +Certificate+ with +to_cert+. At this point it works just like any other certificate. You'll have to provide a serial number to actually sign it.
221
+
222
+ = Certificate Revocation Lists (CRLs)
223
+
224
+ Revocation lists let clients know when a certificate in the wild should no longer be trusted.
225
+
226
+ Like end-user certificates, CRLs have to be signed by a signing authority to be valid. Additionally, you will need to furnish a +nextUpdate+ value that indicates to the client when it should look for updates to the CRL and how long it should consider a cached value valid.
227
+
228
+ Ideally you would place the result CRL somewhere generally accessible on the Internet and reference the URI in the +crlDistributionPoints+ extension on issued certificates.
229
+
230
+ crl = CertificateAuthority::CertificateRevocationList.new
231
+ crl << certificate # Some CertificateAuthority::Certificate
232
+ crl << serial_number # Also works with plain CertificateAuthority::SerialNumber
233
+ crl.parent = root_certificate # A valid root
234
+ crl.next_update = (60 * 60 * 10) # 10 Hours
235
+ crl.sign!
236
+ crl.to_pem
237
+
238
+ = OCSP Support
239
+
240
+ OCSP is the Online Certificate Status Protocol. It provides a mechanism to query an authority to see if a certificate is still valid without downloading an entire CRL. To use this mechanism you provide a URI in the Authority Information Access extension.
241
+ If a client wishes to check the validity of a certificate they can query this endpoint.
242
+ This request will only contain serial numbers, so you'll need to uniquely identify your authority in the AIA path.
243
+
244
+ If a client sends you a DER encoded OCSP request you can read it out via +OCSPRequestReader+
245
+
246
+ ocsp_request_reader = CertificateAuthority::OCSPRequestReader.from_der(@ocsp_request.to_der)
247
+ ocsp_request_reader.serial_numbers
248
+
249
+ Then, you can construct a response like this
250
+
251
+ response_builder = CertificateAuthority::OCSPResponseBuilder.from_request_reader(ocsp_request_reader)
252
+ response_builder.parent = root
253
+ response = response_builder.build_response # Returns OpenSSL::OCSP::Response
254
+ response.to_der
255
+
256
+ The response builder will copy a (possible) nonce from the request. By default, the +OCSPResponseBuilder+ will say that every certificate is GOOD.
257
+ You should definitely override this if you plan on revoking certificates.
258
+ If you want to override this you'll need to supply a proc/lambda that takes a serial number and returns an array of status and reason.
259
+
260
+ response_builder = CertificateAuthority::OCSPResponseBuilder.from_request_reader(ocsp_request_reader)
261
+ response_builder.verification_mechanism = lambda {|certid|
262
+ [CertificateAuthority::OCSPResponseBuilder::REVOKED,CertificateAuthority::OCSPResponseBuilder::UNSPECIFIED]
263
+ }
264
+ response_builder.parent = root
265
+ response = response_builder.build_response # Response will say everything is revoked for unspecified reasons
266
+
267
+ Lastly, you can configure a nextUpdate time in the response. This is the length of time for which a client may consider this response valid.
268
+ The default is 15 minutes.
269
+
270
+ response_builder.next_update = 30 * 60 # 30 minutes
271
+
196
272
  = PKCS#11 Support
197
273
 
198
274
  If you happen to have a PKCS#11 compliant hardware token you can use +certificate_authority+ to maintain private key materials in hardware security modules. At this point the scope of operating that hardware is out of scope of this README but it's there and it is supported.
@@ -223,15 +299,28 @@ Your current version of OpenSSL _must_ include dynamic engine support and you wi
223
299
 
224
300
  Also of note, I have gotten these to work with 32-bit copies of Ubuntu 10.10 and pre-Snow Leopard versions of OS X. If you are running Snow Leopard you're out of luck since none of the companies I've contacted make a 64 bit driver.
225
301
 
226
- = Coming Soon
302
+ = Hopefully in the future
227
303
 
228
304
  * More PKCS#11 hardware (I need driver support from the manufacturers)
305
+
306
+ = Todone
307
+
229
308
  * Support for working with CSRs to request & issue certificates
309
+ * OCSP support
230
310
 
231
311
  = Misc notes
232
312
 
233
313
  * Firefox will complain about root/intermediate certificates unless both digitalSignature and keyEncipherment are specified as keyUsage attributes. Thanks diogomonica
234
314
 
315
+ = Special thanks and Contributions
316
+
317
+ * Diogo Monica @diogo
318
+ * Justin Cummins @sul3n3t
319
+ * @databus23
320
+ * Colin Jones @trptcolin
321
+ * Eric Monti @emonti
322
+ * TJ Vanderpoel @bougyman
323
+
235
324
  == Meta
236
325
 
237
326
  Written by Chris Chandler(http://chrischandler.name)
data/Rakefile CHANGED
@@ -1,35 +1,9 @@
1
- require 'rubygems'
2
- require 'bundler'
3
- require 'rspec'
4
- require 'rspec/core/rake_task'
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+ require "rubocop/rake_task"
5
4
 
6
- begin
7
- Bundler.setup(:default, :development)
8
- rescue Bundler::BundlerError => e
9
- $stderr.puts e.message
10
- $stderr.puts "Run `bundle install` to install missing gems"
11
- exit e.status_code
12
- end
13
-
14
- require 'rake'
15
-
16
- desc 'Default: run specs.'
17
- task :default => :spec
18
-
19
- require 'jeweler'
20
- Jeweler::Tasks.new do |gem|
21
- # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
22
- gem.name = "certificate_authority"
23
- gem.homepage = "http://github.com/cchandler/certificate_authority"
24
- gem.license = "MIT"
25
- gem.summary = 'Ruby gem for managing the core functions outlined in RFC-3280 for PKI'
26
- # gem.description = ''
27
- gem.email = "chris@flatterline.com"
28
- gem.authors = ["Chris Chandler"]
29
-
30
- # gem.add_dependency('activemodel', '3.0.6')
31
- end
32
- Jeweler::RubygemsDotOrgTasks.new
5
+ desc "Default: run specs."
6
+ task default: %i[spec]
33
7
 
34
8
  task :spec do
35
9
  Rake::Task["spec:units"].invoke
@@ -38,15 +12,6 @@ end
38
12
  namespace :spec do
39
13
  desc "Run unit specs."
40
14
  RSpec::Core::RakeTask.new(:units) do |t|
41
- t.rspec_opts = ['--colour --format progress --tag ~pkcs11']
15
+ t.rspec_opts = ["--colour --format progress --tag ~pkcs11"]
42
16
  end
43
-
44
- desc "Run integration specs."
45
- RSpec::Core::RakeTask.new(:integrations) do |t|
46
- t.rspec_opts = ['--colour --format progress']
47
- end
48
- end
49
-
50
- RSpec::Core::RakeTask.new(:doc) do |t|
51
- t.rspec_opts = ['--format specdoc ']
52
17
  end
@@ -1,72 +1,28 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
- # -*- encoding: utf-8 -*-
1
+ require File.expand_path("lib/certificate_authority/version", __dir__)
5
2
 
6
- Gem::Specification.new do |s|
7
- s.name = "certificate_authority"
8
- s.version = "0.1.6"
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "certificate_authority"
5
+ spec.version = CertificateAuthority::VERSION
6
+ spec.authors = ["Chris Chandler"]
7
+ spec.email = ["squanderingtime@gmail.com"]
9
8
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Chris Chandler"]
12
- s.date = "2012-08-12"
13
- s.email = "chris@flatterline.com"
14
- s.extra_rdoc_files = [
15
- "README.rdoc"
16
- ]
17
- s.files = [
18
- "Gemfile",
19
- "Gemfile.lock",
20
- "README.rdoc",
21
- "Rakefile",
22
- "VERSION.yml",
23
- "certificate_authority.gemspec",
24
- "lib/certificate_authority.rb",
25
- "lib/certificate_authority/certificate.rb",
26
- "lib/certificate_authority/certificate_revocation_list.rb",
27
- "lib/certificate_authority/distinguished_name.rb",
28
- "lib/certificate_authority/extensions.rb",
29
- "lib/certificate_authority/key_material.rb",
30
- "lib/certificate_authority/ocsp_handler.rb",
31
- "lib/certificate_authority/pkcs11_key_material.rb",
32
- "lib/certificate_authority/serial_number.rb",
33
- "lib/certificate_authority/signing_entity.rb",
34
- "lib/tasks/certificate_authority.rake",
35
- "spec/spec_helper.rb",
36
- "spec/units/certificate_authority_spec.rb",
37
- "spec/units/certificate_revocation_list_spec.rb",
38
- "spec/units/certificate_spec.rb",
39
- "spec/units/distinguished_name_spec.rb",
40
- "spec/units/extensions_spec.rb",
41
- "spec/units/key_material_spec.rb",
42
- "spec/units/ocsp_handler_spec.rb",
43
- "spec/units/pkcs11_key_material_spec.rb",
44
- "spec/units/serial_number_spec.rb",
45
- "spec/units/signing_entity_spec.rb",
46
- "spec/units/units_helper.rb"
47
- ]
48
- s.homepage = "http://github.com/cchandler/certificate_authority"
49
- s.licenses = ["MIT"]
50
- s.require_paths = ["lib"]
51
- s.rubygems_version = "1.8.15"
52
- s.summary = "Ruby gem for managing the core functions outlined in RFC-3280 for PKI"
9
+ spec.summary = "Ruby gem for managing the core functions outlined in RFC-3280 for PKI"
10
+ spec.homepage = "https://github.com/cchandler/certificate_authority"
11
+ spec.license = "MIT"
53
12
 
54
- if s.respond_to? :specification_version then
55
- s.specification_version = 3
13
+ spec.metadata["homepage_uri"] = "https://github.com/cchandler/certificate_authority"
14
+ spec.metadata["source_code_uri"] = "https://github.com/cchandler/certificate_authority"
56
15
 
57
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
58
- s.add_runtime_dependency(%q<activemodel>, [">= 3.0.6"])
59
- s.add_development_dependency(%q<rspec>, [">= 0"])
60
- s.add_development_dependency(%q<jeweler>, [">= 1.5.2"])
61
- else
62
- s.add_dependency(%q<activemodel>, [">= 3.0.6"])
63
- s.add_dependency(%q<rspec>, [">= 0"])
64
- s.add_dependency(%q<jeweler>, [">= 1.5.2"])
65
- end
66
- else
67
- s.add_dependency(%q<activemodel>, [">= 3.0.6"])
68
- s.add_dependency(%q<rspec>, [">= 0"])
69
- s.add_dependency(%q<jeweler>, [">= 1.5.2"])
16
+ spec.files = Dir.chdir(__dir__) do
17
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec/)}) }
70
18
  end
71
- end
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.required_ruby_version = ">= 2.4"
72
22
 
23
+ spec.add_development_dependency "coveralls"
24
+ spec.add_development_dependency "pry"
25
+ spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "rspec"
27
+ spec.add_development_dependency "rubocop"
28
+ end
@@ -1,11 +1,11 @@
1
- $:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
2
-
3
- #Exterior requirements
1
+ # Exterior requirements
4
2
  require 'openssl'
5
- require 'active_model'
6
3
 
7
- #Internal modules
4
+ # Internal modules
5
+ require 'certificate_authority/core_extensions'
8
6
  require 'certificate_authority/signing_entity'
7
+ require 'certificate_authority/revocable'
8
+ require 'certificate_authority/validations'
9
9
  require 'certificate_authority/distinguished_name'
10
10
  require 'certificate_authority/serial_number'
11
11
  require 'certificate_authority/key_material'
@@ -14,6 +14,7 @@ require 'certificate_authority/extensions'
14
14
  require 'certificate_authority/certificate'
15
15
  require 'certificate_authority/certificate_revocation_list'
16
16
  require 'certificate_authority/ocsp_handler'
17
+ require 'certificate_authority/signing_request'
17
18
 
18
19
  module CertificateAuthority
19
20
  end