certificate_authority_sonian 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'http://rubygems.org'
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
data/Gemfile.lock ADDED
@@ -0,0 +1,39 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ 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)
32
+
33
+ PLATFORMS
34
+ ruby
35
+
36
+ DEPENDENCIES
37
+ activemodel (>= 3.0.6)
38
+ jeweler (>= 1.5.2)
39
+ rspec
data/README.rdoc ADDED
@@ -0,0 +1,243 @@
1
+ = CertificateAuthority - Because it shouldn't be this damned complicated
2
+
3
+ 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
+
5
+ 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.
6
+
7
+ Because this library is built using the native Ruby bindings for OpenSSL it also supports PKCS#11 cryptographic hardware for secure maintenance of private key materials.
8
+
9
+ = So you want to maintain a certificate authority root
10
+
11
+ Let's suppose hypothetically you want to be able to issue and manage your own certificates. This section is meant to outline the basic functions you'll need(optionally want) to support. Not everyone is out to be in total compliance with WebTrust[link:http://www.webtrust.org/] or {Mozilla's rules for CA inclusion}[link:https://wiki.mozilla.org/CA:How_to_apply].
12
+
13
+ The three primary elements to be aware of are:
14
+
15
+ [Certificate Authority] These are the functions primarily related to the signing, issuance, and revocation of certificates.
16
+
17
+ [Registration Authority] These are the functions primarily related to registering and requesting certificates and vetting of the entities requesting certification.
18
+
19
+ [Validation Authority] These are the functions related to verifying the status of certificates out in the wild. Mostly CRLs and OCSP related functions.
20
+
21
+ = Establishing a new root in software
22
+
23
+ Let's look at a complete example for generating a new root certificate. Assuming that you don't have a PKCS#11 hardware token available (lists coming...) we'll have to store this safe.
24
+
25
+ Generating a self-signed root certificate is fairly easy:
26
+
27
+ require 'certificate_authority'
28
+ root = CertificateAuthority::Certificate.new
29
+ root.subject.common_name= "http://mydomain.com"
30
+ root.serial_number.number=1
31
+ root.key_material.generate_key
32
+ root.signing_entity = true
33
+ signing_profile = {"extensions" => {"keyUsage" => {"usage" => ["critical", "keyCertSign"] }} }
34
+ root.sign!(signing_profile)
35
+
36
+ The required elements for the gem at this time are a common name for the subject and a serial number for the certificate. Since this is our self-signed root we're going to give it the first serial available of 1. Because certificate_authority is not designed to manage the issuance lifecycle you'll be expected to store serial numbers yourself.
37
+
38
+ Next, after taking care of required fields, we will require key material for the new certificate. There's a convenience method made available on the key_material object for generating new keys. The private key will be available in:
39
+
40
+ root.key_material.private_key
41
+
42
+ and the public key:
43
+
44
+ root.key_material.public_key
45
+
46
+ Make sure to save the private key somewhere safe!
47
+
48
+ Lastly, we declare that the certificate we're about to sign is itself a signing entity so we can continue on and sign other certificates.
49
+
50
+ == Creating a new intermediate
51
+
52
+ Maybe you don't want to actually sign certificates with your super-secret root certificate. This is actually how a good number of most public certificate authorities do it. Rather than sign with the primary root, they generate an intermediate root that is then responsible for signing the final certificates. If you wanted to create an intermediate root certificate you would do something like the following:
53
+
54
+ intermediate = CertificateAuthority::Certificate.new
55
+ intermediate.subject.common_name= "My snazzy intermediate!"
56
+ intermediate.serial_number.number=2
57
+ intermediate.key_material.generate_key
58
+ intermediate.signing_entity = true
59
+ intermediate.parent = root
60
+ signing_profile = {"extensions" => {"keyUsage" => {"usage" => ["critical", "keyCertSign"] }} }
61
+ intermediate.sign!(signing_profile)
62
+
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!+.
64
+
65
+ = Creating new certificates (in general)
66
+
67
+ Now that we have a root certificate (and possibly an intermediate) we can sign end-user certificates. It is, perhaps unsurprisingly, similar to all the others:
68
+
69
+ plain_cert = CertificateAuthority::Certificate.new
70
+ plain_cert.subject.common_name= "http://mydomain.com"
71
+ plain_cert.serial_number.number=4
72
+ plain_cert.key_material.generate_key
73
+ plain_cert.parent = root # or intermediate
74
+ plain_cert.sign!
75
+
76
+ That's all there is to it! In this example we generate the key material ourselves, but it's possible for the end-user to generate certificate signing request (CSR) that we can then parse and consume automatically (coming soon). To get the PEM formatted certificate for the user you would need to call:
77
+
78
+ plain_cert.to_pem
79
+
80
+ to get the certificate body.
81
+
82
+ = Signing Profiles
83
+
84
+ Creating basic certificates is all well and good, but maybe you want _more_ signing control. +certificate_authority+ supports the idea of signing profiles. These are hashes containing values that +sign!+ will use to merge in additional control options for setting extensions on the certificate.
85
+
86
+ Here's an example of a full signing profile for most of the common V3 extensions:
87
+
88
+ signing_profile = {
89
+ "extensions" => {
90
+ "basicConstraints" => {"ca" => false},
91
+ "crlDistributionPoints" => {"uri" => "http://notme.com/other.crl" },
92
+ "subjectKeyIdentifier" => {},
93
+ "authorityKeyIdentifier" => {},
94
+ "authorityInfoAccess" => {"ocsp" => ["http://youFillThisOut/ocsp/"] },
95
+ "keyUsage" => {"usage" => ["digitalSignature","nonRepudiation"] },
96
+ "extendedKeyUsage" => {"usage" => [ "serverAuth","clientAuth"]},
97
+ "subjectAltName" => {"uris" => ["http://subdomains.youFillThisOut/"]},
98
+ "certificatePolicies" => {
99
+ "policy_identifier" => "1.3.5.8", "cps_uris" => ["http://my.host.name/", "http://my.your.name/"],
100
+ "user_notice" => {
101
+ "explicit_text" => "Explicit Text Here",
102
+ "organization" => "Organization name",
103
+ "notice_numbers" => "1,2,3,4"
104
+ }
105
+ }
106
+ }
107
+ }
108
+
109
+ Using a signing profile is done this way:
110
+
111
+ certificate.sign!(signing_profile)
112
+
113
+ At that point all the configuration options will be merged into the extensions.
114
+
115
+ == Basic Constraints
116
+
117
+ The basic constraints extension allows you to control whether or not a certificate can sign other certificates.
118
+
119
+ [CA] If this value is true then this certificate has the authority to sign additional certificates.
120
+
121
+ [pathlen] This is the maximum length of the chain-of-trust. For instance, if an intermediate certificate has a pathlen of 1 then it can sign additional certificates, but it cannot create another signing entity because the total chain-of-trust would have a length greater than 1.
122
+
123
+ == CRL Distribution Points
124
+
125
+ This extension controls where a conformant client can go to obtain a list of certificate revocation information. At this point +certificate_authority+ only supports a list of URIs. The formal RFC however provides for the ability to provide a URI and an issuer identifier that allows a different signing entity to generate/sign the CRL.
126
+
127
+ [uri] The URI in subject alternative name format of the URI endpoint. Example: "http://ca.chrischandler.name/some_identifier.crl"
128
+
129
+ == Subject Key Identifier
130
+
131
+ This extension is required to be present, but doesn't offer any configurable parameters. Directly from the RFC:
132
+
133
+ The subject key identifier extension provides a means of identifying
134
+ certificates that contain a particular public key.
135
+
136
+ To facilitate certification path construction, this extension MUST
137
+ appear in all conforming CA certificates, that is, all certificates
138
+ including the basic constraints extension (section 4.2.1.10) where
139
+ the value of cA is TRUE. The value of the subject key identifier
140
+ MUST be the value placed in the key identifier field of the Authority
141
+ Key Identifier extension (section 4.2.1.1) of certificates issued by
142
+ the subject of this certificate.
143
+
144
+ == Authority Key Identifier
145
+
146
+ Just like the subject key identifier, this is required under most circumstances and doesn't contain any meaningful configuration options. From the RFC:
147
+
148
+ The keyIdentifier field of the authorityKeyIdentifier extension MUST
149
+ be included in all certificates generated by conforming CAs to
150
+ facilitate certification path construction. There is one exception;
151
+ where a CA distributes its public key in the form of a "self-signed"
152
+ certificate, the authority key identifier MAY be omitted. The
153
+ signature on a self-signed certificate is generated with the private
154
+ key associated with the certificate's subject public key. (This
155
+ proves that the issuer possesses both the public and private keys.)
156
+ In this case, the subject and authority key identifiers would be
157
+ identical, but only the subject key identifier is needed for
158
+ certification path building.
159
+
160
+ == Authority Info Access
161
+
162
+ The authority info access extension allows a CA to sign a certificate with information a client can use to get up-to-the-minute status information on a signed certificate. This takes the form of an OCSP[link:http://en.wikipedia.org/wiki/Online_Certificate_Status_Protocol] (Online Certificate Status Protocol) endpoints.
163
+
164
+ [ocsp] This is an array of URIs specifying possible endpoints that will be able to provide a signed response. +certificate_authority+ has an OCSP message handler for parsing OCSP requests and generating OCSP signed responses.
165
+
166
+ == Key Usage
167
+
168
+ This extension contains a list of the functions this certificate is allowed to participate in.
169
+
170
+ [usage] An array of OIDs in string format. The acceptable values are specified by OpenSSL and are: +digitalSignature+, +nonRepudiation+, +keyEncipherment+, +dataEncipherment+, +keyAgreement+, +keyCertSign+, +cRLSign+, +encipherOnly+ and +decipherOnly+.
171
+
172
+ == Extended Key Usage
173
+
174
+ This one is like key usage, but allows for certain application specific purposes. It's generally only present in end-user certificates.
175
+
176
+ [usage] An array of OIDs in string format. The only ones with practical significance at this point are: +serverAuth+, +clientAuth+, and +codeSigning+.
177
+
178
+ == Subject Alternative Name
179
+
180
+ If the certificate needs to work for multiple domains then you can specify the others for which it is valid in the subject alternative name field.
181
+
182
+ [uris] An array of full URIs for other common names this certificate should be valid for. For instance, if you want http://ca.chrischandler.name and http://www.ca.chrischandler.name to share the same cert you would place both in the +uris+ attribute of the subject alternative name.
183
+
184
+ == Certificate Policies
185
+
186
+ This is one of the most esoteric of the extensions. This allows a conformant certificate authority to embed signing policy information into the certificate body. Public certificate authorities are required to maintain a Certificate Practice Statement in accordance with {RFC 2527}[link:http://www.ietf.org/rfc/rfc2527.txt].
187
+
188
+ These CPSs define what vetting criteria and maintenance practices are required to issue, maintain, and revoke a certificate. While it might be overkill for private certificates, if you wanted to make an actual public CA you would need to put together a practice statement and embed it in certificates you issue.
189
+
190
+ [policy_identifier] This is an arbitrary OID (that you make up!) that uniquely represents the policy you are enforcing for whatever kind of certificate this is meant to be.
191
+
192
+ [cps_uris] This is an array of URIs where a client or human can go to get information related to your certification practice.
193
+
194
+ [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
+
196
+ = PKCS#11 Support
197
+
198
+ 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.
199
+
200
+ To configure a certificate to utilize PKCS#11 instead of in memory keys all you need to do is:
201
+
202
+ root = CertificateAuthority::Certificate.new
203
+ root.subject.common_name= "http://mydomain.com"
204
+ root.serial_number.number=1
205
+ root.signing_entity = true
206
+
207
+ key_material_in_hardware = CertificateAuthority::Pkcs11KeyMaterial.new
208
+ key_material_in_hardware.token_id = "46"
209
+ key_material_in_hardware.pkcs11_lib = "/usr/lib/libeTPkcs11.so"
210
+ key_material_in_hardware.openssl_pkcs11_engine_lib = "/usr/lib/engines/engine_pkcs11.so"
211
+ key_material_in_hardware.pin = "11111111"
212
+
213
+ root.key_material = key_material_in_hardware
214
+ root.sign!
215
+
216
+ Your current version of OpenSSL _must_ include dynamic engine support and you will need to have OpenSSL PKCS#11 engine support. You will also require the actual PKCS#11 driver from the hardware manufacturer. As of today the only tokens I've gotten to work are:
217
+
218
+ [eTokenPro] Released by Aladdin (now SafeNet Inc.). I have only had success with the version 4 and 5 (32 bit only) copy of the driver. The newer authentication client released by SafeNet appears to be completely broken for interacting with the tokens outside of SafeNet's own tools. If anyone has a different experience I'd like to hear from you.
219
+
220
+ [ACS CryptoMate] Also a 32-bit only driver. You'll have to jump through some hoops to get the Linux PKCS#11 driver but it works surprisingly well. It also appears to support symmetric key operations in hardware.
221
+
222
+ [Your company] Do you make a PKCS#11 device? I'd love to get it working but I probably can't afford your device. Get in touch with me and if you're willing to loan me one for a week I can get it listed.
223
+
224
+ 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
+
226
+ = Coming Soon
227
+
228
+ * More PKCS#11 hardware (I need driver support from the manufacturers)
229
+ * Support for working with CSRs to request & issue certificates
230
+
231
+ = Misc notes
232
+
233
+ * Firefox will complain about root/intermediate certificates unless both digitalSignature and keyEncipherment are specified as keyUsage attributes. Thanks diogomonica
234
+
235
+ == Meta
236
+
237
+ Written by Chris Chandler(http://chrischandler.name)
238
+
239
+ Released under the MIT License: http://www.opensource.org/licenses/mit-license.php
240
+
241
+ Main page: http://github.com/cchandler/certificate_authority
242
+
243
+ Issue tracking: https://github.com/cchandler/certificate_authority/issues
data/Rakefile ADDED
@@ -0,0 +1,52 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ require 'rspec'
4
+ require 'rspec/core/rake_task'
5
+
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
33
+
34
+ task :spec do
35
+ Rake::Task["spec:units"].invoke
36
+ end
37
+
38
+ namespace :spec do
39
+ desc "Run unit specs."
40
+ RSpec::Core::RakeTask.new(:units) do |t|
41
+ t.rspec_opts = ['--colour --format progress --tag ~pkcs11']
42
+ 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
+ end
data/VERSION.yml ADDED
@@ -0,0 +1,5 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 1
4
+ :patch: 7
5
+ :build:
@@ -0,0 +1,71 @@
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 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "certificate_authority_sonian"
8
+ s.version = "0.1.7"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["TJ Vanderpoel"]
12
+ s.date = "2013-01-08"
13
+ s.email = "tj@rubyists.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/bougyman/certificate_authority"
49
+ s.licenses = ["MIT"]
50
+ s.require_paths = ["lib"]
51
+ s.rubygems_version = "1.8.24"
52
+ s.summary = "Ruby gem for managing the core functions outlined in RFC-3280 for PKI"
53
+
54
+ if s.respond_to? :specification_version then
55
+ s.specification_version = 3
56
+
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"])
70
+ end
71
+ end
@@ -0,0 +1,19 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
2
+
3
+ #Exterior requirements
4
+ require 'openssl'
5
+ require 'active_model'
6
+
7
+ #Internal modules
8
+ require 'certificate_authority/signing_entity'
9
+ require 'certificate_authority/distinguished_name'
10
+ require 'certificate_authority/serial_number'
11
+ require 'certificate_authority/key_material'
12
+ require 'certificate_authority/pkcs11_key_material'
13
+ require 'certificate_authority/extensions'
14
+ require 'certificate_authority/certificate'
15
+ require 'certificate_authority/certificate_revocation_list'
16
+ require 'certificate_authority/ocsp_handler'
17
+
18
+ module CertificateAuthority
19
+ end