pax_global_header 0000666 0000000 0000000 00000000064 14257354536 0014530 g ustar 00root root 0000000 0000000 52 comment=2e9e607397fe960dd8e17f7d7200281d3b0346b0
certificate_authority-1.1.0/ 0000775 0000000 0000000 00000000000 14257354536 0016121 5 ustar 00root root 0000000 0000000 certificate_authority-1.1.0/.github/ 0000775 0000000 0000000 00000000000 14257354536 0017461 5 ustar 00root root 0000000 0000000 certificate_authority-1.1.0/.github/workflows/ 0000775 0000000 0000000 00000000000 14257354536 0021516 5 ustar 00root root 0000000 0000000 certificate_authority-1.1.0/.github/workflows/ci.yml 0000664 0000000 0000000 00000001003 14257354536 0022626 0 ustar 00root root 0000000 0000000 name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
ruby-version:
- '3.1'
- '3.0'
- '2.7'
- '2.6'
- '2.5'
steps:
- uses: actions/checkout@v2
- name: Set up Ruby ${{ matrix.ruby-version }}
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby-version }}
bundler-cache: true # 'bundle install' and cache
- name: Run tests
run: bundle exec rake
certificate_authority-1.1.0/.gitignore 0000664 0000000 0000000 00000000054 14257354536 0020110 0 ustar 00root root 0000000 0000000 pkg
development
.bundle
.rvmrc
coverage
doc
certificate_authority-1.1.0/.rspec 0000664 0000000 0000000 00000000065 14257354536 0017237 0 ustar 00root root 0000000 0000000 --require spec_helper
--color
--format documentation
certificate_authority-1.1.0/Gemfile 0000664 0000000 0000000 00000000047 14257354536 0017415 0 ustar 00root root 0000000 0000000 source 'https://rubygems.org'
gemspec
certificate_authority-1.1.0/Gemfile.lock 0000664 0000000 0000000 00000003153 14257354536 0020345 0 ustar 00root root 0000000 0000000 PATH
remote: .
specs:
certificate_authority (1.1.0)
GEM
remote: https://rubygems.org/
specs:
ast (2.4.0)
coderay (1.1.2)
coveralls (0.8.23)
json (>= 1.8, < 3)
simplecov (~> 0.16.1)
term-ansicolor (~> 1.3)
thor (>= 0.19.4, < 2.0)
tins (~> 1.6)
diff-lcs (1.3)
docile (1.3.2)
json (2.3.0)
method_source (1.0.0)
parallel (1.19.1)
parser (2.7.1.3)
ast (~> 2.4.0)
pry (0.13.1)
coderay (~> 1.1)
method_source (~> 1.0)
rainbow (3.0.0)
rake (13.0.1)
rexml (3.2.5)
rspec (3.9.0)
rspec-core (~> 3.9.0)
rspec-expectations (~> 3.9.0)
rspec-mocks (~> 3.9.0)
rspec-core (3.9.2)
rspec-support (~> 3.9.3)
rspec-expectations (3.9.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.9.0)
rspec-mocks (3.9.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.9.0)
rspec-support (3.9.3)
rubocop (0.84.0)
parallel (~> 1.10)
parser (>= 2.7.0.1)
rainbow (>= 2.2.2, < 4.0)
rexml
rubocop-ast (>= 0.0.3)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 2.0)
rubocop-ast (0.0.3)
parser (>= 2.7.0.1)
ruby-progressbar (1.10.1)
simplecov (0.16.1)
docile (~> 1.1)
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.2)
sync (0.5.0)
term-ansicolor (1.7.1)
tins (~> 1.0)
thor (1.0.1)
tins (1.25.0)
sync
unicode-display_width (1.7.0)
PLATFORMS
ruby
DEPENDENCIES
certificate_authority!
coveralls
pry
rake
rspec
rubocop
BUNDLED WITH
2.1.4
certificate_authority-1.1.0/README.rdoc 0000664 0000000 0000000 00000046645 14257354536 0017746 0 ustar 00root root 0000000 0000000 = CertificateAuthority - Because it shouldn't be this damned complicated
{
}[https://travis-ci.org/cchandler/certificate_authority]
{
}[https://codeclimate.com/github/cchandler/certificate_authority]
{
}[https://coveralls.io/r/cchandler/certificate_authority]
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.
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.
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.
= So you want to maintain a certificate authority root
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].
The three primary elements to be aware of are:
[Certificate Authority] These are the functions primarily related to the signing, issuance, and revocation of certificates.
[Registration Authority] These are the functions primarily related to registering and requesting certificates and vetting of the entities requesting certification.
[Validation Authority] These are the functions related to verifying the status of certificates out in the wild. Mostly CRLs and OCSP related functions.
= Establishing a new root in software
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.
Generating a self-signed root certificate is fairly easy:
require 'certificate_authority'
root = CertificateAuthority::Certificate.new
root.subject.common_name= "http://mydomain.com"
root.serial_number.number=1
root.key_material.generate_key
root.signing_entity = true
signing_profile = {"extensions" => {"keyUsage" => {"usage" => ["critical", "keyCertSign"] }} }
root.sign!(signing_profile)
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.
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:
root.key_material.private_key
and the public key:
root.key_material.public_key
Make sure to save the private key somewhere safe!
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.
== Creating a new intermediate
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:
intermediate = CertificateAuthority::Certificate.new
intermediate.subject.common_name= "My snazzy intermediate!"
intermediate.serial_number.number=2
intermediate.key_material.generate_key
intermediate.signing_entity = true
intermediate.parent = root
signing_profile = {"extensions" => {"keyUsage" => {"usage" => ["critical", "keyCertSign"] }} }
intermediate.sign!(signing_profile)
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!+.
= Creating new certificates (in general)
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:
plain_cert = CertificateAuthority::Certificate.new
plain_cert.subject.common_name= "http://mydomain.com"
plain_cert.serial_number.number=4
plain_cert.key_material.generate_key
plain_cert.parent = root # or intermediate
plain_cert.sign!
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:
plain_cert.to_pem
to get the certificate body.
= Signing Profiles
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.
Here's an example of a full signing profile for most of the common V3 extensions:
signing_profile = {
"extensions" => {
"basicConstraints" => {"ca" => false},
"crlDistributionPoints" => {"uri" => "http://notme.com/other.crl" },
"subjectKeyIdentifier" => {},
"authorityKeyIdentifier" => {},
"authorityInfoAccess" => {"ocsp" => ["http://youFillThisOut/ocsp/"] },
"keyUsage" => {"usage" => ["digitalSignature","nonRepudiation"] },
"extendedKeyUsage" => {"usage" => [ "serverAuth","clientAuth"]},
"subjectAltName" => {"uris" => ["http://subdomains.youFillThisOut/"]},
"certificatePolicies" => {
"policy_identifier" => "1.3.5.8", "cps_uris" => ["http://my.host.name/", "http://my.your.name/"],
"user_notice" => {
"explicit_text" => "Explicit Text Here",
"organization" => "Organization name",
"notice_numbers" => "1,2,3,4"
}
}
}
}
Using a signing profile is done this way:
certificate.sign!(signing_profile)
At that point all the configuration options will be merged into the extensions.
== Basic Constraints
The basic constraints extension allows you to control whether or not a certificate can sign other certificates.
[CA] If this value is true then this certificate has the authority to sign additional certificates.
[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.
== CRL Distribution Points
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.
[uri] The URI in subject alternative name format of the URI endpoint. Example: "http://ca.chrischandler.name/some_identifier.crl"
== Subject Key Identifier
This extension is required to be present, but doesn't offer any configurable parameters. Directly from the RFC:
The subject key identifier extension provides a means of identifying
certificates that contain a particular public key.
To facilitate certification path construction, this extension MUST
appear in all conforming CA certificates, that is, all certificates
including the basic constraints extension (section 4.2.1.10) where
the value of cA is TRUE. The value of the subject key identifier
MUST be the value placed in the key identifier field of the Authority
Key Identifier extension (section 4.2.1.1) of certificates issued by
the subject of this certificate.
== Authority Key Identifier
Just like the subject key identifier, this is required under most circumstances and doesn't contain any meaningful configuration options. From the RFC:
The keyIdentifier field of the authorityKeyIdentifier extension MUST
be included in all certificates generated by conforming CAs to
facilitate certification path construction. There is one exception;
where a CA distributes its public key in the form of a "self-signed"
certificate, the authority key identifier MAY be omitted. The
signature on a self-signed certificate is generated with the private
key associated with the certificate's subject public key. (This
proves that the issuer possesses both the public and private keys.)
In this case, the subject and authority key identifiers would be
identical, but only the subject key identifier is needed for
certification path building.
== Authority Info Access
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.
[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.
== Key Usage
This extension contains a list of the functions this certificate is allowed to participate in.
[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+.
== Extended Key Usage
This one is like key usage, but allows for certain application specific purposes. It's generally only present in end-user certificates.
[usage] An array of OIDs in string format. The only ones with practical significance at this point are: +serverAuth+, +clientAuth+, and +codeSigning+.
== Subject Alternative Name
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.
[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.
== Certificate Policies
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].
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.
[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.
[cps_uris] This is an array of URIs where a client or human can go to get information related to your certification practice.
[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.
= Certificate Signing Requests (CSRs)
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.
Here's an example of using +certificate_authority+ to generate a CSR.
csr = CertificateAuthority::SigningRequest.new
dn = CertificateAuthority::DistinguishedName.new
dn.common_name = "localhost"
csr.distinguished_name = dn
k = CertificateAuthority::MemoryKeyMaterial.new
k.generate_key(2048)
csr.key_material = k
csr.digest = "SHA256"
csr.to_x509_csr.to_pem
Similarly, reading a CSR in is as simple as providing the PEM formatted version to +SigningRequest.from_x509_csr+.
csr = CertificateAuthority::SigningRequest.from_x509_csr(@pem_csr)
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.
= Certificate Revocation Lists (CRLs)
Revocation lists let clients know when a certificate in the wild should no longer be trusted.
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.
Ideally you would place the result CRL somewhere generally accessible on the Internet and reference the URI in the +crlDistributionPoints+ extension on issued certificates.
crl = CertificateAuthority::CertificateRevocationList.new
crl << certificate # Some CertificateAuthority::Certificate
crl << serial_number # Also works with plain CertificateAuthority::SerialNumber
crl.parent = root_certificate # A valid root
crl.next_update = (60 * 60 * 10) # 10 Hours
crl.sign!
crl.to_pem
= OCSP Support
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.
If a client wishes to check the validity of a certificate they can query this endpoint.
This request will only contain serial numbers, so you'll need to uniquely identify your authority in the AIA path.
If a client sends you a DER encoded OCSP request you can read it out via +OCSPRequestReader+
ocsp_request_reader = CertificateAuthority::OCSPRequestReader.from_der(@ocsp_request.to_der)
ocsp_request_reader.serial_numbers
Then, you can construct a response like this
response_builder = CertificateAuthority::OCSPResponseBuilder.from_request_reader(ocsp_request_reader)
response_builder.parent = root
response = response_builder.build_response # Returns OpenSSL::OCSP::Response
response.to_der
The response builder will copy a (possible) nonce from the request. By default, the +OCSPResponseBuilder+ will say that every certificate is GOOD.
You should definitely override this if you plan on revoking certificates.
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.
response_builder = CertificateAuthority::OCSPResponseBuilder.from_request_reader(ocsp_request_reader)
response_builder.verification_mechanism = lambda {|certid|
[CertificateAuthority::OCSPResponseBuilder::REVOKED,CertificateAuthority::OCSPResponseBuilder::UNSPECIFIED]
}
response_builder.parent = root
response = response_builder.build_response # Response will say everything is revoked for unspecified reasons
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.
The default is 15 minutes.
response_builder.next_update = 30 * 60 # 30 minutes
= PKCS#11 Support
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.
To configure a certificate to utilize PKCS#11 instead of in memory keys all you need to do is:
root = CertificateAuthority::Certificate.new
root.subject.common_name= "http://mydomain.com"
root.serial_number.number=1
root.signing_entity = true
key_material_in_hardware = CertificateAuthority::Pkcs11KeyMaterial.new
key_material_in_hardware.token_id = "46"
key_material_in_hardware.pkcs11_lib = "/usr/lib/libeTPkcs11.so"
key_material_in_hardware.openssl_pkcs11_engine_lib = "/usr/lib/engines/engine_pkcs11.so"
key_material_in_hardware.pin = "11111111"
root.key_material = key_material_in_hardware
root.sign!
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:
[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.
[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.
[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.
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.
= Hopefully in the future
* More PKCS#11 hardware (I need driver support from the manufacturers)
= Todone
* Support for working with CSRs to request & issue certificates
* OCSP support
= Misc notes
* Firefox will complain about root/intermediate certificates unless both digitalSignature and keyEncipherment are specified as keyUsage attributes. Thanks diogomonica
= Special thanks and Contributions
* Diogo Monica @diogo
* Justin Cummins @sul3n3t
* @databus23
* Colin Jones @trptcolin
* Eric Monti @emonti
* TJ Vanderpoel @bougyman
== Meta
Written by Chris Chandler(http://chrischandler.name)
Released under the MIT License: http://www.opensource.org/licenses/mit-license.php
Main page: http://github.com/cchandler/certificate_authority
Issue tracking: https://github.com/cchandler/certificate_authority/issues
certificate_authority-1.1.0/Rakefile 0000664 0000000 0000000 00000000541 14257354536 0017566 0 ustar 00root root 0000000 0000000 require "bundler/gem_tasks"
require "rspec/core/rake_task"
require "rubocop/rake_task"
desc "Default: run specs."
task default: %i[spec]
task :spec do
Rake::Task["spec:units"].invoke
end
namespace :spec do
desc "Run unit specs."
RSpec::Core::RakeTask.new(:units) do |t|
t.rspec_opts = ["--colour --format progress --tag ~pkcs11"]
end
end
certificate_authority-1.1.0/certificate_authority.gemspec 0000664 0000000 0000000 00000002021 14257354536 0024053 0 ustar 00root root 0000000 0000000 require File.expand_path("lib/certificate_authority/version", __dir__)
Gem::Specification.new do |spec|
spec.name = "certificate_authority"
spec.version = CertificateAuthority::VERSION
spec.authors = ["Chris Chandler"]
spec.email = ["squanderingtime@gmail.com"]
spec.summary = "Ruby gem for managing the core functions outlined in RFC-3280 for PKI"
spec.homepage = "https://github.com/cchandler/certificate_authority"
spec.license = "MIT"
spec.metadata["homepage_uri"] = "https://github.com/cchandler/certificate_authority"
spec.metadata["source_code_uri"] = "https://github.com/cchandler/certificate_authority"
spec.files = Dir.chdir(__dir__) do
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec/)}) }
end
spec.require_paths = ["lib"]
spec.required_ruby_version = ">= 2.4"
spec.add_development_dependency "coveralls"
spec.add_development_dependency "pry"
spec.add_development_dependency "rake"
spec.add_development_dependency "rspec"
spec.add_development_dependency "rubocop"
end
certificate_authority-1.1.0/lib/ 0000775 0000000 0000000 00000000000 14257354536 0016667 5 ustar 00root root 0000000 0000000 certificate_authority-1.1.0/lib/certificate_authority.rb 0000664 0000000 0000000 00000001306 14257354536 0023606 0 ustar 00root root 0000000 0000000 # Exterior requirements
require 'openssl'
# Internal modules
require 'certificate_authority/core_extensions'
require 'certificate_authority/signing_entity'
require 'certificate_authority/revocable'
require 'certificate_authority/validations'
require 'certificate_authority/distinguished_name'
require 'certificate_authority/serial_number'
require 'certificate_authority/key_material'
require 'certificate_authority/pkcs11_key_material'
require 'certificate_authority/extensions'
require 'certificate_authority/certificate'
require 'certificate_authority/certificate_revocation_list'
require 'certificate_authority/ocsp_handler'
require 'certificate_authority/signing_request'
module CertificateAuthority
end
certificate_authority-1.1.0/lib/certificate_authority/ 0000775 0000000 0000000 00000000000 14257354536 0023261 5 ustar 00root root 0000000 0000000 certificate_authority-1.1.0/lib/certificate_authority/certificate.rb 0000664 0000000 0000000 00000023104 14257354536 0026070 0 ustar 00root root 0000000 0000000 module CertificateAuthority
class Certificate
include Validations
include Revocable
attr_accessor :distinguished_name
attr_accessor :serial_number
attr_accessor :key_material
attr_accessor :not_before
attr_accessor :not_after
attr_accessor :extensions
attr_accessor :openssl_body
alias :subject :distinguished_name #Same thing as the DN
attr_accessor :parent
def validate
errors.add :base, "Distinguished name must be valid" unless distinguished_name.valid?
errors.add :base, "Key material must be valid" unless key_material.valid?
errors.add :base, "Serial number must be valid" unless serial_number.valid?
errors.add :base, "Extensions must be valid" unless extensions.each do |item|
unless item.respond_to?(:valid?)
true
else
item.valid?
end
end
end
def initialize
self.distinguished_name = DistinguishedName.new
self.serial_number = SerialNumber.new
self.key_material = MemoryKeyMaterial.new
self.not_before = Date.today.utc
self.not_after = Date.today.advance(:years => 1).utc
self.parent = self
self.extensions = load_extensions()
self.signing_entity = false
end
=begin
def self.from_openssl openssl_cert
unless openssl_cert.is_a? OpenSSL::X509::Certificate
raise "Can only construct from an OpenSSL::X509::Certificate"
end
certificate = Certificate.new
# Only subject, key_material, and body are used for signing
certificate.distinguished_name = DistinguishedName.from_openssl openssl_cert.subject
certificate.key_material.public_key = openssl_cert.public_key
certificate.openssl_body = openssl_cert
certificate.serial_number.number = openssl_cert.serial.to_i
certificate.not_before = openssl_cert.not_before
certificate.not_after = openssl_cert.not_after
# TODO extensions
certificate
end
=end
def sign!(signing_profile={})
raise "Invalid certificate #{self.errors.full_messages}" unless valid?
merge_profile_with_extensions(signing_profile)
openssl_cert = OpenSSL::X509::Certificate.new
openssl_cert.version = 2
openssl_cert.not_before = self.not_before
openssl_cert.not_after = self.not_after
openssl_cert.public_key = self.key_material.public_key
openssl_cert.serial = self.serial_number.number
openssl_cert.subject = self.distinguished_name.to_x509_name
openssl_cert.issuer = parent.distinguished_name.to_x509_name
factory = OpenSSL::X509::ExtensionFactory.new
factory.subject_certificate = openssl_cert
#NB: If the parent doesn't have an SSL body we're making this a self-signed cert
if parent.openssl_body.nil?
factory.issuer_certificate = openssl_cert
else
factory.issuer_certificate = parent.openssl_body
end
factory.config = build_openssl_config
# Order matters: e.g. for self-signed, subjectKeyIdentifier must come before authorityKeyIdentifier
self.extensions.keys.sort{|a,b| b<=>a}.each do |k|
e = extensions[k]
next if e.to_s.nil? or e.to_s == "" ## If the extension returns an empty string we won't include it
ext = factory.create_ext(e.openssl_identifier, e.to_s, e.critical)
openssl_cert.add_extension(ext)
end
if signing_profile["digest"].nil?
digest = OpenSSL::Digest.new("SHA512")
else
digest = OpenSSL::Digest.new(signing_profile["digest"])
end
self.openssl_body = openssl_cert.sign(parent.key_material.private_key, digest)
end
def is_signing_entity?
self.extensions["basicConstraints"].ca
end
def signing_entity=(signing)
self.extensions["basicConstraints"].ca = signing
end
def revoked?
!self.revoked_at.nil?
end
def to_pem
raise "Certificate has no signed body" if self.openssl_body.nil?
self.openssl_body.to_pem
end
def to_csr
csr = SigningRequest.new
csr.distinguished_name = self.distinguished_name
csr.key_material = self.key_material
factory = OpenSSL::X509::ExtensionFactory.new
exts = []
self.extensions.keys.each do |k|
## Don't copy over key identifiers for CSRs
next if k == "subjectKeyIdentifier" || k == "authorityKeyIdentifier"
e = extensions[k]
## If the extension returns an empty string we won't include it
next if e.to_s.nil? or e.to_s == ""
exts << factory.create_ext(e.openssl_identifier, e.to_s, e.critical)
end
attrval = OpenSSL::ASN1::Set([OpenSSL::ASN1::Sequence(exts)])
attrs = [
OpenSSL::X509::Attribute.new("extReq", attrval),
OpenSSL::X509::Attribute.new("msExtReq", attrval)
]
csr.attributes = attrs
csr
end
def self.from_x509_cert(raw_cert)
openssl_cert = OpenSSL::X509::Certificate.new(raw_cert)
Certificate.from_openssl(openssl_cert)
end
def is_root_entity?
self.parent == self && is_signing_entity?
end
def is_intermediate_entity?
(self.parent != self) && is_signing_entity?
end
private
def merge_profile_with_extensions(signing_profile={})
return self.extensions if signing_profile["extensions"].nil?
signing_config = signing_profile["extensions"]
signing_config.keys.each do |k|
extension = self.extensions[k]
items = signing_config[k]
items.keys.each do |profile_item_key|
if extension.respond_to?("#{profile_item_key}=".to_sym)
if k == 'subjectAltName' && profile_item_key == 'emails'
items[profile_item_key].map do |email|
if email == 'email:copy'
fail "no email address provided for subject: #{subject.to_x509_name}" unless subject.email_address
"email:#{subject.email_address}"
else
email
end
end
end
extension.send("#{profile_item_key}=".to_sym, items[profile_item_key] )
else
p "Tried applying '#{profile_item_key}' to #{extension.class} but it doesn't respond!"
end
end
end
end
# Enumeration of the extensions. Not the worst option since
# the likelihood of these needing to be updated is low at best.
EXTENSIONS = [
CertificateAuthority::Extensions::BasicConstraints,
CertificateAuthority::Extensions::CrlDistributionPoints,
CertificateAuthority::Extensions::SubjectKeyIdentifier,
CertificateAuthority::Extensions::AuthorityKeyIdentifier,
CertificateAuthority::Extensions::AuthorityInfoAccess,
CertificateAuthority::Extensions::KeyUsage,
CertificateAuthority::Extensions::ExtendedKeyUsage,
CertificateAuthority::Extensions::SubjectAlternativeName,
CertificateAuthority::Extensions::CertificatePolicies
]
def load_extensions
extension_hash = {}
EXTENSIONS.each do |klass|
extension = klass.new
extension_hash[extension.openssl_identifier] = extension
end
extension_hash
end
def build_openssl_config
OpenSSL::Config.parse(openssl_config_string)
end
def openssl_config_string
lines = openssl_config_without_multi_value + openssl_config_with_multi_value
return '' if lines.empty?
(["[extensions]" ]+ lines).join("\n")
end
def openssl_config_without_multi_value
no_multi_value_keys = self.extensions.keys.select { |k| extensions[k].config_extensions.empty? }
lines = no_multi_value_keys.map do |k|
value = extensions[k].to_s
value.empty? ? '' : "#{k} = #{value}"
end.reject(&:empty?)
lines
end
def openssl_config_with_multi_value
multi_value_keys = self.extensions.keys.reject { |k| extensions[k].config_extensions.empty? }
sections = {}
entries = multi_value_keys.map do |k|
sections.merge!(extensions[k].config_extensions)
value = comma_terminate(extensions[k]) + section_ref_str(extensions[k].config_extensions.keys)
"#{k} = #{value}"
end.reject(&:empty?)
section_lines = sections.keys.flat_map do |k|
section_lines(k, sections[k])
end
entries + [''] + section_lines
end
def comma_terminate(val)
s = val.to_s
s.empty? ? s : "#{s},"
end
def section_ref_str(section_names)
section_names.map { |n| "@#{n}"}.join(',')
end
def section_lines(section_name, value_hash)
["[#{section_name}]"] + value_hash.keys.map { |k| "#{k} = #{value_hash[k]}"} + ['']
end
def merge_options(config,hash)
hash.keys.each do |k|
config[k] = hash[k]
end
config
end
def self.from_openssl openssl_cert
unless openssl_cert.is_a? OpenSSL::X509::Certificate
raise "Can only construct from an OpenSSL::X509::Certificate"
end
certificate = Certificate.new
# Only subject, key_material, and body are used for signing
certificate.distinguished_name = DistinguishedName.from_openssl openssl_cert.subject
certificate.key_material.public_key = openssl_cert.public_key
certificate.openssl_body = openssl_cert
certificate.serial_number.number = openssl_cert.serial.to_i
certificate.not_before = openssl_cert.not_before
certificate.not_after = openssl_cert.not_after
EXTENSIONS.each do |klass|
_,v,c = (openssl_cert.extensions.detect { |e| e.to_a.first == klass::OPENSSL_IDENTIFIER } || []).to_a
certificate.extensions[klass::OPENSSL_IDENTIFIER] = klass.parse(v, c) if v
end
certificate
end
end
end
certificate_authority-1.1.0/lib/certificate_authority/certificate_revocation_list.rb 0000664 0000000 0000000 00000004542 14257354536 0031361 0 ustar 00root root 0000000 0000000 module CertificateAuthority
class CertificateRevocationList
include Validations
attr_accessor :certificates
attr_accessor :parent
attr_accessor :crl_body
attr_accessor :next_update
attr_accessor :last_update_skew_seconds
def validate
errors.add :next_update, "Next update must be a positive value" if self.next_update < 0
errors.add :parent, "A parent entity must be set" if self.parent.nil?
end
def initialize
self.certificates = []
self.next_update = 60 * 60 * 4 # 4 hour default
self.last_update_skew_seconds = 0
end
def <<(revocable)
case revocable
when Revocable
raise "Only revoked entities can be added to a CRL" unless revocable.revoked?
self.certificates << revocable
when OpenSSL::X509::Certificate
raise "Not implemented yet"
else
raise "#{revocable.class} cannot be included in a CRL"
end
end
def sign!(signing_profile={})
raise "No parent entity has been set!" if self.parent.nil?
raise "Invalid CRL" unless self.valid?
revocations = self.certificates.collect do |revocable|
revocation = OpenSSL::X509::Revoked.new
## We really just need a serial number, now we have to dig it out
case revocable
when Certificate
x509_cert = OpenSSL::X509::Certificate.new(revocable.to_pem)
revocation.serial = x509_cert.serial
when SerialNumber
revocation.serial = revocable.number
end
revocation.time = revocable.revoked_at
revocation
end
crl = OpenSSL::X509::CRL.new
revocations.each do |revocation|
crl.add_revoked(revocation)
end
crl.version = 1
crl.last_update = Time.now - self.last_update_skew_seconds
crl.next_update = Time.now + self.next_update
signing_cert = OpenSSL::X509::Certificate.new(self.parent.to_pem)
if signing_profile["digest"].nil?
digest = OpenSSL::Digest.new("SHA512")
else
digest = OpenSSL::Digest.new(signing_profile["digest"])
end
crl.issuer = signing_cert.subject
self.crl_body = crl.sign(self.parent.key_material.private_key, digest)
self.crl_body
end
def to_pem
raise "No signed CRL body" if self.crl_body.nil?
self.crl_body.to_pem
end
end#CertificateRevocationList
end
certificate_authority-1.1.0/lib/certificate_authority/core_extensions.rb 0000664 0000000 0000000 00000001522 14257354536 0027015 0 ustar 00root root 0000000 0000000 #
# ActiveSupport has these modifications. Now that we don't use ActiveSupport,
# these are added here as a kindness.
#
require 'date'
unless nil.respond_to?(:blank?)
class NilClass
def blank?
true
end
end
end
unless String.respond_to?(:blank?)
class String
def blank?
self.empty?
end
end
end
class Date
def today
t = Time.now.utc
Date.new(t.year, t.month, t.day)
end
def utc
self.to_datetime.to_time.utc
end
unless Date.respond_to?(:advance)
def advance(options)
options = options.dup
d = self
d = d >> options.delete(:years) * 12 if options[:years]
d = d >> options.delete(:months) if options[:months]
d = d + options.delete(:weeks) * 7 if options[:weeks]
d = d + options.delete(:days) if options[:days]
d
end
end
end
certificate_authority-1.1.0/lib/certificate_authority/distinguished_name.rb 0000664 0000000 0000000 00000005360 14257354536 0027455 0 ustar 00root root 0000000 0000000 module CertificateAuthority
class DistinguishedName
include Validations
def validate
if self.common_name.nil? || self.common_name.empty?
errors.add :common_name, 'cannot be blank'
end
end
attr_accessor :common_name
alias :cn :common_name
alias :cn= :common_name=
attr_accessor :locality
alias :l :locality
alias :l= :locality=
attr_accessor :state
alias :s :state
alias :st= :state=
attr_accessor :country
alias :c :country
alias :c= :country=
attr_accessor :organization
alias :o :organization
alias :o= :organization=
attr_accessor :organizational_unit
alias :ou :organizational_unit
alias :ou= :organizational_unit=
attr_accessor :email_address
alias :emailAddress :email_address
alias :emailAddress= :email_address=
attr_accessor :serial_number
alias :serialNumber :serial_number
alias :serialNumber= :serial_number=
def to_x509_name
raise "Invalid Distinguished Name" unless valid?
# NB: the capitalization in the strings counts
name = OpenSSL::X509::Name.new
name.add_entry("serialNumber", serial_number) unless serial_number.blank?
name.add_entry("C", country) unless country.blank?
name.add_entry("ST", state) unless state.blank?
name.add_entry("L", locality) unless locality.blank?
name.add_entry("O", organization) unless organization.blank?
name.add_entry("OU", organizational_unit) unless organizational_unit.blank?
name.add_entry("CN", common_name)
name.add_entry("emailAddress", email_address) unless email_address.blank?
name
end
def ==(other)
# Use the established OpenSSL comparison
self.to_x509_name() == other.to_x509_name()
end
def self.from_openssl openssl_name
unless openssl_name.is_a? OpenSSL::X509::Name
raise "Argument must be a OpenSSL::X509::Name"
end
WrappedDistinguishedName.new(openssl_name)
end
end
## This is a significantly more complicated case. It's possible that
## generically handled certificates will include custom OIDs in the
## subject.
class WrappedDistinguishedName < DistinguishedName
attr_accessor :x509_name
def initialize(x509_name)
@x509_name = x509_name
subject = @x509_name.to_a
subject.each do |element|
field = element[0].downcase
value = element[1]
#type = element[2] ## -not used
method_sym = "#{field}=".to_sym
if self.respond_to?(method_sym)
self.send("#{field}=",value)
else
## Custom OID
@custom_oids = true
end
end
end
def to_x509_name
@x509_name
end
def custom_oids?
@custom_oids
end
end
end
certificate_authority-1.1.0/lib/certificate_authority/extensions.rb 0000664 0000000 0000000 00000036001 14257354536 0026005 0 ustar 00root root 0000000 0000000 module CertificateAuthority
module Extensions
module ExtensionAPI
def to_s
raise "Implementation required"
end
def self.parse(value, critical)
raise "Implementation required"
end
def config_extensions
{}
end
def openssl_identifier
raise "Implementation required"
end
def ==(value)
raise "Implementation required"
end
end
# Specifies whether an X.509v3 certificate can act as a CA, signing other
# certificates to be verified. If set, a path length constraint can also be
# specified.
# Reference: Section 4.2.1.10 of RFC3280
# http://tools.ietf.org/html/rfc3280#section-4.2.1.10
class BasicConstraints
OPENSSL_IDENTIFIER = "basicConstraints"
include ExtensionAPI
include Validations
attr_accessor :critical
attr_accessor :ca
attr_accessor :path_len
def validate
unless [true, false].include? self.critical
errors.add :critical, 'must be true or false'
end
unless [true, false].include? self.ca
errors.add :ca, 'must be true or false'
end
end
def initialize
@critical = false
@ca = false
end
def openssl_identifier
OPENSSL_IDENTIFIER
end
def is_ca?
@ca
end
def path_len=(value)
fail(ArgumentError, "path_len must be a non-negative integer") if !value.is_a?(Integer) || value < 0
@path_len = value
end
def to_s
res = []
res << "CA:#{@ca}"
res << "pathlen:#{@path_len}" unless @path_len.nil?
res.join(',')
end
def ==(o)
o.class == self.class && o.state == state
end
def self.parse(value, critical)
obj = self.new
return obj if value.nil?
obj.critical = critical
value.split(/,\s*/).each do |v|
c = v.split(':', 2)
obj.ca = (c.last.upcase == "TRUE") if c.first == "CA"
obj.path_len = c.last.to_i if c.first == "pathlen"
end
obj
end
protected
def state
[@critical,@ca,@path_len]
end
end
# Specifies where CRL information be be retrieved. This extension isn't
# critical, but is recommended for proper CAs.
# Reference: Section 4.2.1.14 of RFC3280
# http://tools.ietf.org/html/rfc3280#section-4.2.1.14
class CrlDistributionPoints
OPENSSL_IDENTIFIER = "crlDistributionPoints"
include ExtensionAPI
attr_accessor :critical
attr_accessor :uris
def initialize
@critical = false
@uris = []
end
def openssl_identifier
OPENSSL_IDENTIFIER
end
## NB: At this time it seems OpenSSL's extension handlers don't support
## any of the config options the docs claim to support... everything comes back
## "missing value" on GENERAL NAME. Even if copied verbatim
def config_extensions
{
# "custom_crl_fields" => {"fullname" => "URI:#{fullname}"},
# "issuer_sect" => {"CN" => "crlissuer.com", "C" => "US", "O" => "shudder"}
}
end
# This is for legacy support. Technically it can (and probably should)
# be an array. But if someone is calling the old accessor we shouldn't
# necessarily break it.
def uri=(value)
@uris << value
end
def to_s
res = []
@uris.each do |uri|
res << "URI:#{uri}"
end
res.join(',')
end
def ==(o)
o.class == self.class && o.state == state
end
def self.parse(value, critical)
obj = self.new
return obj if value.nil?
obj.critical = critical
value.split(/,\s*/).each do |v|
c = v.split(':', 2)
obj.uris << c.last if c.first == "URI"
end
obj
end
protected
def state
[@critical,@uri]
end
end
# Identifies the public key associated with a given certificate.
# Should be required for "CA" certificates.
# Reference: Section 4.2.1.2 of RFC3280
# http://tools.ietf.org/html/rfc3280#section-4.2.1.2
class SubjectKeyIdentifier
OPENSSL_IDENTIFIER = "subjectKeyIdentifier"
include ExtensionAPI
attr_accessor :critical
attr_accessor :identifier
def initialize
@critical = false
@identifier = "hash"
end
def openssl_identifier
OPENSSL_IDENTIFIER
end
def to_s
res = []
res << @identifier
res.join(',')
end
def ==(o)
o.class == self.class && o.state == state
end
def self.parse(value, critical)
obj = self.new
return obj if value.nil?
obj.critical = critical
obj.identifier = value
obj
end
protected
def state
[@critical,@identifier]
end
end
# Identifies the public key associated with a given private key.
# Reference: Section 4.2.1.1 of RFC3280
# http://tools.ietf.org/html/rfc3280#section-4.2.1.1
class AuthorityKeyIdentifier
OPENSSL_IDENTIFIER = "authorityKeyIdentifier"
include ExtensionAPI
attr_accessor :critical
attr_accessor :identifier
def initialize
@critical = false
@identifier = ["keyid", "issuer"]
end
def openssl_identifier
OPENSSL_IDENTIFIER
end
def to_s
res = []
res += @identifier
res.join(',')
end
def ==(o)
o.class == self.class && o.state == state
end
def self.parse(value, critical)
obj = self.new
return obj if value.nil?
obj.critical = critical
obj.identifier = value.split(/,\s*/).last.chomp
obj
end
protected
def state
[@critical,@identifier]
end
end
# Specifies how to access CA information and services for the CA that
# issued this certificate.
# Generally used to specify OCSP servers.
# Reference: Section 4.2.2.1 of RFC3280
# http://tools.ietf.org/html/rfc3280#section-4.2.2.1
class AuthorityInfoAccess
OPENSSL_IDENTIFIER = "authorityInfoAccess"
include ExtensionAPI
attr_accessor :critical
attr_accessor :ocsp
attr_accessor :ca_issuers
def initialize
@critical = false
@ocsp = []
@ca_issuers = []
end
def openssl_identifier
OPENSSL_IDENTIFIER
end
def to_s
res = []
res += @ocsp.map {|o| "OCSP;URI:#{o}" }
res += @ca_issuers.map {|c| "caIssuers;URI:#{c}" }
res.join(',')
end
def ==(o)
o.class == self.class && o.state == state
end
def self.parse(value, critical)
obj = self.new
return obj if value.nil?
obj.critical = critical
value.split("\n").each do |v|
if v =~ /^OCSP/
obj.ocsp << v.split.last
end
if v =~ /^CA Issuers/
obj.ca_issuers << v.split.last
end
end
obj
end
protected
def state
[@critical,@ocsp,@ca_issuers]
end
end
# Specifies the allowed usage purposes of the keypair specified in this certificate.
# Reference: Section 4.2.1.3 of RFC3280
# http://tools.ietf.org/html/rfc3280#section-4.2.1.3
#
# Note: OpenSSL when parsing an extension will return results in the form
# 'Digital Signature', but on signing you have to set it to 'digitalSignature'.
# So copying an extension from an imported cert isn't going to work yet.
class KeyUsage
OPENSSL_IDENTIFIER = "keyUsage"
include ExtensionAPI
attr_accessor :critical
attr_accessor :usage
def initialize
@critical = false
@usage = ["digitalSignature", "nonRepudiation"]
end
def openssl_identifier
OPENSSL_IDENTIFIER
end
def to_s
res = []
res += @usage
res.join(',')
end
def ==(o)
o.class == self.class && o.state == state
end
def self.parse(value, critical)
obj = self.new
return obj if value.nil?
obj.critical = critical
obj.usage = value.split(/,\s*/)
obj
end
protected
def state
[@critical,@usage]
end
end
# Specifies even more allowed usages in addition to what is specified in
# the Key Usage extension.
# Reference: Section 4.2.1.13 of RFC3280
# http://tools.ietf.org/html/rfc3280#section-4.2.1.13
class ExtendedKeyUsage
OPENSSL_IDENTIFIER = "extendedKeyUsage"
include ExtensionAPI
attr_accessor :critical
attr_accessor :usage
def initialize
@critical = false
@usage = ["serverAuth"]
end
def openssl_identifier
OPENSSL_IDENTIFIER
end
def to_s
res = []
res += @usage
res.join(',')
end
def ==(o)
o.class == self.class && o.state == state
end
def self.parse(value, critical)
obj = self.new
return obj if value.nil?
obj.critical = critical
obj.usage = value.split(/,\s*/)
obj
end
protected
def state
[@critical,@usage]
end
end
# Specifies additional "names" for which this certificate is valid.
# Reference: Section 4.2.1.7 of RFC3280
# http://tools.ietf.org/html/rfc3280#section-4.2.1.7
class SubjectAlternativeName
OPENSSL_IDENTIFIER = "subjectAltName"
include ExtensionAPI
attr_accessor :critical
attr_accessor :uris, :dns_names, :ips, :emails
def initialize
@critical = false
@uris = []
@dns_names = []
@ips = []
@emails = []
end
def openssl_identifier
OPENSSL_IDENTIFIER
end
def uris=(value)
raise "URIs must be an array" unless value.is_a?(Array)
@uris = value
end
def dns_names=(value)
raise "DNS names must be an array" unless value.is_a?(Array)
@dns_names = value
end
def ips=(value)
raise "IPs must be an array" unless value.is_a?(Array)
@ips = value
end
def emails=(value)
raise "Emails must be an array" unless value.is_a?(Array)
@emails = value
end
def to_s
res = []
res += @uris.map {|u| "URI:#{u}" }
res += @dns_names.map {|d| "DNS:#{d}" }
res += @ips.map {|i| "IP:#{i}" }
res += @emails.map {|i| "email:#{i}" }
res.join(',')
end
def ==(o)
o.class == self.class && o.state == state
end
def self.parse(value, critical)
obj = self.new
return obj if value.nil?
obj.critical = critical
value.split(/,\s*/).each do |v|
c = v.split(':', 2)
obj.uris << c.last if c.first == "URI"
obj.dns_names << c.last if c.first == "DNS"
obj.ips << c.last if c.first == "IP"
obj.emails << c.last if c.first == "EMAIL"
end
obj
end
protected
def state
[@critical,@uris,@dns_names,@ips,@emails]
end
end
class CertificatePolicies
OPENSSL_IDENTIFIER = "certificatePolicies"
include ExtensionAPI
attr_accessor :critical
attr_accessor :policy_identifier
attr_accessor :cps_uris
##User notice
attr_accessor :explicit_text
attr_accessor :organization
attr_accessor :notice_numbers
def initialize
self.critical = false
@contains_data = false
end
def openssl_identifier
OPENSSL_IDENTIFIER
end
def user_notice=(value={})
value.keys.each do |key|
self.send("#{key}=".to_sym, value[key])
end
end
def config_extensions
config_extension = {}
custom_policies = {}
notice = {}
unless self.policy_identifier.nil?
custom_policies["policyIdentifier"] = self.policy_identifier
end
if !self.cps_uris.nil? and self.cps_uris.is_a?(Array)
self.cps_uris.each_with_index do |cps_uri,i|
custom_policies["CPS.#{i}"] = cps_uri
end
end
unless self.explicit_text.nil?
notice["explicitText"] = self.explicit_text
end
unless self.organization.nil?
notice["organization"] = self.organization
end
unless self.notice_numbers.nil?
notice["noticeNumbers"] = self.notice_numbers
end
if notice.keys.size > 0
custom_policies["userNotice.1"] = "@notice"
config_extension["notice"] = notice
end
if custom_policies.keys.size > 0
config_extension["custom_policies"] = custom_policies
@contains_data = true
end
config_extension
end
def to_s
return "" unless @contains_data
res = []
res << "ia5org"
res += @config_extensions["custom_policies"] unless @config_extensions.nil?
res.join(',')
end
def self.parse(value, critical)
obj = self.new
return obj if value.nil?
obj.critical = critical
value.split(/,\s*/).each do |v|
c = v.split(':', 2)
obj.policy_identifier = c.last if c.first == "policyIdentifier"
obj.cps_uris << c.last if c.first =~ %r{CPS.\d+}
# TODO: explicit_text, organization, notice_numbers
end
obj
end
end
# DEPRECATED
# Specifics the purposes for which a certificate can be used.
# The basicConstraints, keyUsage, and extendedKeyUsage extensions are now used instead.
# https://www.openssl.org/docs/apps/x509v3_config.html#Netscape_Certificate_Type
class NetscapeCertificateType
OPENSSL_IDENTIFIER = "nsCertType"
include ExtensionAPI
attr_accessor :critical
attr_accessor :flags
def initialize
self.critical = false
self.flags = []
end
def openssl_identifier
OPENSSL_IDENTIFIER
end
def to_s
res = []
res += self.flags
res.join(',')
end
def self.parse(value, critical)
obj = self.new
return obj if value.nil?
obj.critical = critical
obj.flags = value.split(/,\s*/)
obj
end
end
# DEPRECATED
# Contains a comment which will be displayed when the certificate is viewed in some browsers.
# https://www.openssl.org/docs/apps/x509v3_config.html#Netscape_String_extensions_
class NetscapeComment
OPENSSL_IDENTIFIER = "nsComment"
include ExtensionAPI
attr_accessor :critical
attr_accessor :comment
def initialize
self.critical = false
end
def openssl_identifier
OPENSSL_IDENTIFIER
end
def to_s
res = []
res << self.comment if self.comment
res.join(',')
end
def self.parse(value, critical)
obj = self.new
return obj if value.nil?
obj.critical = critical
obj.comment = value
obj
end
end
end
end
certificate_authority-1.1.0/lib/certificate_authority/key_material.rb 0000664 0000000 0000000 00000004377 14257354536 0026267 0 ustar 00root root 0000000 0000000 module CertificateAuthority
module KeyMaterial
def public_key
raise "Required implementation"
end
def private_key
raise "Required implementation"
end
def is_in_hardware?
raise "Required implementation"
end
def is_in_memory?
raise "Required implementation"
end
def self.from_x509_key_pair(pair,password=nil)
if password.nil?
key = OpenSSL::PKey::RSA.new(pair)
else
key = OpenSSL::PKey::RSA.new(pair,password)
end
mem_key = MemoryKeyMaterial.new
mem_key.public_key = key.public_key
mem_key.private_key = key
mem_key
end
def self.from_x509_public_key(public_key_pem)
key = OpenSSL::PKey::RSA.new(public_key_pem)
signing_request_key = SigningRequestKeyMaterial.new
signing_request_key.public_key = key.public_key
signing_request_key
end
end
class MemoryKeyMaterial
include KeyMaterial
include Validations
attr_accessor :keypair
attr_accessor :private_key
attr_accessor :public_key
def initialize
end
def validate
if private_key.nil?
errors.add :private_key, "cannot be blank"
end
if public_key.nil?
errors.add :public_key, "cannot be blank"
end
end
def is_in_hardware?
false
end
def is_in_memory?
true
end
def generate_key(modulus_bits=2048)
self.keypair = OpenSSL::PKey::RSA.new(modulus_bits)
self.private_key = keypair
self.public_key = keypair.public_key
self.keypair
end
def private_key
@private_key
end
def public_key
@public_key
end
end
class SigningRequestKeyMaterial
include KeyMaterial
include Validations
def validate
errors.add :public_key, "cannot be blank" if public_key.nil?
end
attr_accessor :public_key
def initialize(request=nil)
if request.is_a? OpenSSL::X509::Request
raise "Invalid certificate signing request" unless request.verify request.public_key
self.public_key = request.public_key
end
end
def is_in_hardware?
false
end
def is_in_memory?
true
end
def private_key
nil
end
def public_key
@public_key
end
end
end
certificate_authority-1.1.0/lib/certificate_authority/ocsp_handler.rb 0000664 0000000 0000000 00000010544 14257354536 0026253 0 ustar 00root root 0000000 0000000 module CertificateAuthority
class OCSPResponseBuilder
attr_accessor :ocsp_response
attr_accessor :verification_mechanism
attr_accessor :ocsp_request_reader
attr_accessor :parent
attr_accessor :next_update
GOOD = OpenSSL::OCSP::V_CERTSTATUS_GOOD
REVOKED = OpenSSL::OCSP::V_CERTSTATUS_REVOKED
NO_REASON=0
KEY_COMPROMISED=OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE
UNSPECIFIED=OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED
def build_response()
raise "Requires a parent for signing" if @parent.nil?
if @verification_mechanism.nil?
## If no verification callback is provided we're marking it GOOD
@verification_mechanism = lambda {|cert_id| [GOOD,NO_REASON] }
end
@ocsp_request_reader.ocsp_request.certid.each do |cert_id|
result,reason = verification_mechanism.call(cert_id.serial)
## cert_id, status, reason, rev_time, this update, next update, ext
## - unit of time is seconds
## - rev_time is currently set to "now"
@ocsp_response.add_status(cert_id,
result, reason,
0, 0, @next_update, nil)
end
@ocsp_response.sign(OpenSSL::X509::Certificate.new(@parent.to_pem), @parent.key_material.private_key, nil, nil)
OpenSSL::OCSP::Response.create(OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, @ocsp_response)
end
def self.from_request_reader(request_reader,verification_mechanism=nil)
response_builder = OCSPResponseBuilder.new
response_builder.ocsp_request_reader = request_reader
ocsp_response = OpenSSL::OCSP::BasicResponse.new
ocsp_response.copy_nonce(request_reader.ocsp_request)
response_builder.ocsp_response = ocsp_response
response_builder.next_update = 60*15 #Default of 15 minutes
response_builder
end
end
class OCSPRequestReader
attr_accessor :raw_ocsp_request
attr_accessor :ocsp_request
def serial_numbers
@ocsp_request.certid.collect do |cert_id|
cert_id.serial
end
end
def self.from_der(request_body)
reader = OCSPRequestReader.new
reader.raw_ocsp_request = request_body
reader.ocsp_request = OpenSSL::OCSP::Request.new(request_body)
reader
end
end
## DEPRECATED
class OCSPHandler
include Validations
attr_accessor :ocsp_request
attr_accessor :certificate_ids
attr_accessor :certificates
attr_accessor :parent
attr_accessor :ocsp_response_body
def validate
errors.add :parent, "A parent entity must be set" if parent.nil?
all_certificates_available
end
def initialize
self.certificates = {}
end
def <<(cert)
self.certificates[cert.serial_number.number.to_s] = cert
end
def extract_certificate_serials
openssl_request = OpenSSL::OCSP::Request.new(@ocsp_request)
if openssl_request.certid.nil?
raise "Invalid openssl request"
end
self.certificate_ids = openssl_request.certid.collect do |cert_id|
cert_id.serial
end
self.certificate_ids
end
def response
raise "Invalid response" unless valid?
openssl_ocsp_response = OpenSSL::OCSP::BasicResponse.new
openssl_ocsp_request = OpenSSL::OCSP::Request.new(self.ocsp_request)
openssl_ocsp_response.copy_nonce(openssl_ocsp_request)
openssl_ocsp_request.certid.each do |cert_id|
certificate = self.certificates[cert_id.serial.to_s]
openssl_ocsp_response.add_status(cert_id,
OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0,
0, 0, 30, nil)
end
openssl_ocsp_response.sign(OpenSSL::X509::Certificate.new(self.parent.to_pem), self.parent.key_material.private_key, nil, nil)
final_response = OpenSSL::OCSP::Response.create(OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, openssl_ocsp_response)
self.ocsp_response_body = final_response
self.ocsp_response_body
end
def to_der
raise "No signed OCSP response body available" if self.ocsp_response_body.nil?
self.ocsp_response_body.to_der
end
private
def all_certificates_available
openssl_ocsp_request = OpenSSL::OCSP::Request.new(self.ocsp_request)
openssl_ocsp_request.certid.each do |cert_id|
certificate = self.certificates[cert_id.serial.to_s]
errors.add(:base, "Certificate #{cert_id.serial} has not been added yet") if certificate.nil?
end
end
end
end
certificate_authority-1.1.0/lib/certificate_authority/pkcs11_key_material.rb 0000664 0000000 0000000 00000003000 14257354536 0027427 0 ustar 00root root 0000000 0000000 module CertificateAuthority
class Pkcs11KeyMaterial
include KeyMaterial
attr_accessor :engine
attr_accessor :token_id
attr_accessor :pkcs11_lib
attr_accessor :openssl_pkcs11_engine_lib
attr_accessor :pin
def initialize(attributes = {})
@attributes = attributes
initialize_engine
end
def is_in_hardware?
true
end
def is_in_memory?
false
end
def generate_key(modulus_bits=1024)
puts "Key generation is not currently supported in hardware"
nil
end
def private_key
initialize_engine
self.engine.load_private_key(self.token_id)
end
def public_key
initialize_engine
self.engine.load_public_key(self.token_id)
end
private
def initialize_engine
## We're going to return early and try again later if params weren't passed in
## at initialization. Any attempt at getting a public/private key will try
## again.
return false if self.openssl_pkcs11_engine_lib.nil? or self.pkcs11_lib.nil?
return self.engine unless self.engine.nil?
OpenSSL::Engine.load
pkcs11 = OpenSSL::Engine.by_id("dynamic") do |e|
e.ctrl_cmd("SO_PATH",self.openssl_pkcs11_engine_lib)
e.ctrl_cmd("ID","pkcs11")
e.ctrl_cmd("LIST_ADD","1")
e.ctrl_cmd("LOAD")
e.ctrl_cmd("PIN",self.pin) unless self.pin.nil? or self.pin == ""
e.ctrl_cmd("MODULE_PATH",self.pkcs11_lib)
end
self.engine = pkcs11
pkcs11
end
end
end
certificate_authority-1.1.0/lib/certificate_authority/revocable.rb 0000664 0000000 0000000 00000000370 14257354536 0025550 0 ustar 00root root 0000000 0000000 module CertificateAuthority
module Revocable
attr_accessor :revoked_at
def revoke!(time=Time.now)
@revoked_at = time
end
def revoked?
# If we have a time, then we're revoked
!@revoked_at.nil?
end
end
end
certificate_authority-1.1.0/lib/certificate_authority/serial_number.rb 0000664 0000000 0000000 00000000671 14257354536 0026441 0 ustar 00root root 0000000 0000000 require 'securerandom'
module CertificateAuthority
class SerialNumber
include Validations
include Revocable
attr_accessor :number
def validate
if self.number.nil?
errors.add :number, "must not be empty"
elsif self.number.to_i <= 0
errors.add :number, "must be greater than zero"
end
end
def initialize
self.number = SecureRandom.random_number(2**128-1)
end
end
end
certificate_authority-1.1.0/lib/certificate_authority/signing_entity.rb 0000664 0000000 0000000 00000000452 14257354536 0026641 0 ustar 00root root 0000000 0000000 module CertificateAuthority
module SigningEntity
def self.included(mod)
mod.class_eval do
attr_accessor :signing_entity
end
end
def signing_entity=(val)
raise "invalid param" unless [true,false].include?(val)
@signing_entity = val
end
end
end
certificate_authority-1.1.0/lib/certificate_authority/signing_request.rb 0000664 0000000 0000000 00000006257 14257354536 0027026 0 ustar 00root root 0000000 0000000 module CertificateAuthority
class SigningRequest
attr_accessor :distinguished_name
attr_accessor :key_material
attr_accessor :raw_body
attr_accessor :openssl_csr
attr_accessor :digest
attr_accessor :attributes
def initialize()
@attributes = []
end
# Fake attribute for convenience because adding
# alternative names on a CSR is remarkably non-trivial.
def subject_alternative_names=(alt_names)
raise "alt_names must be an Array" unless alt_names.is_a?(Array)
factory = OpenSSL::X509::ExtensionFactory.new
name_list = alt_names.map{|m| "DNS:#{m}"}.join(",")
ext = factory.create_ext("subjectAltName",name_list,false)
ext_set = OpenSSL::ASN1::Set([OpenSSL::ASN1::Sequence([ext])])
attr = OpenSSL::X509::Attribute.new("extReq", ext_set)
@attributes << attr
end
def read_attributes_by_oid(*oids)
attributes.detect { |a| oids.include?(a.oid) }
end
protected :read_attributes_by_oid
def to_cert
cert = Certificate.new
if !@distinguished_name.nil?
cert.distinguished_name = @distinguished_name
end
cert.key_material = @key_material
if attribute = read_attributes_by_oid('extReq', 'msExtReq')
set = OpenSSL::ASN1.decode(attribute.value)
seq = set.value.first
seq.value.collect { |asn1ext| OpenSSL::X509::Extension.new(asn1ext).to_a }.each do |o, v, c|
Certificate::EXTENSIONS.each do |klass|
cert.extensions[klass::OPENSSL_IDENTIFIER] = klass.parse(v, c) if v && klass::OPENSSL_IDENTIFIER == o
end
end
end
cert
end
def to_pem
to_x509_csr.to_pem
end
def to_x509_csr
raise "Must specify a DN/subject on csr" if @distinguished_name.nil?
raise "Invalid DN in request" unless @distinguished_name.valid?
raise "CSR must have key material" if @key_material.nil?
raise "CSR must include a public key on key material" if @key_material.public_key.nil?
raise "Need a private key on key material for CSR generation" if @key_material.private_key.nil?
opensslcsr = OpenSSL::X509::Request.new
opensslcsr.subject = @distinguished_name.to_x509_name
opensslcsr.public_key = @key_material.public_key
opensslcsr.attributes = @attributes unless @attributes.nil?
opensslcsr.sign @key_material.private_key, OpenSSL::Digest.new(@digest || "SHA512")
opensslcsr
end
def self.from_x509_csr(raw_csr)
csr = SigningRequest.new
openssl_csr = OpenSSL::X509::Request.new(raw_csr)
csr.distinguished_name = DistinguishedName.from_openssl openssl_csr.subject
csr.raw_body = raw_csr
csr.openssl_csr = openssl_csr
csr.attributes = openssl_csr.attributes
key_material = SigningRequestKeyMaterial.new
key_material.public_key = openssl_csr.public_key
csr.key_material = key_material
csr
end
def self.from_netscape_spkac(raw_spkac)
openssl_spkac = OpenSSL::Netscape::SPKI.new raw_spkac
csr = SigningRequest.new
csr.raw_body = raw_spkac
key_material = SigningRequestKeyMaterial.new
key_material.public_key = openssl_spkac.public_key
csr
end
end
end
certificate_authority-1.1.0/lib/certificate_authority/validations.rb 0000664 0000000 0000000 00000001025 14257354536 0026121 0 ustar 00root root 0000000 0000000 #
# This is a super simple replacement for ActiveSupport::Validations
#
module CertificateAuthority
class Errors < Array
def add(symbol, msg)
self.push([symbol, msg])
end
def full_messages
self.map {|i| i[0].to_s + ": " + i[1]}.join("\n")
end
end
module Validations
def valid?
@errors = Errors.new
validate
errors.empty?
end
# must be overridden
def validate
raise NotImplementedError
end
def errors
@errors ||= Errors.new
end
end
end
certificate_authority-1.1.0/lib/certificate_authority/version.rb 0000664 0000000 0000000 00000000073 14257354536 0025273 0 ustar 00root root 0000000 0000000 module CertificateAuthority
VERSION = '1.1.0'.freeze
end
certificate_authority-1.1.0/lib/tasks/ 0000775 0000000 0000000 00000000000 14257354536 0020014 5 ustar 00root root 0000000 0000000 certificate_authority-1.1.0/lib/tasks/certificate_authority.rake 0000664 0000000 0000000 00000001037 14257354536 0025253 0 ustar 00root root 0000000 0000000 require 'certificate_authority'
namespace :certificate_authority do
desc "Generate a quick self-signed cert"
task :self_signed do
cn = "http://localhost"
cn = ENV['DOMAIN'] unless ENV['DOMAIN'].nil?
root = CertificateAuthority::Certificate.new
root.subject.common_name= cn
root.key_material.generate_key
root.signing_entity = true
root.valid?
root.sign!
print "Your cert for #{cn}\n"
print root.to_pem
print "Your private key\n"
print root.key_material.private_key.to_pem
end
end
certificate_authority-1.1.0/spec/ 0000775 0000000 0000000 00000000000 14257354536 0017053 5 ustar 00root root 0000000 0000000 certificate_authority-1.1.0/spec/samples/ 0000775 0000000 0000000 00000000000 14257354536 0020517 5 ustar 00root root 0000000 0000000 certificate_authority-1.1.0/spec/samples/certs/ 0000775 0000000 0000000 00000000000 14257354536 0021637 5 ustar 00root root 0000000 0000000 certificate_authority-1.1.0/spec/samples/certs/DigiCertHighAssuranceEVCA-1.pem 0000664 0000000 0000000 00000014670 14257354536 0027306 0 ustar 00root root 0000000 0000000 Certificate:
Data:
Version: 3 (0x2)
Serial Number:
08:bb:b0:25:47:13:4b:c9:b1:10:d7:c1:a2:12:59:c5
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA
Validity
Not Before: Nov 10 00:00:00 2006 GMT
Not After : Nov 10 00:00:00 2021 GMT
Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV CA-1
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (2048 bit)
Modulus (2048 bit):
00:f3:96:62:d8:75:6e:19:ff:3f:34:7c:49:4f:31:
7e:0d:04:4e:99:81:e2:b3:85:55:91:30:b1:c0:af:
70:bb:2c:a8:e7:18:aa:3f:78:f7:90:68:52:86:01:
88:97:e2:3b:06:65:90:aa:bd:65:76:c2:ec:be:10:
5b:37:78:83:60:75:45:c6:bd:74:aa:b6:9f:a4:3a:
01:50:17:c4:39:69:b9:f1:4f:ef:82:c1:ca:f3:4a:
db:cc:9e:50:4f:4d:40:a3:3a:90:e7:86:66:bc:f0:
3e:76:28:4c:d1:75:80:9e:6a:35:14:35:03:9e:db:
0c:8c:c2:28:ad:50:b2:ce:f6:91:a3:c3:a5:0a:58:
49:f6:75:44:6c:ba:f9:ce:e9:ab:3a:02:e0:4d:f3:
ac:e2:7a:e0:60:22:05:3c:82:d3:52:e2:f3:9c:47:
f8:3b:d8:b2:4b:93:56:4a:bf:70:ab:3e:e9:68:c8:
1d:8f:58:1d:2a:4d:5e:27:3d:ad:0a:59:2f:5a:11:
20:40:d9:68:04:68:2d:f4:c0:84:0b:0a:1b:78:df:
ed:1a:58:dc:fb:41:5a:6d:6b:f2:ed:1c:ee:5c:32:
b6:5c:ec:d7:a6:03:32:a6:e8:de:b7:28:27:59:88:
80:ff:7b:ad:89:58:d5:1e:14:a4:f2:b0:70:d4:a0:
3e:a7
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Certificate Sign, CRL Sign
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication, Code Signing, E-mail Protection, Time Stamping
X509v3 Certificate Policies:
Policy: 2.16.840.1.114412.2.1
CPS: http://www.digicert.com/ssl-cps-repository.htm
User Notice:
Explicit Text:
X509v3 Basic Constraints: critical
CA:TRUE
Authority Information Access:
OCSP - URI:http://ocsp.digicert.com
CA Issuers - URI:http://www.digicert.com/CACerts/DigiCertHighAssuranceEVRootCA.crt
X509v3 CRL Distribution Points:
URI:http://crl3.digicert.com/DigiCertHighAssuranceEVRootCA.crl
URI:http://crl4.digicert.com/DigiCertHighAssuranceEVRootCA.crl
X509v3 Subject Key Identifier:
4C:58:CB:25:F0:41:4F:52:F4:28:C8:81:43:9B:A6:A8:A0:E6:92:E5
X509v3 Authority Key Identifier:
keyid:B1:3E:C3:69:03:F8:BF:47:01:D4:98:26:1A:08:02:EF:63:64:2B:C3
Signature Algorithm: sha1WithRSAEncryption
50:1e:43:b0:f7:4d:29:96:5b:bb:a7:d3:0a:b5:b5:d5:d0:27:
aa:f9:af:c7:25:d1:95:d5:2f:5a:53:bd:42:07:7e:78:49:ca:
0b:eb:4c:55:e2:ea:2f:7f:49:ad:c7:ff:d1:2d:3e:9c:a0:64:
2b:51:9e:91:26:28:bb:87:bb:75:7c:bc:a1:fd:66:68:2e:4c:
4a:16:cc:fe:06:cf:31:ea:80:6e:e4:bd:e8:03:72:f6:25:b5:
41:83:61:d0:97:0a:27:1d:b3:f7:2b:32:84:8f:5b:e7:cc:3f:
e2:2c:67:86:94:f4:b2:2b:6c:52:3b:67:2a:8d:58:95:00:14:
46:24:ac:0b:fa:c9:8e:c7:26:80:df:d1:e1:97:e3:f8:bb:68:
c6:9c:bd:be:08:54:3b:10:32:7c:81:1f:2b:28:95:a8:41:0a:
c6:d0:30:66:b4:e9:f2:a2:00:69:20:07:ca:82:4c:1e:cf:a7:
98:b8:0c:ee:cd:16:1c:be:1a:63:d4:c0:99:f6:67:b2:f0:8e:
17:2d:58:c2:80:aa:5d:96:c7:b3:28:ed:f0:da:8e:b6:47:1b:
8f:4e:15:f1:97:4c:0b:4b:af:81:d4:46:94:62:2c:43:a7:3c:
25:48:19:63:f2:5c:aa:15:89:76:84:85:73:91:7d:28:3c:09:
83:82:bc:f7
-----BEGIN CERTIFICATE-----
MIIG4zCCBcugAwIBAgIQCLuwJUcTS8mxENfBohJZxTANBgkqhkiG9w0BAQUFADBs
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTIxMTExMDAwMDAwMFowaTEL
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
LmRpZ2ljZXJ0LmNvbTEoMCYGA1UEAxMfRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
RVYgQ0EtMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPOWYth1bhn/
PzR8SU8xfg0ETpmB4rOFVZEwscCvcLssqOcYqj9495BoUoYBiJfiOwZlkKq9ZXbC
7L4QWzd4g2B1Rca9dKq2n6Q6AVAXxDlpufFP74LByvNK28yeUE9NQKM6kOeGZrzw
PnYoTNF1gJ5qNRQ1A57bDIzCKK1Qss72kaPDpQpYSfZ1RGy6+c7pqzoC4E3zrOJ6
4GAiBTyC01Li85xH+DvYskuTVkq/cKs+6WjIHY9YHSpNXic9rQpZL1oRIEDZaARo
LfTAhAsKG3jf7RpY3PtBWm1r8u0c7lwytlzs16YDMqbo3rcoJ1mIgP97rYlY1R4U
pPKwcNSgPqcCAwEAAaOCA4IwggN+MA4GA1UdDwEB/wQEAwIBhjA7BgNVHSUENDAy
BggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMDBggrBgEFBQcDBAYIKwYBBQUH
AwgwggHEBgNVHSAEggG7MIIBtzCCAbMGCWCGSAGG/WwCATCCAaQwOgYIKwYBBQUH
AgEWLmh0dHA6Ly93d3cuZGlnaWNlcnQuY29tL3NzbC1jcHMtcmVwb3NpdG9yeS5o
dG0wggFkBggrBgEFBQcCAjCCAVYeggFSAEEAbgB5ACAAdQBzAGUAIABvAGYAIAB0
AGgAaQBzACAAQwBlAHIAdABpAGYAaQBjAGEAdABlACAAYwBvAG4AcwB0AGkAdAB1
AHQAZQBzACAAYQBjAGMAZQBwAHQAYQBuAGMAZQAgAG8AZgAgAHQAaABlACAARABp
AGcAaQBDAGUAcgB0ACAARQBWACAAQwBQAFMAIABhAG4AZAAgAHQAaABlACAAUgBl
AGwAeQBpAG4AZwAgAFAAYQByAHQAeQAgAEEAZwByAGUAZQBtAGUAbgB0ACAAdwBo
AGkAYwBoACAAbABpAG0AaQB0ACAAbABpAGEAYgBpAGwAaQB0AHkAIABhAG4AZAAg
AGEAcgBlACAAaQBuAGMAbwByAHAAbwByAGEAdABlAGQAIABoAGUAcgBlAGkAbgAg
AGIAeQAgAHIAZQBmAGUAcgBlAG4AYwBlAC4wDwYDVR0TAQH/BAUwAwEB/zCBgwYI
KwYBBQUHAQEEdzB1MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j
b20wTQYIKwYBBQUHMAKGQWh0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NBQ2VydHMv
RGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3J0MIGPBgNVHR8EgYcwgYQw
QKA+oDyGOmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEhpZ2hBc3N1
cmFuY2VFVlJvb3RDQS5jcmwwQKA+oDyGOmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNv
bS9EaWdpQ2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5jcmwwHQYDVR0OBBYEFExY
yyXwQU9S9CjIgUObpqig5pLlMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSYJhoIAu9j
ZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQBQHkOw900pllu7p9MKtbXV0Ceq+a/HJdGV
1S9aU71CB354ScoL60xV4uovf0mtx//RLT6coGQrUZ6RJii7h7t1fLyh/WZoLkxK
Fsz+Bs8x6oBu5L3oA3L2JbVBg2HQlwonHbP3KzKEj1vnzD/iLGeGlPSyK2xSO2cq
jViVABRGJKwL+smOxyaA39Hhl+P4u2jGnL2+CFQ7EDJ8gR8rKJWoQQrG0DBmtOny
ogBpIAfKgkwez6eYuAzuzRYcvhpj1MCZ9mey8I4XLVjCgKpdlsezKO3w2o62RxuP
ThXxl0wLS6+B1EaUYixDpzwlSBlj8lyqFYl2hIVzkX0oPAmDgrz3
-----END CERTIFICATE-----
certificate_authority-1.1.0/spec/samples/certs/apple_wwdr_issued_cert.pem 0000664 0000000 0000000 00000014103 14257354536 0027076 0 ustar 00root root 0000000 0000000 Certificate:
Data:
Version: 3 (0x2)
Serial Number:
0f:50:11:d8:8f:07:09:bf
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=US, O=Apple Inc., OU=Apple Worldwide Developer Relations, CN=Apple Worldwide Developer Relations Certification Authority
Validity
Not Before: Jun 26 21:18:40 2012 GMT
Not After : Jun 26 21:18:40 2013 GMT
Subject: UID=pass.void-star.com.meepedoo, CN=Pass Type ID: pass.void-star.com.meepedoo, OU=UL736KYQR9, O=Eric Monti, C=US
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (2048 bit)
Modulus (2048 bit):
00:af:f9:a6:9f:c0:8b:a5:56:f2:b6:97:0a:86:42:
d0:f1:54:01:98:95:9f:d9:69:2b:9c:be:b0:b5:f4:
a4:ad:9e:e6:ef:8e:a5:dc:50:d0:ce:2a:89:a9:41:
ce:44:36:af:90:33:e7:56:76:9e:68:91:df:c6:e7:
b8:21:f2:d5:75:d2:2a:17:3a:9d:4a:e0:cc:d2:94:
90:e7:f2:36:2f:1c:41:00:02:76:45:fe:c2:6a:fc:
36:96:e7:7e:59:00:f2:85:9e:31:ff:a3:9b:a0:b8:
6d:95:9e:e4:f1:c4:d0:e9:7c:70:61:52:03:39:5c:
b8:8a:34:69:22:82:c5:44:f9:cd:a1:25:57:26:86:
e4:31:d5:08:c9:9d:5f:73:44:10:21:6d:99:90:74:
f6:69:fb:20:de:a9:46:49:a3:a9:96:ab:66:44:e6:
bd:56:65:8e:7d:dd:07:7e:71:bd:13:0f:b1:50:07:
af:eb:71:78:af:46:d5:71:39:da:ed:f2:d1:db:8d:
81:64:7f:56:c6:87:f1:7e:a5:a3:f4:9f:02:01:b9:
d0:36:7f:87:f2:0d:d6:93:4e:cb:d8:32:9c:5a:ea:
44:07:64:6a:9f:1c:14:8e:9a:3a:0e:a3:86:2c:e8:
20:2a:f1:32:e0:11:2a:13:8a:d3:4c:73:5e:ab:70:
fa:4d
Exponent: 65537 (0x10001)
X509v3 extensions:
Authority Information Access:
OCSP - URI:http://ocsp.apple.com/ocsp-wwdr03
X509v3 Subject Key Identifier:
02:87:24:00:CA:53:38:8F:C3:4D:5C:80:98:E1:65:95:38:D5:2B:69
X509v3 Basic Constraints:
CA:FALSE
X509v3 Authority Key Identifier:
keyid:88:27:17:09:A9:B6:18:60:8B:EC:EB:BA:F6:47:59:C5:52:54:A3:B7
X509v3 Certificate Policies:
Policy: 1.2.840.113635.100.5.1
CPS: http://www.apple.com/appleca/
User Notice:
Explicit Text: Reliance on this certificate by any party assumes acceptance of the then applicable standard terms and conditions of use, certificate policy and certification practice statements.
X509v3 CRL Distribution Points:
URI:http://crl.apple.com/wwdrca.crl
X509v3 Key Usage:
Digital Signature
X509v3 Extended Key Usage:
TLS Web Client Authentication, 1.2.840.113635.100.4.14
1.2.840.113635.100.6.3.2:
..
1.2.840.113635.100.6.1.16:
..pass.void-star.com.meepedoo
Signature Algorithm: sha1WithRSAEncryption
5d:e8:2d:5a:d7:65:9e:92:dd:bf:66:1c:04:99:08:a9:40:b7:
92:dc:fa:d4:c8:8c:cf:ad:3a:99:22:34:0c:0f:72:c9:4f:7f:
c5:90:dc:8a:5d:47:c0:dd:ee:47:f7:01:81:6a:06:61:66:c3:
44:a1:0b:96:e5:70:a2:2f:c3:bb:98:d0:bf:07:0a:3d:56:d1:
95:01:08:16:6e:9a:5e:6b:45:ce:d9:b5:78:09:0f:eb:ff:11:
a6:9a:eb:65:f3:b3:b1:14:a5:6f:97:a1:53:31:65:a6:e0:ea:
e6:70:2f:df:5a:f9:b5:e4:59:2b:33:d4:a0:a3:4c:c6:61:c8:
56:5a:ca:be:4e:ac:12:c7:d3:1e:e5:b6:e3:de:04:c4:63:e5:
0e:33:4d:b9:33:92:7e:11:a4:ee:85:2b:65:00:7f:a5:dc:f6:
19:5b:69:37:fe:61:a7:e6:45:27:c5:1c:3a:b6:46:76:fb:f3:
56:93:00:2a:4f:b4:1e:d3:ed:75:8c:32:e5:09:c8:28:84:46:
29:4d:db:8f:e9:6e:1c:9e:bb:76:74:6a:8f:63:d5:04:1a:b3:
16:42:cc:70:4c:b1:88:e2:6d:58:bd:52:d2:3c:dc:52:9d:de:
37:94:20:00:07:6e:06:48:e7:17:86:44:a2:3a:23:07:c1:74:
ef:6f:2a:a5
-----BEGIN CERTIFICATE-----
MIIF8zCCBNugAwIBAgIID1AR2I8HCb8wDQYJKoZIhvcNAQEFBQAwgZYxCzAJBgNV
BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js
ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3
aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw
HhcNMTIwNjI2MjExODQwWhcNMTMwNjI2MjExODQwWjCBmDErMCkGCgmSJomT8ixk
AQEMG3Bhc3Mudm9pZC1zdGFyLmNvbS5tZWVwZWRvbzEyMDAGA1UEAwwpUGFzcyBU
eXBlIElEOiBwYXNzLnZvaWQtc3Rhci5jb20ubWVlcGVkb28xEzARBgNVBAsMClVM
NzM2S1lRUjkxEzARBgNVBAoMCkVyaWMgTW9udGkxCzAJBgNVBAYTAlVTMIIBIjAN
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr/mmn8CLpVbytpcKhkLQ8VQBmJWf
2WkrnL6wtfSkrZ7m746l3FDQziqJqUHORDavkDPnVnaeaJHfxue4IfLVddIqFzqd
SuDM0pSQ5/I2LxxBAAJ2Rf7Cavw2lud+WQDyhZ4x/6OboLhtlZ7k8cTQ6XxwYVID
OVy4ijRpIoLFRPnNoSVXJobkMdUIyZ1fc0QQIW2ZkHT2afsg3qlGSaOplqtmROa9
VmWOfd0HfnG9Ew+xUAev63F4r0bVcTna7fLR242BZH9WxofxfqWj9J8CAbnQNn+H
8g3Wk07L2DKcWupEB2RqnxwUjpo6DqOGLOggKvEy4BEqE4rTTHNeq3D6TQIDAQAB
o4ICPzCCAjswPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vb2Nz
cC5hcHBsZS5jb20vb2NzcC13d2RyMDMwHQYDVR0OBBYEFAKHJADKUziPw01cgJjh
ZZU41StpMAkGA1UdEwQCMAAwHwYDVR0jBBgwFoAUiCcXCam2GGCL7Ou69kdZxVJU
o7cwggEPBgNVHSAEggEGMIIBAjCB/wYJKoZIhvdjZAUBMIHxMCkGCCsGAQUFBwIB
Fh1odHRwOi8vd3d3LmFwcGxlLmNvbS9hcHBsZWNhLzCBwwYIKwYBBQUHAgIwgbYM
gbNSZWxpYW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1
bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0
ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRlIHBvbGljeSBh
bmQgY2VydGlmaWNhdGlvbiBwcmFjdGljZSBzdGF0ZW1lbnRzLjAwBgNVHR8EKTAn
MCWgI6Ahhh9odHRwOi8vY3JsLmFwcGxlLmNvbS93d2RyY2EuY3JsMAsGA1UdDwQE
AwIHgDAeBgNVHSUEFzAVBggrBgEFBQcDAgYJKoZIhvdjZAQOMBAGCiqGSIb3Y2QG
AwIEAgUAMCsGCiqGSIb3Y2QGARAEHQwbcGFzcy52b2lkLXN0YXIuY29tLm1lZXBl
ZG9vMA0GCSqGSIb3DQEBBQUAA4IBAQBd6C1a12Wekt2/ZhwEmQipQLeS3PrUyIzP
rTqZIjQMD3LJT3/FkNyKXUfA3e5H9wGBagZhZsNEoQuW5XCiL8O7mNC/Bwo9VtGV
AQgWbppea0XO2bV4CQ/r/xGmmutl87OxFKVvl6FTMWWm4OrmcC/fWvm15FkrM9Sg
o0zGYchWWsq+TqwSx9Me5bbj3gTEY+UOM025M5J+EaTuhStlAH+l3PYZW2k3/mGn
5kUnxRw6tkZ2+/NWkwAqT7Qe0+11jDLlCcgohEYpTduP6W4cnrt2dGqPY9UEGrMW
QsxwTLGI4m1YvVLSPNxSnd43lCAAB24GSOcXhkSiOiMHwXTvbyql
-----END CERTIFICATE-----
certificate_authority-1.1.0/spec/samples/certs/apple_wwdr_issuer.pem 0000664 0000000 0000000 00000011414 14257354536 0026101 0 ustar 00root root 0000000 0000000 Certificate:
Data:
Version: 3 (0x2)
Serial Number: 25 (0x19)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=US, O=Apple Inc., OU=Apple Certification Authority, CN=Apple Root CA
Validity
Not Before: Feb 14 18:56:35 2008 GMT
Not After : Feb 14 18:56:35 2016 GMT
Subject: C=US, O=Apple Inc., OU=Apple Worldwide Developer Relations, CN=Apple Worldwide Developer Relations Certification Authority
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (2048 bit)
Modulus (2048 bit):
00:ca:38:54:a6:cb:56:aa:c8:24:39:48:e9:8c:ee:
ec:5f:b8:7f:26:91:bc:34:53:7a:ce:7c:63:80:61:
77:64:5e:a5:07:23:b6:39:fe:50:2d:15:56:58:70:
2d:7e:c4:6e:c1:4a:85:3e:2f:f0:de:84:1a:a1:57:
c9:af:7b:18:ff:6a:fa:15:12:49:15:08:19:ac:aa:
db:2a:32:ed:96:63:68:52:15:3d:8c:8a:ec:bf:6b:
18:95:e0:03:ac:01:7d:97:05:67:ce:0e:85:95:37:
6a:ed:09:b6:ae:67:cd:51:64:9f:c6:5c:d1:bc:57:
6e:67:35:80:76:36:a4:87:81:6e:38:8f:d8:2b:15:
4e:7b:25:d8:5a:bf:4e:83:c1:8d:d2:93:d5:1a:71:
b5:60:9c:9d:33:4e:55:f9:12:58:0c:86:b8:16:0d:
c1:e5:77:45:8d:50:48:ba:2b:2d:e4:94:85:e1:e8:
c4:9d:c6:68:a5:b0:a3:fc:67:7e:70:ba:02:59:4b:
77:42:91:39:b9:f5:cd:e1:4c:ef:c0:3b:48:8c:a6:
e5:21:5d:fd:6a:6a:bb:a7:16:35:60:d2:e6:ad:f3:
46:29:c9:e8:c3:8b:e9:79:c0:6a:61:67:15:b2:f0:
fd:e5:68:bc:62:5f:6e:cf:99:dd:ef:1b:63:fe:92:
65:ab
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Subject Key Identifier:
88:27:17:09:A9:B6:18:60:8B:EC:EB:BA:F6:47:59:C5:52:54:A3:B7
X509v3 Authority Key Identifier:
keyid:2B:D0:69:47:94:76:09:FE:F4:6B:8D:2E:40:A6:F7:47:4D:7F:08:5E
X509v3 CRL Distribution Points:
URI:http://www.apple.com/appleca/root.crl
1.2.840.113635.100.6.2.1:
..
Signature Algorithm: sha1WithRSAEncryption
da:32:00:96:c5:54:94:d3:3b:82:37:66:7d:2e:68:d5:c3:c6:
b8:cb:26:8c:48:90:cf:13:24:6a:46:8e:63:d4:f0:d0:13:06:
dd:d8:c4:c1:37:15:f2:33:13:39:26:2d:ce:2e:55:40:e3:0b:
03:af:fa:12:c2:e7:0d:21:b8:d5:80:cf:ac:28:2f:ce:2d:b3:
4e:af:86:19:04:c6:e9:50:dd:4c:29:47:10:23:fc:6c:bb:1b:
98:6b:48:89:e1:5b:9d:de:46:db:35:85:35:ef:3e:d0:e2:58:
4b:38:f4:ed:75:5a:1f:5c:70:1d:56:39:12:e5:e1:0d:11:e4:
89:25:06:bd:d5:b4:15:8e:5e:d0:59:97:90:e9:4b:81:e2:df:
18:af:44:74:1e:19:a0:3a:47:cc:91:1d:3a:eb:23:5a:fe:a5:
2d:97:f7:7b:bb:d6:87:46:42:85:eb:52:3d:26:b2:63:a8:b4:
b1:ca:8f:f4:cc:e2:b3:c8:47:e0:bf:9a:59:83:fa:da:98:53:
2a:82:f5:7c:65:2e:95:d9:33:5d:f5:ed:65:cc:31:37:c5:5a:
04:e8:6b:e1:e7:88:03:4a:75:9e:9b:28:cb:4a:40:88:65:43:
75:dd:cb:3a:25:23:c5:9e:57:f8:2e:ce:d2:a9:92:5e:73:2e:
2f:25:75:15
-----BEGIN CERTIFICATE-----
MIIEIzCCAwugAwIBAgIBGTANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJVUzET
MBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlv
biBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwHhcNMDgwMjE0MTg1
NjM1WhcNMTYwMjE0MTg1NjM1WjCBljELMAkGA1UEBhMCVVMxEzARBgNVBAoMCkFw
cGxlIEluYy4xLDAqBgNVBAsMI0FwcGxlIFdvcmxkd2lkZSBEZXZlbG9wZXIgUmVs
YXRpb25zMUQwQgYDVQQDDDtBcHBsZSBXb3JsZHdpZGUgRGV2ZWxvcGVyIFJlbGF0
aW9ucyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAMo4VKbLVqrIJDlI6Yzu7F+4fyaRvDRTes58Y4Bhd2RepQcj
tjn+UC0VVlhwLX7EbsFKhT4v8N6EGqFXya97GP9q+hUSSRUIGayq2yoy7ZZjaFIV
PYyK7L9rGJXgA6wBfZcFZ84OhZU3au0Jtq5nzVFkn8Zc0bxXbmc1gHY2pIeBbjiP
2CsVTnsl2Fq/ToPBjdKT1RpxtWCcnTNOVfkSWAyGuBYNweV3RY1QSLorLeSUheHo
xJ3GaKWwo/xnfnC6AllLd0KRObn1zeFM78A7SIym5SFd/Wpqu6cWNWDS5q3zRinJ
6MOL6XnAamFnFbLw/eVovGJfbs+Z3e8bY/6SZasCAwEAAaOBrjCBqzAOBgNVHQ8B
Af8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUiCcXCam2GGCL7Ou6
9kdZxVJUo7cwHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wNgYDVR0f
BC8wLTAroCmgJ4YlaHR0cDovL3d3dy5hcHBsZS5jb20vYXBwbGVjYS9yb290LmNy
bDAQBgoqhkiG92NkBgIBBAIFADANBgkqhkiG9w0BAQUFAAOCAQEA2jIAlsVUlNM7
gjdmfS5o1cPGuMsmjEiQzxMkakaOY9Tw0BMG3djEwTcV8jMTOSYtzi5VQOMLA6/6
EsLnDSG41YDPrCgvzi2zTq+GGQTG6VDdTClHECP8bLsbmGtIieFbnd5G2zWFNe8+
0OJYSzj07XVaH1xwHVY5EuXhDRHkiSUGvdW0FY5e0FmXkOlLgeLfGK9EdB4ZoDpH
zJEdOusjWv6lLZf3e7vWh0ZChetSPSayY6i0scqP9Mzis8hH4L+aWYP62phTKoL1
fGUuldkzXfXtZcwxN8VaBOhr4eeIA0p1npsoy0pAiGVDdd3LOiUjxZ5X+C7O0qmS
XnMuLyV1FQ==
-----END CERTIFICATE-----
certificate_authority-1.1.0/spec/samples/certs/ca.crt 0000664 0000000 0000000 00000017177 14257354536 0022751 0 ustar 00root root 0000000 0000000 Certificate:
Data:
Version: 3 (0x2)
Serial Number:
e7:13:70:5d:01:cc:39:d2
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=AU, ST=Some-State, L=locality, O=Internet Widgits Pty Ltd, OU=section, CN=example ca/emailAddress=emailaddr@foo.com
Validity
Not Before: Sep 14 18:42:25 2012 GMT
Not After : Sep 14 18:42:25 2013 GMT
Subject: C=AU, ST=Some-State, L=locality, O=Internet Widgits Pty Ltd, OU=section, CN=example ca/emailAddress=emailaddr@foo.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (4096 bit)
Modulus (4096 bit):
00:c0:b4:be:5d:80:c2:19:5f:5c:f4:64:72:2f:3c:
0f:d1:6f:f2:69:74:de:ee:86:d2:a9:4e:02:85:d1:
e2:b0:84:c8:73:1f:e0:0d:a9:9f:60:e0:53:7f:b3:
4e:ed:42:63:3d:19:09:bc:67:a0:13:32:dc:a0:25:
ac:09:e1:7e:ae:72:73:4f:a1:9c:76:8c:80:35:e2:
75:2e:b2:4a:68:5f:03:83:bc:2e:63:1f:4a:7b:29:
80:2c:3e:fe:72:7f:43:ee:7b:59:6f:fc:51:8b:42:
0a:1b:b9:bb:5f:14:cd:9e:16:36:dd:05:ef:2c:21:
3e:de:39:bc:27:b1:0c:06:6a:49:f8:01:ff:3a:cc:
2c:5a:d9:56:0f:81:bc:6b:88:ee:83:72:d9:14:0c:
34:08:98:aa:1d:35:c2:34:fd:0c:3b:5d:5a:72:c1:
9b:28:ac:04:e1:30:3b:b8:ea:04:a2:48:34:a2:87:
3b:1c:b8:fc:89:f6:91:35:42:e9:6e:c7:af:ab:3b:
f6:b7:0a:2e:e3:7f:31:45:1d:04:a5:a4:5a:f6:cd:
bb:62:f9:49:e0:83:b3:77:df:ee:ba:84:bf:07:fa:
29:72:6d:2d:b8:e0:42:10:bd:f9:f3:e4:c6:7e:8a:
e8:d7:11:b8:67:14:b4:8c:f5:c4:a9:fa:d9:04:bd:
17:7f:b4:d0:a3:b9:c7:df:44:2d:50:dd:ba:7c:01:
11:02:23:d9:9c:4c:9a:f0:92:2f:4a:b7:0a:72:3f:
fc:61:6d:08:3b:cc:99:3c:65:78:92:76:63:a3:c4:
cb:1f:b8:ca:4a:7a:b0:c4:22:b2:9a:13:b6:ae:19:
60:7a:bd:37:1b:93:0e:02:9f:22:e4:dc:21:24:11:
4d:9d:9e:30:7f:7b:92:48:2d:4d:b9:1a:2a:58:c6:
77:4b:70:cf:c1:a6:6d:06:f9:54:83:bf:27:73:8f:
cc:8b:5c:7a:d2:79:56:75:41:d4:77:5f:9c:39:30:
02:0c:c5:0b:0c:32:6b:23:39:68:26:d5:f7:ef:b1:
7f:1e:c6:1d:a9:39:64:15:dd:b0:df:f5:d6:cf:c0:
73:b2:d0:f2:2a:f4:6e:9e:d8:9c:5b:9f:bf:ce:e7:
69:80:bf:69:d2:20:3b:aa:55:49:3e:fa:50:fc:63:
7e:8d:90:46:9a:7d:eb:9c:ca:17:bc:36:d7:88:e0:
d9:c4:29:8c:2f:bc:ce:9d:e5:35:d5:ec:d7:a6:93:
49:2a:84:3b:b6:37:1e:0c:57:f1:04:bb:2f:ea:75:
75:6a:de:0c:71:42:e6:e9:14:5e:ee:55:1a:1f:a4:
87:21:2b:12:98:8b:17:63:c8:84:88:43:46:f4:8f:
b2:b7:5b
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
28:88:9A:FA:67:E6:16:C3:67:92:46:15:0B:46:12:08:54:45:AC:3A
X509v3 Authority Key Identifier:
keyid:28:88:9A:FA:67:E6:16:C3:67:92:46:15:0B:46:12:08:54:45:AC:3A
DirName:/C=AU/ST=Some-State/L=locality/O=Internet Widgits Pty Ltd/OU=section/CN=example ca/emailAddress=emailaddr@foo.com
serial:E7:13:70:5D:01:CC:39:D2
X509v3 Basic Constraints:
CA:TRUE
Signature Algorithm: sha1WithRSAEncryption
81:b5:c6:b6:4a:10:f5:8a:98:30:96:07:46:8e:bb:6b:b3:c1:
2e:fa:f3:59:ca:e1:c6:85:70:b6:bc:fe:9f:77:0a:70:1a:56:
fb:46:71:d6:ee:90:cf:f5:a6:1d:4c:3c:24:76:32:fe:ec:55:
d6:c4:cd:3a:ee:dd:2d:97:b6:3b:d3:3b:3f:02:21:1c:ba:03:
48:b8:8d:03:a7:b8:70:81:b6:43:82:82:5f:34:eb:b1:a7:01:
cf:e4:f8:f7:d0:d8:5a:b6:c4:a6:0b:4e:e2:cc:4d:be:d4:99:
f4:37:54:6f:a7:7d:63:7c:7f:25:34:bb:e0:f4:e2:cf:31:c3:
99:4e:9e:a0:d1:f0:3b:15:8e:95:2e:76:a7:14:f0:3b:0c:e7:
42:8d:12:53:f9:24:d7:f9:90:93:71:56:9a:5f:35:8e:f3:29:
1e:d8:d2:71:fe:d8:d0:eb:d9:61:d5:3e:dd:d8:8f:6a:10:0d:
7c:f8:2a:1d:ef:24:d0:c1:13:d7:d6:9e:f7:cc:20:62:ea:78:
71:d1:7a:5f:2e:20:0d:64:38:07:1b:c9:a0:0f:3c:c9:4e:3f:
b1:84:8c:ae:86:ea:60:c7:84:2f:b6:d6:93:95:8d:36:9f:d2:
6a:bf:5e:98:1f:f9:da:fd:97:f3:e0:a7:0b:a7:52:30:e5:10:
89:c1:2c:85:75:07:a4:c7:d4:dc:b5:96:2a:c3:d5:eb:3b:7c:
fb:a0:55:4c:c1:65:6c:f8:29:74:8b:78:54:7d:a0:d0:9c:32:
8a:87:48:90:ad:5c:41:fe:ab:16:5a:ad:44:06:1b:c6:4d:e4:
01:f0:d8:c7:b1:db:bf:ca:fd:31:75:0a:01:70:00:45:e1:2d:
98:42:d5:36:53:2c:f1:57:93:7d:cd:e6:24:f3:4d:c9:31:ce:
a6:59:fe:2c:4a:61:56:9d:ad:55:7b:43:c5:48:ee:95:1e:b4:
0b:8d:4d:53:c7:a9:af:03:01:12:99:06:e8:fe:3a:63:8d:53:
30:8e:5a:95:64:d4:28:04:d8:bf:72:30:a1:fb:10:a7:84:15:
1b:13:a0:82:f3:38:5b:95:57:79:16:24:49:1a:1c:c5:43:90:
04:dd:5f:7b:d6:67:36:e1:41:fe:9d:20:a4:08:9c:14:9d:e3:
30:5c:1f:8e:46:f7:89:6b:f3:04:b9:75:b6:b6:33:49:54:99:
8e:9d:b0:f5:2b:51:61:3a:48:fc:f5:73:32:cd:a2:f6:9d:2a:
52:92:66:ae:a9:1f:06:b0:4d:63:29:83:e8:80:61:af:99:76:
bc:fd:97:d4:98:0b:49:d5:94:24:b1:34:85:31:0a:4e:6c:c3:
0d:de:be:85:1d:49:41:6c
-----BEGIN CERTIFICATE-----
MIIG0zCCBLugAwIBAgIJAOcTcF0BzDnSMA0GCSqGSIb3DQEBBQUAMIGhMQswCQYD
VQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTERMA8GA1UEBxMIbG9jYWxpdHkx
ITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEQMA4GA1UECxMHc2Vj
dGlvbjETMBEGA1UEAxMKZXhhbXBsZSBjYTEgMB4GCSqGSIb3DQEJARYRZW1haWxh
ZGRyQGZvby5jb20wHhcNMTIwOTE0MTg0MjI1WhcNMTMwOTE0MTg0MjI1WjCBoTEL
MAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxETAPBgNVBAcTCGxvY2Fs
aXR5MSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEDAOBgNVBAsT
B3NlY3Rpb24xEzARBgNVBAMTCmV4YW1wbGUgY2ExIDAeBgkqhkiG9w0BCQEWEWVt
YWlsYWRkckBmb28uY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA
wLS+XYDCGV9c9GRyLzwP0W/yaXTe7obSqU4ChdHisITIcx/gDamfYOBTf7NO7UJj
PRkJvGegEzLcoCWsCeF+rnJzT6GcdoyANeJ1LrJKaF8Dg7wuYx9KeymALD7+cn9D
7ntZb/xRi0IKG7m7XxTNnhY23QXvLCE+3jm8J7EMBmpJ+AH/OswsWtlWD4G8a4ju
g3LZFAw0CJiqHTXCNP0MO11acsGbKKwE4TA7uOoEokg0ooc7HLj8ifaRNULpbsev
qzv2twou438xRR0EpaRa9s27YvlJ4IOzd9/uuoS/B/opcm0tuOBCEL358+TGforo
1xG4ZxS0jPXEqfrZBL0Xf7TQo7nH30QtUN26fAERAiPZnEya8JIvSrcKcj/8YW0I
O8yZPGV4knZjo8TLH7jKSnqwxCKymhO2rhlger03G5MOAp8i5NwhJBFNnZ4wf3uS
SC1NuRoqWMZ3S3DPwaZtBvlUg78nc4/Mi1x60nlWdUHUd1+cOTACDMULDDJrIzlo
JtX377F/HsYdqTlkFd2w3/XWz8BzstDyKvRunticW5+/zudpgL9p0iA7qlVJPvpQ
/GN+jZBGmn3rnMoXvDbXiODZxCmML7zOneU11ezXppNJKoQ7tjceDFfxBLsv6nV1
at4McULm6RRe7lUaH6SHISsSmIsXY8iEiENG9I+yt1sCAwEAAaOCAQowggEGMB0G
A1UdDgQWBBQoiJr6Z+YWw2eSRhULRhIIVEWsOjCB1gYDVR0jBIHOMIHLgBQoiJr6
Z+YWw2eSRhULRhIIVEWsOqGBp6SBpDCBoTELMAkGA1UEBhMCQVUxEzARBgNVBAgT
ClNvbWUtU3RhdGUxETAPBgNVBAcTCGxvY2FsaXR5MSEwHwYDVQQKExhJbnRlcm5l
dCBXaWRnaXRzIFB0eSBMdGQxEDAOBgNVBAsTB3NlY3Rpb24xEzARBgNVBAMTCmV4
YW1wbGUgY2ExIDAeBgkqhkiG9w0BCQEWEWVtYWlsYWRkckBmb28uY29tggkA5xNw
XQHMOdIwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAgEAgbXGtkoQ9YqY
MJYHRo67a7PBLvrzWcrhxoVwtrz+n3cKcBpW+0Zx1u6Qz/WmHUw8JHYy/uxV1sTN
Ou7dLZe2O9M7PwIhHLoDSLiNA6e4cIG2Q4KCXzTrsacBz+T499DYWrbEpgtO4sxN
vtSZ9DdUb6d9Y3x/JTS74PTizzHDmU6eoNHwOxWOlS52pxTwOwznQo0SU/kk1/mQ
k3FWml81jvMpHtjScf7Y0OvZYdU+3diPahANfPgqHe8k0MET19ae98wgYup4cdF6
Xy4gDWQ4BxvJoA88yU4/sYSMrobqYMeEL7bWk5WNNp/Sar9emB/52v2X8+CnC6dS
MOUQicEshXUHpMfU3LWWKsPV6zt8+6BVTMFlbPgpdIt4VH2g0JwyiodIkK1cQf6r
FlqtRAYbxk3kAfDYx7Hbv8r9MXUKAXAAReEtmELVNlMs8VeTfc3mJPNNyTHOpln+
LEphVp2tVXtDxUjulR60C41NU8eprwMBEpkG6P46Y41TMI5alWTUKATYv3IwofsQ
p4QVGxOggvM4W5VXeRYkSRocxUOQBN1fe9ZnNuFB/p0gpAicFJ3jMFwfjkb3iWvz
BLl1trYzSVSZjp2w9StRYTpI/PVzMs2i9p0qUpJmrqkfBrBNYymD6IBhr5l2vP2X
1JgLSdWUJLE0hTEKTmzDDd6+hR1JQWw=
-----END CERTIFICATE-----
certificate_authority-1.1.0/spec/samples/certs/ca.key 0000664 0000000 0000000 00000006253 14257354536 0022742 0 ustar 00root root 0000000 0000000 -----BEGIN RSA PRIVATE KEY-----
MIIJKQIBAAKCAgEAwLS+XYDCGV9c9GRyLzwP0W/yaXTe7obSqU4ChdHisITIcx/g
DamfYOBTf7NO7UJjPRkJvGegEzLcoCWsCeF+rnJzT6GcdoyANeJ1LrJKaF8Dg7wu
Yx9KeymALD7+cn9D7ntZb/xRi0IKG7m7XxTNnhY23QXvLCE+3jm8J7EMBmpJ+AH/
OswsWtlWD4G8a4jug3LZFAw0CJiqHTXCNP0MO11acsGbKKwE4TA7uOoEokg0ooc7
HLj8ifaRNULpbsevqzv2twou438xRR0EpaRa9s27YvlJ4IOzd9/uuoS/B/opcm0t
uOBCEL358+TGforo1xG4ZxS0jPXEqfrZBL0Xf7TQo7nH30QtUN26fAERAiPZnEya
8JIvSrcKcj/8YW0IO8yZPGV4knZjo8TLH7jKSnqwxCKymhO2rhlger03G5MOAp8i
5NwhJBFNnZ4wf3uSSC1NuRoqWMZ3S3DPwaZtBvlUg78nc4/Mi1x60nlWdUHUd1+c
OTACDMULDDJrIzloJtX377F/HsYdqTlkFd2w3/XWz8BzstDyKvRunticW5+/zudp
gL9p0iA7qlVJPvpQ/GN+jZBGmn3rnMoXvDbXiODZxCmML7zOneU11ezXppNJKoQ7
tjceDFfxBLsv6nV1at4McULm6RRe7lUaH6SHISsSmIsXY8iEiENG9I+yt1sCAwEA
AQKCAgAo+AQkwtQBKuoLNzOjYSSHxUIHM4aVtWoh/mjA5H9KQeCPwS4UGYS9xtNZ
qdhUzrFkcudD+8/nZP/MuFWcACm7kq97NYObHIHBcvSwyczR5alMn3xJLITcLFWI
kpfr5ayejfDUwxLfBVo6zMDOFREl09k0IifX/PVtr16WHajN0FkLdfk6GeAwLFaE
k3NodUMoBQmrnnCNh09bSGuScl3gXRd2oDyJaBDdgzCfPnlfuvQdvZxOnfFqr1Xt
ud0A5UkuoV/xSCPxz7+8zs+HG6sPH2wAPbl8FuPXz27kjoZCfufC4P1AecTx5EG4
nWGp04Ru/OB0Yc2EzldSP/dVb5IIAEeIzeqOC1dKh+m5BL6+KCMW4RA2VRmtVcSO
Xu8/uLNw3coWj8OdUg4JJLWIuY17puKyhmMuZqXSwF5qcSCD2kGMtgdIFevHGLDy
NCXIxAhnp/mWGJJvkRPxe7NVZSKGh7nfGGFbr2GAsTX5XZetk6ye/A+oNrUM4UP+
WQNtD5m2R1IPIp7f8NdTiSpAsKrgzDVEKSdXW/DObRm64DdRINuxGkrjDTOR6B+M
HmcKQdMZPVyzWeFHF+JyR4+GVx2OZ/5lzEPTHO8thiA1nn1ov/RYZwuwrl8EKDt6
jgU26C+1TD3lL9smBdekOB8EtQT2EcuE7hwS6ca4Sryj5RYCmQKCAQEA/DTBSczZ
HtPcHs75IiHfUXGoJB943LIR4cqrWKO2xy16MpamNQy8yBzet7pgXmrxixtar13B
SpPozQNwlKD43rLSG77soY9eZcn2SQCOlcuekdRczR2jp4cnIo3bTXOm5OTz55EK
WTLGkTirlcGCPFHv866qrmVQF+cIo3qtszrwuJGkOWTfU8X9zSN+AU+KwAqam5C5
ZbkcXFNwI2FOud5nQsOrjJ9Aivrw1CbHvHqAiZzZXjZmMNurH/cLX9jregxoiTAv
wXsS1Apvvq0kvWJ9QrRBNyRsZ6qEt0ABgf2tl6+4t+S9bCmS2L6RzqjrxbkVPoM2
ChHX+8XkwuVUHwKCAQEAw5rao4MU4itSeaWLrny5oo57pICyY3zF5c5HySpaWyA8
JksxYCvNDR1aFZjCdOG9zOf5vLieniyTK+Tl3FF5P6OxSJOcQ9UOXaoTKny1Kw9W
BMTbR0COLXsJSNvjNyZSyoLgOOLTZj11S+X/W1vb+Xi0kkx4SS6Tg3i5N+0Fl2Wa
Mgucy/pgq+JBTlgKZ1Rjpna1T5ibUn0pT6fxgZ2U+FAD0cYNyaCjVmzMbiIkLUId
jJEDGYXenyoIFI0rrJvF/0nl98BZjsT9+GNs0ZlejS0rfn2+DWlrLur3aqG2i3Yr
L9nWZ51bSB7UhHALN2t2qd9etKWmz4YbuFHPvHOVRQKCAQEAgmdMoboXcYcdw5hE
3M8ixtu7kqHrPkGcWWEPY4+SzD3JdyrJ2ZgybE3xIpJtjaRCLCkCpLYXYVZFAuwK
Y+8vfwZ6+PmpJIgayQq6G1j8YJud680gBraSjeal54ntoIhx/Nwc+NjXvvMwFJp2
rcIWctXy+c6QVgfwd8tvfgfKlGefW++COGLdzlULO+xkFI1qMo3JDzKviddCwMIr
sz93E0fZoH3Hz7fwCWxi5W7/y4aTu5OsGLiL8itCug5khTSF3N9ZlcWii6n1PEoB
KVghLQMlvT2ykq50ls1mPdIMdYgTH+Et43eUMb71PLicb3yMG/ns8Bur71z2jinu
dI9bBQKCAQBk30XjTuUFIbw9mX6oNA/zYbEni2rzXVQdB70DY8EG/1+li99hrhTn
r3xWaNnXNtcPhY3HohnCjlAzMa7MaIOzqvHw8JaEcKog6WVK4tb25sjAWtiOLR9l
Gu8V0LejKDNH1ihVjbvhHM6RnoGKlpuhUnskeyUI8GkIQsiZq7TXd4EGT/DDTFJw
MZTmFwb+dImTPeKQsq1e48bbGku0QRSi3XiqxI01ro6tMhxWq2qmoFLmu52ymtPM
lvtlxcuBDzATUAO1OU+2Daa/Yl6q1IHrIiEs8SGCfxvULT38knq1/vGUkq077+00
CxojVjiiktu2DMglNswIdytyaVZM4/pVAoIBAQDmXzA7dptH9tOrp5/pYO4C8Fk0
4NB7OgKrhtE8YQtfghQn1O0FjvNT/o1+Gf9mf40Np7OtVulhZ56fQupmkk56TAJu
P1YDVDRPLOvMkYeIsqqv6HnXGQaS6Bv91wrqwWPjLDD3pH+AdjP27SnObzARjRUq
/s5LmI+u87rCldkGLG4qO4sjptWRlU8pIsLWQ3NckXINT7i8wwXzEfOcu7IzKWg6
sdzMWxc7Vt/4WE5m+9DLkpk3sD9dqELHry5lGWbpLHhfoVXoRdoFNVmyi2ckdr0J
FJ6hkWkgQ4ee+yHyL3FfYRbGIolqaVSCd8/CvvDZ/24eS3/7TpCzf8SUqtL6
-----END RSA PRIVATE KEY-----
certificate_authority-1.1.0/spec/samples/certs/client.crt 0000664 0000000 0000000 00000010643 14257354536 0023633 0 ustar 00root root 0000000 0000000 Certificate:
Data:
Version: 1 (0x0)
Serial Number: 2 (0x2)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=AU, ST=Some-State, L=locality, O=Internet Widgits Pty Ltd, OU=section, CN=example ca/emailAddress=emailaddr@foo.com
Validity
Not Before: Sep 14 18:43:15 2012 GMT
Not After : Sep 14 18:43:15 2013 GMT
Subject: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=client.example.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:dd:81:af:cb:67:4f:9d:2b:37:9f:bb:52:6a:17:
f3:25:ba:ca:6d:23:45:94:dc:08:9b:cd:82:56:79:
da:0b:47:c9:d0:3f:a8:16:bb:56:77:3a:85:a9:ab:
20:f3:1e:2d:5c:fa:b2:23:90:86:81:bf:a9:f6:10:
85:55:3f:c6:aa:7e:fa:43:96:08:c0:fa:e8:2f:cb:
e5:2d:01:d1:12:22:a2:3f:7a:c5:75:4e:6f:47:d3:
2e:7a:fe:17:6e:4f:a3:20:60:5b:46:57:51:69:ce:
8f:33:87:05:df:1e:cb:fb:32:43:2a:71:6c:44:d1:
a6:2d:98:41:e4:88:36:9a:f1
Exponent: 65537 (0x10001)
Signature Algorithm: sha1WithRSAEncryption
9e:7f:e1:05:a7:9a:86:6c:0d:6e:37:76:ae:2e:5b:78:e5:22:
6f:52:40:36:e8:7e:cf:20:77:4f:3b:b4:7b:7c:72:46:68:df:
fe:04:87:16:9f:cd:6e:0f:79:01:25:cf:ca:5e:b8:47:31:9e:
f1:20:44:26:78:79:40:00:57:cc:a6:a8:39:67:ef:01:d7:65:
1c:dd:5d:8f:6e:48:43:f4:03:48:46:8f:08:95:cf:27:3f:30:
da:82:a7:33:82:5f:82:cb:e6:2c:f0:25:e8:87:3b:e5:bf:82:
79:72:a9:10:45:69:3c:7f:f0:dd:c9:50:6e:02:c9:05:16:cf:
c3:58:15:3f:a6:32:ec:80:4f:88:b4:72:d2:5f:70:62:24:98:
e5:99:c8:a7:d9:dd:0c:b0:cb:9c:70:d1:6a:44:21:d9:d7:65:
a6:71:6f:60:64:7e:28:de:5d:98:42:6d:aa:fc:32:f9:1c:d6:
5c:d7:b6:15:18:79:09:80:7e:d7:9e:74:16:a5:80:39:6d:93:
8e:8e:4e:c5:8c:f5:4c:ea:d3:fd:12:bc:fa:fc:b8:e2:2c:30:
52:f4:eb:ad:d9:56:e9:84:e9:a8:df:a3:16:fa:d2:1e:74:49:
5d:d1:24:10:f2:2e:c4:b9:4a:a9:2d:3d:a4:70:6d:24:00:26:
46:bf:e2:98:16:4d:c8:55:40:a7:ab:76:b3:c6:a7:72:46:2d:
9b:fd:a2:ca:b8:62:9c:59:53:cc:64:ef:60:76:10:c8:c9:e7:
51:11:82:d4:81:04:73:e9:af:df:2d:c4:c7:2d:e4:17:d4:e2:
10:82:68:56:ae:7a:f2:3c:60:b7:59:29:39:6a:56:86:94:fc:
93:2b:5b:f0:ac:80:1d:c7:c5:b7:27:36:94:1c:ad:e9:1c:6b:
f3:8a:2a:6c:c8:ce:69:52:b2:42:d9:b9:e7:8e:a3:d4:18:07:
a1:db:bf:54:3c:ec:2e:68:7f:cf:d6:71:8f:3e:99:88:e4:ea:
7f:98:22:3a:31:68:24:a5:47:23:e2:d6:21:8f:1f:5f:a7:9a:
12:10:ba:6d:ac:22:e7:97:95:93:a2:b5:1c:f8:c8:86:1a:ad:
32:ff:64:4f:25:8d:d5:25:29:46:85:30:bc:c4:86:41:1b:6b:
24:7e:04:b6:eb:46:39:55:9c:4d:84:86:2f:bf:11:26:a9:40:
3d:2d:f4:90:22:05:7f:27:3b:13:d1:86:17:70:05:e1:68:be:
12:ce:c5:30:7b:0a:1b:7b:8a:89:e6:e7:9a:9c:b0:8b:c1:f8:
c3:b6:0a:4c:41:da:fe:cd:ea:ce:89:3b:a5:8d:30:90:93:93:
9b:85:b6:61:46:8d:69:f2
-----BEGIN CERTIFICATE-----
MIID9DCCAdwCAQIwDQYJKoZIhvcNAQEFBQAwgaExCzAJBgNVBAYTAkFVMRMwEQYD
VQQIEwpTb21lLVN0YXRlMREwDwYDVQQHEwhsb2NhbGl0eTEhMB8GA1UEChMYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRAwDgYDVQQLEwdzZWN0aW9uMRMwEQYDVQQD
EwpleGFtcGxlIGNhMSAwHgYJKoZIhvcNAQkBFhFlbWFpbGFkZHJAZm9vLmNvbTAe
Fw0xMjA5MTQxODQzMTVaFw0xMzA5MTQxODQzMTVaMGIxCzAJBgNVBAYTAkFVMRMw
EQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0
eSBMdGQxGzAZBgNVBAMTEmNsaWVudC5leGFtcGxlLmNvbTCBnzANBgkqhkiG9w0B
AQEFAAOBjQAwgYkCgYEA3YGvy2dPnSs3n7tSahfzJbrKbSNFlNwIm82CVnnaC0fJ
0D+oFrtWdzqFqasg8x4tXPqyI5CGgb+p9hCFVT/Gqn76Q5YIwProL8vlLQHREiKi
P3rFdU5vR9Muev4Xbk+jIGBbRldRac6PM4cF3x7L+zJDKnFsRNGmLZhB5Ig2mvEC
AwEAATANBgkqhkiG9w0BAQUFAAOCAgEAnn/hBaeahmwNbjd2ri5beOUib1JANuh+
zyB3Tzu0e3xyRmjf/gSHFp/Nbg95ASXPyl64RzGe8SBEJnh5QABXzKaoOWfvAddl
HN1dj25IQ/QDSEaPCJXPJz8w2oKnM4JfgsvmLPAl6Ic75b+CeXKpEEVpPH/w3clQ
bgLJBRbPw1gVP6Yy7IBPiLRy0l9wYiSY5ZnIp9ndDLDLnHDRakQh2ddlpnFvYGR+
KN5dmEJtqvwy+RzWXNe2FRh5CYB+1550FqWAOW2Tjo5OxYz1TOrT/RK8+vy44iww
UvTrrdlW6YTpqN+jFvrSHnRJXdEkEPIuxLlKqS09pHBtJAAmRr/imBZNyFVAp6t2
s8anckYtm/2iyrhinFlTzGTvYHYQyMnnURGC1IEEc+mv3y3Exy3kF9TiEIJoVq56
8jxgt1kpOWpWhpT8kytb8KyAHcfFtyc2lByt6Rxr84oqbMjOaVKyQtm5546j1BgH
odu/VDzsLmh/z9Zxjz6ZiOTqf5giOjFoJKVHI+LWIY8fX6eaEhC6bawi55eVk6K1
HPjIhhqtMv9kTyWN1SUpRoUwvMSGQRtrJH4EtutGOVWcTYSGL78RJqlAPS30kCIF
fyc7E9GGF3AF4Wi+Es7FMHsKG3uKiebnmpywi8H4w7YKTEHa/s3qzok7pY0wkJOT
m4W2YUaNafI=
-----END CERTIFICATE-----
certificate_authority-1.1.0/spec/samples/certs/client.csr 0000664 0000000 0000000 00000001203 14257354536 0023622 0 ustar 00root root 0000000 0000000 -----BEGIN CERTIFICATE REQUEST-----
MIIBojCCAQsCAQAwYjELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUx
ITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEbMBkGA1UEAxMSY2xp
ZW50LmV4YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdga/L
Z0+dKzefu1JqF/MlusptI0WU3AibzYJWedoLR8nQP6gWu1Z3OoWpqyDzHi1c+rIj
kIaBv6n2EIVVP8aqfvpDlgjA+ugvy+UtAdESIqI/esV1Tm9H0y56/hduT6MgYFtG
V1Fpzo8zhwXfHsv7MkMqcWxE0aYtmEHkiDaa8QIDAQABoAAwDQYJKoZIhvcNAQEF
BQADgYEARSbIBSvvhvqX7zMBap+RcQfMdXbSQTI3iNVSEOoUtfuGEJOmkHrWwsz0
ZfKv/qC9LBeWD+yqDeKbuRNJEla2oIInUfs3FINYLsm3jufsuBpVPY1OOglq91VD
v1zBodLbTvbHIHKStsMfNaS9lKYZ/PycWNXxhQhpZZAeGBqk3mY=
-----END CERTIFICATE REQUEST-----
certificate_authority-1.1.0/spec/samples/certs/client.key 0000664 0000000 0000000 00000001573 14257354536 0023635 0 ustar 00root root 0000000 0000000 -----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQDdga/LZ0+dKzefu1JqF/MlusptI0WU3AibzYJWedoLR8nQP6gW
u1Z3OoWpqyDzHi1c+rIjkIaBv6n2EIVVP8aqfvpDlgjA+ugvy+UtAdESIqI/esV1
Tm9H0y56/hduT6MgYFtGV1Fpzo8zhwXfHsv7MkMqcWxE0aYtmEHkiDaa8QIDAQAB
AoGBAIdkD4mqWhVdJyCxJMzIWsyDAdv3pT45x+FDmhk1XbtrY8WwQxOx6kXyNWTh
vsAbf+rHKT9nxW9lMYO/0V+sHcdRtG0NEXPfB8pX7LEsaHpRPHkVoiWpRlCL/maM
ci85RPsATlDkiOn1luysfk2PHy5aSKG0RkLS7lSkahTQOn9JAkEA8goUnDdh5hVm
7o2npeZG66Zb2mnm1l8aO9LJ76u6L/jmTx5aSRXP0aBiDb1PXJZedqhd/MdPcYEI
QsFCIoT/iwJBAOpIbAK15eWsubUme/UoCbfNpM4H3jQXbSODgJ83nwmqr2slrX9m
soz/+2nZl6/TL344xxTmDChFGivHdh7JXvMCQBoHi3/hVN3xn0g4Y7crtKTTFz29
9d1IDQIyARWNWlCea+ZGVV9WwSrCHMlteoNyiGYqZTEyHhEO11yWfA5KT1ECQQCY
bFHJWaqeyMdxsf4Hu+rGqIZGfRv17B/XcSDndXqFAYVrQnIkZx5XWduqPCTSAaXu
iuYLFLhoIr0qKnURBpY9AkEAy9JOf5tqc1jFndLIgVtXzM5KptIFHr1ZA7VSfrdY
ozt9adbCTXfNTTLqAK0N7A2F7T3APEbpPuR2a7TpzawRWA==
-----END RSA PRIVATE KEY-----
certificate_authority-1.1.0/spec/samples/certs/github.com.pem 0000664 0000000 0000000 00000015132 14257354536 0024403 0 ustar 00root root 0000000 0000000 Certificate:
Data:
Version: 3 (0x2)
Serial Number:
0e:77:76:8a:5d:07:f0:e5:79:59:ca:2a:9d:50:82:b5
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV CA-1
Validity
Not Before: May 27 00:00:00 2011 GMT
Not After : Jul 29 12:00:00 2013 GMT
Subject: businessCategory=Private Organization/1.3.6.1.4.1.311.60.2.1.3=US/1.3.6.1.4.1.311.60.2.1.2=California/serialNumber=C3268102, C=US, ST=California, L=San Francisco, O=GitHub, Inc., CN=github.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (2048 bit)
Modulus (2048 bit):
00:ed:d3:89:c3:5d:70:72:09:f3:33:4f:1a:72:74:
d9:b6:5a:95:50:bb:68:61:9f:f7:fb:1f:19:e1:da:
04:31:af:15:7c:1a:7f:f9:73:af:1d:e5:43:2b:56:
09:00:45:69:4a:e8:c4:5b:df:c2:77:52:51:19:5b:
d1:2b:d9:39:65:36:a0:32:19:1c:41:73:fb:32:b2:
3d:9f:98:ec:82:5b:0b:37:64:39:2c:b7:10:83:72:
cd:f0:ea:24:4b:fa:d9:94:2e:c3:85:15:39:a9:3a:
f6:88:da:f4:27:89:a6:95:4f:84:a2:37:4e:7c:25:
78:3a:c9:83:6d:02:17:95:78:7d:47:a8:55:83:ee:
13:c8:19:1a:b3:3c:f1:5f:fe:3b:02:e1:85:fb:11:
66:ab:09:5d:9f:4c:43:f0:c7:24:5e:29:72:28:ce:
d4:75:68:4f:24:72:29:ae:39:28:fc:df:8d:4f:4d:
83:73:74:0c:6f:11:9b:a7:dd:62:de:ff:e2:eb:17:
e6:ff:0c:bf:c0:2d:31:3b:d6:59:a2:f2:dd:87:4a:
48:7b:6d:33:11:14:4d:34:9f:32:38:f6:c8:19:9d:
f1:b6:3d:c5:46:ef:51:0b:8a:c6:33:ed:48:61:c4:
1d:17:1b:bd:7c:b6:67:e9:39:cf:a5:52:80:0a:f4:
ea:cd
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Authority Key Identifier:
keyid:4C:58:CB:25:F0:41:4F:52:F4:28:C8:81:43:9B:A6:A8:A0:E6:92:E5
X509v3 Subject Key Identifier:
87:D1:8F:19:6E:E4:87:6F:53:8C:77:91:07:50:DF:A3:BF:55:47:20
X509v3 Subject Alternative Name:
DNS:github.com, DNS:www.github.com
Authority Information Access:
OCSP - URI:http://ocsp.digicert.com
CA Issuers - URI:http://www.digicert.com/CACerts/DigiCertHighAssuranceEVCA-1.crt
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 CRL Distribution Points:
URI:http://crl3.digicert.com/ev2009a.crl
URI:http://crl4.digicert.com/ev2009a.crl
X509v3 Certificate Policies:
Policy: 2.16.840.1.114412.2.1
CPS: http://www.digicert.com/ssl-cps-repository.htm
User Notice:
Explicit Text:
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
Netscape Cert Type:
SSL Client, SSL Server
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
Signature Algorithm: sha1WithRSAEncryption
14:52:71:1f:86:9d:6d:35:3e:86:bb:66:1a:8b:85:98:b9:00:
4c:cb:42:b5:46:fc:06:e7:44:39:c8:e8:52:d8:11:14:23:b3:
72:96:e9:14:94:9e:2f:00:28:f7:d5:04:45:40:00:c6:f4:57:
42:42:de:09:89:97:11:0d:14:5c:6b:bd:0b:f7:18:a3:5f:67:
02:f3:09:38:63:bf:c1:12:9d:30:ba:8e:a5:54:74:59:53:67:
a1:1b:50:5b:26:da:fd:13:7e:59:17:bf:49:ef:94:7e:45:a4:
fd:3a:49:32:f0:6a:ff:89:8d:a9:61:a9:aa:9b:96:46:c8:1c:
e0:18:1c:e6:fb:82:f4:0a:ab:52:a6:ca:e8:54:22:d9:db:2a:
3d:5a:22:7b:80:ea:07:05:d4:f9:c7:f0:53:59:5f:bb:77:7e:
de:93:70:41:4e:23:cb:78:79:79:c4:2e:ea:d7:66:2a:18:f7:
d1:c5:7c:e2:12:78:82:8d:1d:ec:82:9e:01:a2:e5:02:be:78:
a1:b9:59:58:c5:4c:6f:4f:a5:31:b4:49:5b:5e:98:1e:2e:38:
f6:19:c4:39:a2:4a:fb:79:05:b8:f2:59:e5:26:12:70:ad:c0:
e8:75:23:1f:18:d1:0b:e0:9f:65:e4:c3:d7:49:87:5b:72:6c:
b1:2f:ac:6f
-----BEGIN CERTIFICATE-----
MIIHKjCCBhKgAwIBAgIQDnd2il0H8OV5WcoqnVCCtTANBgkqhkiG9w0BAQUFADBp
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSgwJgYDVQQDEx9EaWdpQ2VydCBIaWdoIEFzc3VyYW5j
ZSBFViBDQS0xMB4XDTExMDUyNzAwMDAwMFoXDTEzMDcyOTEyMDAwMFowgcoxHTAb
BgNVBA8MFFByaXZhdGUgT3JnYW5pemF0aW9uMRMwEQYLKwYBBAGCNzwCAQMTAlVT
MRswGQYLKwYBBAGCNzwCAQITCkNhbGlmb3JuaWExETAPBgNVBAUTCEMzMjY4MTAy
MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2Fu
IEZyYW5jaXNjbzEVMBMGA1UEChMMR2l0SHViLCBJbmMuMRMwEQYDVQQDEwpnaXRo
dWIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7dOJw11wcgnz
M08acnTZtlqVULtoYZ/3+x8Z4doEMa8VfBp/+XOvHeVDK1YJAEVpSujEW9/Cd1JR
GVvRK9k5ZTagMhkcQXP7MrI9n5jsglsLN2Q5LLcQg3LN8OokS/rZlC7DhRU5qTr2
iNr0J4mmlU+EojdOfCV4OsmDbQIXlXh9R6hVg+4TyBkaszzxX/47AuGF+xFmqwld
n0xD8MckXilyKM7UdWhPJHIprjko/N+NT02Dc3QMbxGbp91i3v/i6xfm/wy/wC0x
O9ZZovLdh0pIe20zERRNNJ8yOPbIGZ3xtj3FRu9RC4rGM+1IYcQdFxu9fLZn6TnP
pVKACvTqzQIDAQABo4IDajCCA2YwHwYDVR0jBBgwFoAUTFjLJfBBT1L0KMiBQ5um
qKDmkuUwHQYDVR0OBBYEFIfRjxlu5IdvU4x3kQdQ36O/VUcgMCUGA1UdEQQeMByC
CmdpdGh1Yi5jb22CDnd3dy5naXRodWIuY29tMIGBBggrBgEFBQcBAQR1MHMwJAYI
KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBLBggrBgEFBQcwAoY/
aHR0cDovL3d3dy5kaWdpY2VydC5jb20vQ0FDZXJ0cy9EaWdpQ2VydEhpZ2hBc3N1
cmFuY2VFVkNBLTEuY3J0MAwGA1UdEwEB/wQCMAAwYQYDVR0fBFowWDAqoCigJoYk
aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL2V2MjAwOWEuY3JsMCqgKKAmhiRodHRw
Oi8vY3JsNC5kaWdpY2VydC5jb20vZXYyMDA5YS5jcmwwggHEBgNVHSAEggG7MIIB
tzCCAbMGCWCGSAGG/WwCATCCAaQwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cuZGln
aWNlcnQuY29tL3NzbC1jcHMtcmVwb3NpdG9yeS5odG0wggFkBggrBgEFBQcCAjCC
AVYeggFSAEEAbgB5ACAAdQBzAGUAIABvAGYAIAB0AGgAaQBzACAAQwBlAHIAdABp
AGYAaQBjAGEAdABlACAAYwBvAG4AcwB0AGkAdAB1AHQAZQBzACAAYQBjAGMAZQBw
AHQAYQBuAGMAZQAgAG8AZgAgAHQAaABlACAARABpAGcAaQBDAGUAcgB0ACAAQwBQ
AC8AQwBQAFMAIABhAG4AZAAgAHQAaABlACAAUgBlAGwAeQBpAG4AZwAgAFAAYQBy
AHQAeQAgAEEAZwByAGUAZQBtAGUAbgB0ACAAdwBoAGkAYwBoACAAbABpAG0AaQB0
ACAAbABpAGEAYgBpAGwAaQB0AHkAIABhAG4AZAAgAGEAcgBlACAAaQBuAGMAbwBy
AHAAbwByAGEAdABlAGQAIABoAGUAcgBlAGkAbgAgAGIAeQAgAHIAZQBmAGUAcgBl
AG4AYwBlAC4wHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBEGCWCGSAGG
+EIBAQQEAwIGwDAOBgNVHQ8BAf8EBAMCBaAwDQYJKoZIhvcNAQEFBQADggEBABRS
cR+GnW01Poa7ZhqLhZi5AEzLQrVG/AbnRDnI6FLYERQjs3KW6RSUni8AKPfVBEVA
AMb0V0JC3gmJlxENFFxrvQv3GKNfZwLzCThjv8ESnTC6jqVUdFlTZ6EbUFsm2v0T
flkXv0nvlH5FpP06STLwav+JjalhqaqblkbIHOAYHOb7gvQKq1KmyuhUItnbKj1a
InuA6gcF1PnH8FNZX7t3ft6TcEFOI8t4eXnELurXZioY99HFfOISeIKNHeyCngGi
5QK+eKG5WVjFTG9PpTG0SVtemB4uOPYZxDmiSvt5BbjyWeUmEnCtwOh1Ix8Y0Qvg
n2Xkw9dJh1tybLEvrG8=
-----END CERTIFICATE-----
certificate_authority-1.1.0/spec/samples/certs/server.crt 0000664 0000000 0000000 00000011072 14257354536 0023660 0 ustar 00root root 0000000 0000000 Certificate:
Data:
Version: 1 (0x0)
Serial Number: 1 (0x1)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=AU, ST=Some-State, L=locality, O=Internet Widgits Pty Ltd, OU=section, CN=example ca/emailAddress=emailaddr@foo.com
Validity
Not Before: Sep 14 18:43:03 2012 GMT
Not After : Sep 14 18:43:03 2013 GMT
Subject: C=AU, ST=Some-State, L=locality, O=Internet Widgits Pty Ltd, OU=ouname, CN=server.example.com/emailAddress=email@example.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:c2:6b:ec:81:d7:3f:94:09:f0:a6:f1:78:65:79:
a7:28:26:5c:b7:96:86:5b:77:9a:be:67:7a:16:e0:
a2:c8:8d:9c:ec:5d:9a:56:0e:c7:f4:8b:11:01:df:
d2:94:80:ba:87:2b:cf:d4:33:4a:06:21:3b:c6:31:
b5:fc:b4:30:f6:fd:28:58:5f:18:11:46:08:fa:12:
75:82:c2:e9:e6:65:9a:e4:fe:8d:f0:36:63:91:06:
bb:43:f6:72:50:5c:8b:00:e3:53:2a:09:34:06:e6:
05:16:30:d0:f8:96:3b:b0:7d:b6:8d:ef:5f:b0:c1:
31:bc:77:d4:a9:93:31:d7:f1
Exponent: 65537 (0x10001)
Signature Algorithm: sha1WithRSAEncryption
aa:c7:e4:d5:c5:33:e8:75:43:01:23:9f:ae:91:c3:17:dc:54:
d5:34:65:e3:76:ec:00:e4:71:06:70:84:10:2d:ae:ea:21:90:
70:27:ec:86:15:97:e5:e4:10:62:19:08:b5:56:86:4f:84:ef:
43:c7:86:06:33:8a:61:bb:71:ac:f9:e1:d2:f0:08:83:32:bb:
73:a0:fd:39:66:8f:a3:d9:bb:59:bb:c2:cc:5e:8f:56:fc:72:
b2:42:da:d2:31:1b:98:be:0d:0c:8d:1a:8e:12:fe:7f:ef:5b:
cf:93:b7:e1:ba:c8:a0:c4:de:60:4f:74:ea:12:9d:3a:ea:81:
28:b3:ed:14:6e:22:00:23:56:b0:ef:d4:7e:6b:7d:4a:fb:7e:
3b:c2:a8:9e:84:42:43:ad:6d:b1:41:78:75:a6:32:46:5c:98:
c2:e5:3b:d0:dd:cc:17:35:7b:f9:54:25:ef:38:07:82:dc:a3:
32:69:bb:15:28:71:a9:c7:a3:8e:55:29:61:04:eb:ee:05:e9:
9f:4b:f6:c7:6e:9b:02:19:e9:0c:5e:66:a1:65:fe:ae:6e:25:
a4:a4:31:3c:40:0d:b9:f4:c2:44:40:23:65:85:58:33:5a:0d:
84:3d:24:71:43:0f:65:69:28:75:de:ae:b3:b7:82:a4:09:f1:
b7:21:8f:5d:76:66:4c:d7:08:19:80:68:a0:9f:33:df:46:a7:
ab:7f:45:4d:1f:d1:45:54:8f:53:b9:da:77:86:b3:e2:b2:7e:
72:a2:6e:ad:08:01:2a:05:79:d7:ba:a2:17:c7:82:72:58:7c:
4d:fb:b9:0e:09:54:24:1e:34:e0:ae:32:d7:0a:00:1b:23:e4:
95:1b:8e:28:6c:7b:31:55:ad:6b:bb:e0:76:d3:2e:d2:14:0c:
02:9a:b5:65:ce:54:c7:28:08:7b:85:3c:43:00:09:c3:90:4e:
b0:9c:57:f0:66:d2:18:95:ce:4e:18:f0:81:f1:16:a1:b0:ca:
a8:85:33:c4:8c:b5:06:9c:eb:e6:5b:b9:13:31:14:53:83:3c:
8f:0e:02:56:f9:b7:07:d5:a0:66:8a:8a:06:ee:c7:46:a2:e6:
b2:f5:ef:be:f5:ac:e0:a3:fa:9e:1d:03:b1:40:0f:b8:8c:bb:
ab:f0:13:55:db:05:65:eb:8a:f7:03:86:e0:a5:bb:f2:ae:ab:
f4:32:7b:2c:28:56:fb:7d:30:b3:c1:71:c7:52:3c:a9:ee:a0:
82:6f:b6:90:54:b7:5b:f2:74:11:4d:40:89:e4:cb:c3:50:b8:
f7:e6:98:bd:95:7e:1c:8f:b9:e8:9f:ef:d6:ca:3b:77:40:6a:
dc:1e:51:74:c0:32:53:61
-----BEGIN CERTIFICATE-----
MIIEOzCCAiMCAQEwDQYJKoZIhvcNAQEFBQAwgaExCzAJBgNVBAYTAkFVMRMwEQYD
VQQIEwpTb21lLVN0YXRlMREwDwYDVQQHEwhsb2NhbGl0eTEhMB8GA1UEChMYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRAwDgYDVQQLEwdzZWN0aW9uMRMwEQYDVQQD
EwpleGFtcGxlIGNhMSAwHgYJKoZIhvcNAQkBFhFlbWFpbGFkZHJAZm9vLmNvbTAe
Fw0xMjA5MTQxODQzMDNaFw0xMzA5MTQxODQzMDNaMIGoMQswCQYDVQQGEwJBVTET
MBEGA1UECBMKU29tZS1TdGF0ZTERMA8GA1UEBxMIbG9jYWxpdHkxITAfBgNVBAoT
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEPMA0GA1UECxMGb3VuYW1lMRswGQYD
VQQDExJzZXJ2ZXIuZXhhbXBsZS5jb20xIDAeBgkqhkiG9w0BCQEWEWVtYWlsQGV4
YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCa+yB1z+UCfCm
8XhleacoJly3loZbd5q+Z3oW4KLIjZzsXZpWDsf0ixEB39KUgLqHK8/UM0oGITvG
MbX8tDD2/ShYXxgRRgj6EnWCwunmZZrk/o3wNmORBrtD9nJQXIsA41MqCTQG5gUW
MND4ljuwfbaN71+wwTG8d9SpkzHX8QIDAQABMA0GCSqGSIb3DQEBBQUAA4ICAQCq
x+TVxTPodUMBI5+ukcMX3FTVNGXjduwA5HEGcIQQLa7qIZBwJ+yGFZfl5BBiGQi1
VoZPhO9Dx4YGM4phu3Gs+eHS8AiDMrtzoP05Zo+j2btZu8LMXo9W/HKyQtrSMRuY
vg0MjRqOEv5/71vPk7fhusigxN5gT3TqEp066oEos+0UbiIAI1aw79R+a31K+347
wqiehEJDrW2xQXh1pjJGXJjC5TvQ3cwXNXv5VCXvOAeC3KMyabsVKHGpx6OOVSlh
BOvuBemfS/bHbpsCGekMXmahZf6ubiWkpDE8QA259MJEQCNlhVgzWg2EPSRxQw9l
aSh13q6zt4KkCfG3IY9ddmZM1wgZgGignzPfRqerf0VNH9FFVI9Tudp3hrPisn5y
om6tCAEqBXnXuqIXx4JyWHxN+7kOCVQkHjTgrjLXCgAbI+SVG44obHsxVa1ru+B2
0y7SFAwCmrVlzlTHKAh7hTxDAAnDkE6wnFfwZtIYlc5OGPCB8RahsMqohTPEjLUG
nOvmW7kTMRRTgzyPDgJW+bcH1aBmiooG7sdGouay9e++9azgo/qeHQOxQA+4jLur
8BNV2wVl64r3A4bgpbvyrqv0MnssKFb7fTCzwXHHUjyp7qCCb7aQVLdb8nQRTUCJ
5MvDULj35pi9lX4cj7non+/Wyjt3QGrcHlF0wDJTYQ==
-----END CERTIFICATE-----
certificate_authority-1.1.0/spec/samples/certs/server.csr 0000664 0000000 0000000 00000001345 14257354536 0023661 0 ustar 00root root 0000000 0000000 -----BEGIN CERTIFICATE REQUEST-----
MIIB6TCCAVICAQAwgagxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRl
MREwDwYDVQQHEwhsb2NhbGl0eTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
dHkgTHRkMQ8wDQYDVQQLEwZvdW5hbWUxGzAZBgNVBAMTEnNlcnZlci5leGFtcGxl
LmNvbTEgMB4GCSqGSIb3DQEJARYRZW1haWxAZXhhbXBsZS5jb20wgZ8wDQYJKoZI
hvcNAQEBBQADgY0AMIGJAoGBAMJr7IHXP5QJ8KbxeGV5pygmXLeWhlt3mr5nehbg
osiNnOxdmlYOx/SLEQHf0pSAuocrz9QzSgYhO8Yxtfy0MPb9KFhfGBFGCPoSdYLC
6eZlmuT+jfA2Y5EGu0P2clBciwDjUyoJNAbmBRYw0PiWO7B9to3vX7DBMbx31KmT
MdfxAgMBAAGgADANBgkqhkiG9w0BAQUFAAOBgQAyoSojahrYbGK+6QbxOO7i5Ufm
VHlhVBbPFfmYDrpWjoRlKVwk1iRNi/3ijQi3oPONk19wRh/A0gD0DOiKi3fz2m5K
gaFLIRcBy25EYVeBic39A6b69SiXQoHv00f5CBHNSHLk4hc30vGIWifexU8ehwJJ
TlHmdHkECni6w0eDmg==
-----END CERTIFICATE REQUEST-----
certificate_authority-1.1.0/spec/samples/certs/server.key 0000664 0000000 0000000 00000001567 14257354536 0023670 0 ustar 00root root 0000000 0000000 -----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDCa+yB1z+UCfCm8XhleacoJly3loZbd5q+Z3oW4KLIjZzsXZpW
Dsf0ixEB39KUgLqHK8/UM0oGITvGMbX8tDD2/ShYXxgRRgj6EnWCwunmZZrk/o3w
NmORBrtD9nJQXIsA41MqCTQG5gUWMND4ljuwfbaN71+wwTG8d9SpkzHX8QIDAQAB
AoGBALX9FBvOAsNuMofyjEJgh6m7jxqCmi3QXVdRwSTdDUMx2+wdCjT4DQ/JhRf+
DT3Y6cFRr27wu5/VSACT08hCW3mVgE5WcsmxvxPeaWMQCAUoHW4I9bmpvf/1AksZ
x36N4GwdEvFjDGlM8B1ndW3qLUp6e5iDFUFB7veQGoA6WR/hAkEA39yivn0ThKH/
9a8glJMBDVmnzNXQveBX+Y0aiJSNTT+rBfDRgWxR8A60z1Xl1iHtGG1j1tRXvDL3
2u2w4d1lnQJBAN5VTMFkf7ojTvPh0+QHkc7b3d0IRruojEIG3A1ZdUj4WaOqnOBs
xk6EWsF5YbCBTWH42qWAq/EBXaJcPbyIdWUCQF25882LcpOSfCcyJpLuJX+gbPf/
AYGuH0dVg6lxgOO553H6TM1CO+AlWCCC11LbK3iRvD5i80TRliJsaCV426UCQEAD
RS8lNVUtV00GhxBPUZ7CVPWPrXXYSFG2UeMSD5+ryXtC4xoGl24B03OC9CpygAom
MSWXj2m7X+8gKbI/g7UCQEc0Ne6+4T0NsCz9Dw2TWqIvi+WbK65veyFC212OJ5Wh
qEF4SY3WXkxJk4Y0ElQARMz6DojpwHI5PtAaYswe8wI=
-----END RSA PRIVATE KEY-----
certificate_authority-1.1.0/spec/spec_helper.rb 0000664 0000000 0000000 00000000402 14257354536 0021665 0 ustar 00root root 0000000 0000000 require 'rubygems'
require 'bundler/setup'
require 'certificate_authority'
require 'pathname'
require 'pry'
require 'coveralls'
Coveralls.wear!
SAMPLES_DIR = Pathname.new(__dir__).join('samples').freeze
def sample_file(name)
SAMPLES_DIR.join(name)
end
certificate_authority-1.1.0/spec/units/ 0000775 0000000 0000000 00000000000 14257354536 0020215 5 ustar 00root root 0000000 0000000 certificate_authority-1.1.0/spec/units/certificate_authority_spec.rb 0000664 0000000 0000000 00000000045 14257354536 0026145 0 ustar 00root root 0000000 0000000 describe CertificateAuthority do
end
certificate_authority-1.1.0/spec/units/certificate_revocation_list_spec.rb 0000664 0000000 0000000 00000010063 14257354536 0027322 0 ustar 00root root 0000000 0000000 describe CertificateAuthority::CertificateRevocationList do
before(:each) do
@crl = CertificateAuthority::CertificateRevocationList.new
@root_certificate = CertificateAuthority::Certificate.new
@root_certificate.signing_entity = true
@root_certificate.subject.common_name = "CRL Root"
@root_certificate.key_material.generate_key(768)
@root_certificate.serial_number.number = 1
@root_certificate.sign!
@certificate = CertificateAuthority::Certificate.new
@certificate.key_material.generate_key(768)
@certificate.subject.common_name = "http://bogusSite.com"
@certificate.parent = @root_certificate
@certificate.serial_number.number = 2
@certificate.sign!
@serial_number = CertificateAuthority::SerialNumber.new
@serial_number.revoked_at = Time.now
@serial_number.number = 5
@crl.parent = @root_certificate
@certificate.revoked_at = Time.now
end
it "should accept a list of certificates" do
@crl << @certificate
end
it "should complain if you add a certificate without a revocation time" do
@certificate.revoked_at = nil
expect{ @crl << @certificate}.to raise_error(RuntimeError)
end
it "should have a 'parent' that will be responsible for signing" do
@crl.parent = @root_certificate
expect(@crl.parent).not_to be_nil
end
it "should raise an error if you try and sign a CRL without attaching a parent" do
@crl.parent = nil
expect { @crl.sign! }.to raise_error(RuntimeError)
end
it "should be able to generate a proper CRL" do
@crl << @certificate
expect {@crl.to_pem}.to raise_error(RuntimeError)
@crl.parent = @root_certificate
@crl.sign!
expect(@crl.to_pem).not_to be_nil
expect(OpenSSL::X509::CRL.new(@crl.to_pem)).not_to be_nil
end
it "should be able to mix Certificates and SerialNumbers for convenience" do
@crl << @certificate
@crl << @serial_number
@crl.parent = @root_certificate
@crl.sign!
openssl_csr = OpenSSL::X509::CRL.new(@crl.to_pem)
expect(openssl_csr.revoked.size).to eq(2)
end
it "should have the correct number of entities" do
@crl << @certificate
@crl.parent = @root_certificate
@crl.sign!
openssl_clr = OpenSSL::X509::CRL.new(@crl.to_pem)
expect(openssl_clr.revoked).to be_a(Array)
expect(openssl_clr.revoked.size).to eq(1)
end
it "should have the serial numbers of revoked entities" do
@crl << @certificate
@crl << @serial_number
@crl.parent = @root_certificate
@crl.sign!
openssl_clr = OpenSSL::X509::CRL.new(@crl.to_pem)
expect(openssl_clr.revoked).to be_a(Array)
expect(openssl_clr.revoked.first.serial).to eq(@certificate.serial_number.number)
expect(openssl_clr.revoked.last.serial).to eq(@serial_number.number)
end
it "should be valid according to OpenSSL and signer" do
@crl << @certificate
@crl.parent = @root_certificate
@crl.sign!
openssl_clr = OpenSSL::X509::CRL.new(@crl.to_pem)
openssl_root = OpenSSL::X509::Certificate.new(@root_certificate.to_pem)
expect(openssl_clr.verify(openssl_root.public_key)).to be_truthy
end
describe "Digests" do
it "should use SHA512 by default" do
@crl << @certificate
@crl.parent = @root_certificate
@crl.sign!
openssl_clr = OpenSSL::X509::CRL.new(@crl.to_pem)
expect(openssl_clr.signature_algorithm).to eq("sha512WithRSAEncryption")
end
it "should support alternate digests supported by OpenSSL" do
@crl << @certificate
@crl.parent = @root_certificate
@crl.sign!({"digest" => "SHA1"})
openssl_clr = OpenSSL::X509::CRL.new(@crl.to_pem)
expect(openssl_clr.signature_algorithm).to eq("sha1WithRSAEncryption")
end
end
describe "Next update" do
it "should be able to set a 'next_update' value" do
@crl.next_update = (60 * 60 * 10) # 10 Hours
expect(@crl.next_update).not_to be_nil
end
it "should throw an error if we try and sign up with a negative next_update" do
@crl.sign!
@crl.next_update = - (60 * 60 * 10)
expect{@crl.sign!}.to raise_error(RuntimeError)
end
end
end
certificate_authority-1.1.0/spec/units/certificate_spec.rb 0000664 0000000 0000000 00000047702 14257354536 0024050 0 ustar 00root root 0000000 0000000 describe CertificateAuthority::Certificate do
before(:each) do
@certificate = CertificateAuthority::Certificate.new
end
describe CertificateAuthority::SigningEntity do
it "should behave as a signing entity" do
expect(@certificate.respond_to?(:is_signing_entity?)).to be_truthy
end
it "should only be a signing entity if it's identified as a CA", :rfc3280 => true do
expect(@certificate.is_signing_entity?).to be_falsey
@certificate.signing_entity = true
expect(@certificate.is_signing_entity?).to be_truthy
end
describe "Root certificates" do
before(:each) do
@certificate.signing_entity = true
end
it "should be able to be identified as a root certificate" do
expect(@certificate.is_root_entity?).to be_truthy
end
it "should only be a root certificate if the parent entity is itself", :rfc3280 => true do
expect(@certificate.parent).to eq(@certificate)
end
it "should be a root certificate by default" do
expect(@certificate.is_root_entity?).to be_truthy
end
it "should be able to self-sign" do
@certificate.serial_number.number = 1
@certificate.subject.common_name = "chrischandler.name"
@certificate.key_material.generate_key(768)
@certificate.sign!
cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
expect(cert.subject.to_s).to eq(cert.issuer.to_s)
end
it "should have the basicContraint CA:TRUE" do
@certificate.serial_number.number = 1
@certificate.subject.common_name = "chrischandler.name"
@certificate.key_material.generate_key(768)
@certificate.sign!
cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
expect(cert.extensions.map{|i| [i.oid,i.value] }.select{|i| i.first == "basicConstraints"}.first[1]).to eq("CA:TRUE")
end
end
describe "Intermediate certificates" do
before(:each) do
@different_cert = CertificateAuthority::Certificate.new
@different_cert.signing_entity = true
@different_cert.subject.common_name = "chrischandler.name root"
@different_cert.key_material.generate_key(768)
@different_cert.serial_number.number = 2
@different_cert.sign! #self-signed
@certificate.parent = @different_cert
@certificate.signing_entity = true
end
it "should be able to be identified as an intermediate certificate" do
expect(@certificate.is_intermediate_entity?).to be_truthy
end
it "should not be identified as a root" do
expect(@certificate.is_root_entity?).to be_falsey
end
it "should only be an intermediate certificate if the parent is a different entity" do
expect(@certificate.parent).not_to eq(@certificate)
expect(@certificate.parent).not_to be_nil
end
it "should correctly be signed by a parent certificate" do
@certificate.subject.common_name = "chrischandler.name"
@certificate.key_material.generate_key(768)
@certificate.signing_entity = true
@certificate.serial_number.number = 1
@certificate.sign!
cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
expect(cert.subject.to_s).not_to eq(cert.issuer.to_s)
end
it "should have the basicContraint CA:TRUE" do
@certificate.subject.common_name = "chrischandler.name"
@certificate.key_material.generate_key(768)
@certificate.signing_entity = true
@certificate.serial_number.number = 3
@certificate.sign!
cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
expect(cert.extensions.map{|i| [i.oid,i.value] }.select{|i| i.first == "basicConstraints"}.first[1]).to eq("CA:TRUE")
end
end
describe "Terminal certificates" do
before(:each) do
@different_cert = CertificateAuthority::Certificate.new
@different_cert.signing_entity = true
@different_cert.subject.common_name = "chrischandler.name root"
@different_cert.key_material.generate_key(768)
@different_cert.serial_number.number = 1
@different_cert.sign! #self-signed
@certificate.parent = @different_cert
end
it "should not be identified as an intermediate certificate" do
expect(@certificate.is_intermediate_entity?).to be_falsey
end
it "should not be identified as a root" do
expect(@certificate.is_root_entity?).to be_falsey
end
it "should have the basicContraint CA:FALSE" do
@certificate.subject.common_name = "chrischandler.name"
@certificate.key_material.generate_key(768)
@certificate.signing_entity = false
@certificate.serial_number.number = 1
@certificate.sign!
cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
expect(cert.extensions.map{|i| [i.oid,i.value] }.select{|i| i.first == "basicConstraints"}.first[1]).to eq("CA:FALSE")
end
end
it "should be able to be identified as a root certificate" do
expect(@certificate.respond_to?(:is_root_entity?)).to be_truthy
end
end #End of SigningEntity
describe "Signed certificates" do
before(:each) do
@certificate = CertificateAuthority::Certificate.new
@certificate.subject.common_name = "chrischandler.name"
@certificate.key_material.generate_key(768)
@certificate.serial_number.number = 1
@certificate.sign!
end
it "should have a PEM encoded certificate body available" do
expect(@certificate.to_pem).not_to be_nil
expect(OpenSSL::X509::Certificate.new(@certificate.to_pem)).not_to be_nil
end
end
describe "X.509 V3 Extensions on Signed Certificates" do
before(:each) do
@certificate = CertificateAuthority::Certificate.new
@certificate.subject.common_name = "chrischandler.name"
@certificate.key_material.generate_key(768)
@certificate.serial_number.number = 1
@signing_profile = {
"extensions" => {
"subjectAltName" => {"uris" => ["www.chrischandler.name"]},
"certificatePolicies" => {
"policy_identifier" => "1.3.5.7",
"cps_uris" => ["http://my.host.name/", "http://my.your.name/"],
"user_notice" => {
"explicit_text" => "Testing!", "organization" => "RSpec Test organization name", "notice_numbers" => "1,2,3,4"
}
}
}
}
@certificate.sign!(@signing_profile)
end
describe "SubjectAltName" do
before(:each) do
@certificate = CertificateAuthority::Certificate.new
@certificate.subject.common_name = "chrischandler.name"
@certificate.key_material.generate_key(768)
@certificate.serial_number.number = 1
end
it "should have a subjectAltName if specified" do
@certificate.sign!({"extensions" => {"subjectAltName" => {"uris" => ["www.chrischandler.name"]}}})
cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
expect(cert.extensions.map(&:oid).include?("subjectAltName")).to be_truthy
end
it "should NOT have a subjectAltName if one was not specified" do
@certificate.sign!
cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
expect(cert.extensions.map(&:oid).include?("subjectAltName")).to be_falsey
end
it 'should replace email:copy with email address' do
@certificate.subject.email_address = 'foo@bar.com'
@certificate.sign!(
{ "extensions" => { "subjectAltName" => { 'emails' => %w[copy fubar@bar.com] } } }
)
cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
alt = cert.extensions.select { |e| e.oid == 'subjectAltName' }.first
expect(alt.value).to eq('email:foo@bar.com, email:fubar@bar.com')
end
end
describe "AuthorityInfoAccess" do
before(:each) do
@certificate = CertificateAuthority::Certificate.new
@certificate.subject.common_name = "chrischandler.name"
@certificate.key_material.generate_key(768)
@certificate.serial_number.number = 1
end
it "should have an authority info access if specified" do
@certificate.sign!({"extensions" => {"authorityInfoAccess" => {"ocsp" => ["www.chrischandler.name"]}}})
cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
expect(cert.extensions.map(&:oid).include?("authorityInfoAccess")).to be_truthy
end
end
describe "CrlDistributionPoints" do
before(:each) do
@certificate = CertificateAuthority::Certificate.new
@certificate.subject.common_name = "chrischandler.name"
@certificate.key_material.generate_key(768)
@certificate.serial_number.number = 1
end
it "should have a crlDistributionPoint if specified" do
@certificate.sign!({"extensions" => {"crlDistributionPoints" => {"uris" => ["http://crlThingy.com"]}}})
cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
expect(cert.extensions.map(&:oid).include?("crlDistributionPoints")).to be_truthy
end
it "should NOT have a crlDistributionPoint if one was not specified" do
@certificate.sign!
cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
expect(cert.extensions.map(&:oid).include?("crlDistributionPoints")).to be_falsey
end
end
describe "CertificatePolicies" do
before(:each) do
@certificate = CertificateAuthority::Certificate.new
@certificate.subject.common_name = "chrischandler.name"
@certificate.key_material.generate_key(768)
@certificate.serial_number.number = 1
end
it "should have a certificatePolicy if specified" do
@certificate.sign!({
"extensions" => {
"certificatePolicies" => {
"policy_identifier" => "1.3.5.7",
"cps_uris" => ["http://my.host.name/", "http://my.your.name/"]
}
}
})
cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
expect(cert.extensions.map(&:oid).include?("certificatePolicies")).to be_truthy
end
pending "should contain a nested userNotice if specified" do
#pending
@certificate.sign!({
"extensions" => {
"certificatePolicies" => {
"policy_identifier" => "1.3.5.7",
"cps_uris" => ["http://my.host.name/", "http://my.your.name/"],
"user_notice" => {
"explicit_text" => "Testing explicit text!", "organization" => "RSpec Test organization name", "notice_numbers" => "1,2,3,4"
}
}
}
})
cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
expect(cert.extensions.map(&:oid).include?("certificatePolicies")).to be_truthy
## Checking OIDs after they've run through OpenSSL is a pain...
## The nicely structured data will be flattened to a single String
cert.extensions.each do |ext|
if ext.oid == "certificatePolicies"
expect(ext.to_a[1]).to include("Testing explicit text!")
end
end
end
it "should NOT include a certificatePolicy if not specified" do
@certificate.sign!
cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
expect(cert.extensions.map(&:oid).include?("certificatePolicies")).to be_falsey
end
end
it "should support BasicConstraints" do
cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
expect(cert.extensions.map(&:oid).include?("basicConstraints")).to be_truthy
end
it "should support subjectKeyIdentifier" do
cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
expect(cert.extensions.map(&:oid).include?("subjectKeyIdentifier")).to be_truthy
end
it "should support authorityKeyIdentifier" do
cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
expect(cert.extensions.map(&:oid).include?("authorityKeyIdentifier")).to be_truthy
end
it "should order subjectKeyIdentifier before authorityKeyIdentifier" do
cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
expect(cert.extensions.map(&:oid).select do |oid|
["subjectKeyIdentifier", "authorityKeyIdentifier"].include?(oid)
end).to eq(["subjectKeyIdentifier", "authorityKeyIdentifier"])
end
it "should support keyUsage" do
cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
expect(cert.extensions.map(&:oid).include?("keyUsage")).to be_truthy
end
it "should support extendedKeyUsage" do
cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
expect(cert.extensions.map(&:oid).include?("extendedKeyUsage")).to be_truthy
end
end
describe "Signing profile" do
before(:each) do
@certificate = CertificateAuthority::Certificate.new
@certificate.subject.common_name = "chrischandler.name"
@certificate.key_material.generate_key(768)
@certificate.serial_number.number = 1
@signing_profile = {
"extensions" => {
"basicConstraints" => {"ca" => false},
"crlDistributionPoints" => {"uri" => "http://notme.com/other.crl" },
"subjectKeyIdentifier" => {},
"authorityKeyIdentifier" => {},
"authorityInfoAccess" => {"ocsp" => ["http://youFillThisOut/ocsp/"], "ca_issuers" => ["http://me.com/other.crt"] },
"keyUsage" => {"usage" => ["digitalSignature","nonRepudiation"] },
"extendedKeyUsage" => {"usage" => [ "serverAuth","clientAuth"]},
"subjectAltName" => {"uris" => ["http://subdomains.youFillThisOut/"]},
"certificatePolicies" => {
"policy_identifier" => "1.3.5.8", "cps_uris" => ["http://my.host.name/", "http://my.your.name/"], "user_notice" => {
"explicit_text" => "Explicit Text Here", "organization" => "Organization name", "notice_numbers" => "1,2,3,4"
}
}
}
}
end
it "should be able to sign with an optional policy hash" do
@certificate.sign!(@signing_profile)
end
it "should support a default signing digest of SHA512" do
@certificate.sign!(@signing_profile)
cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
expect(cert.signature_algorithm).to eq("sha512WithRSAEncryption")
end
it "should support a configurable digest algorithm" do
@signing_profile.merge!({"digest" => "SHA1"})
@certificate.sign!(@signing_profile)
cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
expect(cert.signature_algorithm).to eq("sha1WithRSAEncryption")
end
end
describe "from_openssl" do
before(:each) do
@pem_cert=< Time.now + year - day
end
it "should be able to have a revoked at time" do
expect(@certificate.revoked?).to be_falsey
@certificate.revoked_at = Time.now.utc
expect(@certificate.revoked?).to be_truthy
end
end
certificate_authority-1.1.0/spec/units/distinguished_name_spec.rb 0000664 0000000 0000000 00000006200 14257354536 0025415 0 ustar 00root root 0000000 0000000 describe CertificateAuthority::DistinguishedName do
before(:each) do
@distinguished_name = CertificateAuthority::DistinguishedName.new
end
it "should provide the standard x.509 distinguished name common attributes" do
expect(@distinguished_name.respond_to?(:cn)).to be_truthy
expect(@distinguished_name.respond_to?(:l)).to be_truthy
expect(@distinguished_name.respond_to?(:s)).to be_truthy
expect(@distinguished_name.respond_to?(:o)).to be_truthy
expect(@distinguished_name.respond_to?(:ou)).to be_truthy
expect(@distinguished_name.respond_to?(:c)).to be_truthy
expect(@distinguished_name.respond_to?(:emailAddress)).to be_truthy
expect(@distinguished_name.respond_to?(:serialNumber)).to be_truthy
end
it "should provide human-readable equivalents to the distinguished name common attributes" do
expect(@distinguished_name.respond_to?(:common_name)).to be_truthy
expect(@distinguished_name.respond_to?(:locality)).to be_truthy
expect(@distinguished_name.respond_to?(:state)).to be_truthy
expect(@distinguished_name.respond_to?(:organization)).to be_truthy
expect(@distinguished_name.respond_to?(:organizational_unit)).to be_truthy
expect(@distinguished_name.respond_to?(:country)).to be_truthy
expect(@distinguished_name.respond_to?(:email_address)).to be_truthy
expect(@distinguished_name.respond_to?(:serial_number)).to be_truthy
end
it "should require a common name" do
expect(@distinguished_name.valid?).to be_falsey
expect(@distinguished_name.errors.size).to eq(1)
@distinguished_name.common_name = "chrischandler.name"
expect(@distinguished_name.valid?).to be_truthy
end
it "should be convertible to an OpenSSL::X509::Name" do
@distinguished_name.common_name = "chrischandler.name"
@distinguished_name.to_x509_name
end
describe "from_openssl" do
before do
subject = "/CN=justincummins.name/L=on my laptop/ST=relaxed/C=as/O=programmer/OU=using this code"
@name = OpenSSL::X509::Name.parse subject
@dn = CertificateAuthority::DistinguishedName.from_openssl @name
end
it "should reject non Name objects" do
expect { CertificateAuthority::DistinguishedName.from_openssl "Not a OpenSSL::X509::Name" }.to raise_error(RuntimeError)
end
[:common_name, :locality, :state, :country, :organization, :organizational_unit].each do |field|
it "should set the #{field} attribute" do
expect(@dn.send(field)).not_to be_nil
end
end
it "should create an equivalent object" do
expect(@dn.to_x509_name.to_s.split('/')).to match_array(@name.to_s.split('/'))
end
end
describe CertificateAuthority::WrappedDistinguishedName do
it "should mark the DN as having custom OIDs if there's an unknown subject element" do
OpenSSL::ASN1::ObjectId.register("2.3.4.5","testing","testingCustomOIDs")
subject = "/testingCustomOIDs=custom/CN=justincummins.name/L=on my laptop/ST=relaxed/C=as/O=programmer/OU=using this code"
@name = OpenSSL::X509::Name.parse subject
@dn = CertificateAuthority::DistinguishedName.from_openssl @name
expect(@dn.custom_oids?).to be_truthy
end
end
end
certificate_authority-1.1.0/spec/units/extensions_spec.rb 0000664 0000000 0000000 00000023034 14257354536 0023755 0 ustar 00root root 0000000 0000000 describe CertificateAuthority::Extensions do
describe CertificateAuthority::Extensions::BasicConstraints do
it "should only allow true/false" do
basic_constraints = CertificateAuthority::Extensions::BasicConstraints.new
expect(basic_constraints.valid?).to be_truthy
basic_constraints.ca = "moo"
expect(basic_constraints.valid?).to be_falsey
end
it "should respond to :path_len" do
basic_constraints = CertificateAuthority::Extensions::BasicConstraints.new
expect(basic_constraints.respond_to?(:path_len)).to be_truthy
end
it "should raise an error if :path_len isn't a non-negative integer" do
basic_constraints = CertificateAuthority::Extensions::BasicConstraints.new
expect {basic_constraints.path_len = "moo"}.to raise_error(ArgumentError)
expect {basic_constraints.path_len = -1}.to raise_error(ArgumentError)
expect {basic_constraints.path_len = 1.5}.to raise_error(ArgumentError)
end
it "should generate a proper OpenSSL extension string" do
basic_constraints = CertificateAuthority::Extensions::BasicConstraints.new
basic_constraints.ca = true
basic_constraints.path_len = 2
expect(basic_constraints.to_s).to eq("CA:true,pathlen:2")
end
it "should parse values from a proper OpenSSL extension string" do
basic_constraints = CertificateAuthority::Extensions::BasicConstraints.parse("CA:true,pathlen:2", true)
expect(basic_constraints.critical).to be_truthy
expect(basic_constraints.ca).to be_truthy
expect(basic_constraints.path_len).to eq(2)
end
end
describe CertificateAuthority::Extensions::SubjectAlternativeName do
it "should respond to :uris" do
subjectAltName = CertificateAuthority::Extensions::SubjectAlternativeName.new
expect(subjectAltName.respond_to?(:uris)).to be_truthy
end
it "should require 'uris' to be an Array" do
subjectAltName = CertificateAuthority::Extensions::SubjectAlternativeName.new
expect {subjectAltName.uris = "not an array"}.to raise_error(RuntimeError)
end
it "should generate a proper OpenSSL extension string for URIs" do
subjectAltName = CertificateAuthority::Extensions::SubjectAlternativeName.new
subjectAltName.uris = ["http://localhost.altname.example.com"]
expect(subjectAltName.to_s).to eq("URI:http://localhost.altname.example.com")
subjectAltName.uris = ["http://localhost.altname.example.com", "http://other.example.com"]
expect(subjectAltName.to_s).to eq("URI:http://localhost.altname.example.com,URI:http://other.example.com")
end
it "should parse URIs from a proper OpenSSL extension string" do
subjectAltName = CertificateAuthority::Extensions::SubjectAlternativeName.parse("URI:http://localhost.altname.example.com", false)
expect(subjectAltName.uris).to eq(["http://localhost.altname.example.com"])
subjectAltName = CertificateAuthority::Extensions::SubjectAlternativeName.parse("URI:http://localhost.altname.example.com,URI:http://other.example.com", false)
expect(subjectAltName.uris).to eq(["http://localhost.altname.example.com", "http://other.example.com"])
end
it "should respond to :dns_names" do
subjectAltName = CertificateAuthority::Extensions::SubjectAlternativeName.new
expect(subjectAltName.respond_to?(:dns_names)).to be_truthy
end
it "should require 'dns_names' to be an Array" do
subjectAltName = CertificateAuthority::Extensions::SubjectAlternativeName.new
expect {subjectAltName.dns_names = "not an array"}.to raise_error(RuntimeError)
end
it "should generate a proper OpenSSL extension string for DNS names" do
subjectAltName = CertificateAuthority::Extensions::SubjectAlternativeName.new
subjectAltName.dns_names = ["localhost.altname.example.com"]
expect(subjectAltName.to_s).to eq("DNS:localhost.altname.example.com")
subjectAltName.dns_names = ["localhost.altname.example.com", "other.example.com"]
expect(subjectAltName.to_s).to eq("DNS:localhost.altname.example.com,DNS:other.example.com")
end
it "should parse DNS names from a proper OpenSSL extension string" do
subjectAltName = CertificateAuthority::Extensions::SubjectAlternativeName.parse("DNS:localhost.altname.example.com", false)
expect(subjectAltName.dns_names).to eq(["localhost.altname.example.com"])
subjectAltName = CertificateAuthority::Extensions::SubjectAlternativeName.parse("DNS:localhost.altname.example.com,DNS:other.example.com", false)
expect(subjectAltName.dns_names).to eq(["localhost.altname.example.com", "other.example.com"])
end
it "should respond to :ips" do
subjectAltName = CertificateAuthority::Extensions::SubjectAlternativeName.new
expect(subjectAltName.respond_to?(:ips)).to be_truthy
end
it "should require 'ips' to be an Array" do
subjectAltName = CertificateAuthority::Extensions::SubjectAlternativeName.new
expect {subjectAltName.ips = "not an array"}.to raise_error(RuntimeError)
end
it "should generate a proper OpenSSL extension string for IPs" do
subjectAltName = CertificateAuthority::Extensions::SubjectAlternativeName.new
subjectAltName.ips = ["1.2.3.4"]
expect(subjectAltName.to_s).to eq("IP:1.2.3.4")
subjectAltName.ips = ["1.2.3.4", "5.6.7.8"]
expect(subjectAltName.to_s).to eq("IP:1.2.3.4,IP:5.6.7.8")
end
it "should parse IPs from a proper OpenSSL extension string" do
subjectAltName = CertificateAuthority::Extensions::SubjectAlternativeName.parse("IP:1.2.3.4", false)
expect(subjectAltName.ips).to eq(["1.2.3.4"])
subjectAltName = CertificateAuthority::Extensions::SubjectAlternativeName.parse("IP:1.2.3.4,IP:5.6.7.8", false)
expect(subjectAltName.ips).to eq(["1.2.3.4", "5.6.7.8"])
end
describe 'emails' do
let(:subject) { CertificateAuthority::Extensions::SubjectAlternativeName.new }
it "should require 'emails' to be an Array" do
expect {
subject.emails = "not an array"
}.to raise_error "Emails must be an array"
end
it "should generate a proper OpenSSL extension string for emails" do
subject.emails = ["copy"]
expect(subject.to_s).to eq("email:copy")
subject.emails = ["copy", "foo@bar.com"]
expect(subject.to_s).to eq("email:copy,email:foo@bar.com")
end
end
it "should generate a proper OpenSSL extension string for URIs IPs and DNS names together" do
subjectAltName = CertificateAuthority::Extensions::SubjectAlternativeName.new
subjectAltName.ips = ["1.2.3.4"]
expect(subjectAltName.to_s).to eq("IP:1.2.3.4")
subjectAltName.dns_names = ["localhost.altname.example.com"]
expect(subjectAltName.to_s).to eq("DNS:localhost.altname.example.com,IP:1.2.3.4")
subjectAltName.dns_names = ["localhost.altname.example.com", "other.example.com"]
expect(subjectAltName.to_s).to eq("DNS:localhost.altname.example.com,DNS:other.example.com,IP:1.2.3.4")
subjectAltName.ips = ["1.2.3.4", "5.6.7.8"]
expect(subjectAltName.to_s).to eq("DNS:localhost.altname.example.com,DNS:other.example.com,IP:1.2.3.4,IP:5.6.7.8")
subjectAltName.uris = ["http://localhost.altname.example.com"]
expect(subjectAltName.to_s).to eq("URI:http://localhost.altname.example.com,DNS:localhost.altname.example.com,DNS:other.example.com,IP:1.2.3.4,IP:5.6.7.8")
subjectAltName.uris = ["http://localhost.altname.example.com", "http://other.altname.example.com"]
expect(subjectAltName.to_s).to eq("URI:http://localhost.altname.example.com,URI:http://other.altname.example.com,DNS:localhost.altname.example.com,DNS:other.example.com,IP:1.2.3.4,IP:5.6.7.8")
end
it "should parse URIs IPs and DNS names together from a proper OpenSSL extension string" do
subjectAltName = CertificateAuthority::Extensions::SubjectAlternativeName.parse("IP:1.2.3.4", false)
expect(subjectAltName.ips).to eq(["1.2.3.4"])
subjectAltName = CertificateAuthority::Extensions::SubjectAlternativeName.parse("DNS:localhost.altname.example.com,IP:1.2.3.4", false)
expect(subjectAltName.dns_names).to eq(["localhost.altname.example.com"])
subjectAltName = CertificateAuthority::Extensions::SubjectAlternativeName.parse("DNS:localhost.altname.example.com,DNS:other.example.com,IP:1.2.3.4", false)
expect(subjectAltName.dns_names).to eq(["localhost.altname.example.com", "other.example.com"])
subjectAltName = CertificateAuthority::Extensions::SubjectAlternativeName.parse("DNS:localhost.altname.example.com,DNS:other.example.com,IP:1.2.3.4,IP:5.6.7.8", false)
expect(subjectAltName.ips).to eq(["1.2.3.4", "5.6.7.8"])
subjectAltName = CertificateAuthority::Extensions::SubjectAlternativeName.parse("URI:http://localhost.altname.example.com,DNS:localhost.altname.example.com,DNS:other.example.com,IP:1.2.3.4,IP:5.6.7.8", false)
expect(subjectAltName.uris).to eq(["http://localhost.altname.example.com"])
subjectAltName = CertificateAuthority::Extensions::SubjectAlternativeName.parse("URI:http://localhost.altname.example.com,URI:http://other.altname.example.com,DNS:localhost.altname.example.com,DNS:other.example.com,IP:1.2.3.4,IP:5.6.7.8", false)
expect(subjectAltName.uris).to eq(["http://localhost.altname.example.com", "http://other.altname.example.com"])
subjectAltName.emails= ["copy", "foo@bar.com"]
expect(subjectAltName.to_s).to eq("URI:http://localhost.altname.example.com,URI:http://other.altname.example.com,DNS:localhost.altname.example.com,DNS:other.example.com,IP:1.2.3.4,IP:5.6.7.8,email:copy,email:foo@bar.com")
end
end
end
certificate_authority-1.1.0/spec/units/key_material_spec.rb 0000664 0000000 0000000 00000015336 14257354536 0024232 0 ustar 00root root 0000000 0000000 describe CertificateAuthority::KeyMaterial do
[CertificateAuthority::MemoryKeyMaterial, CertificateAuthority::SigningRequestKeyMaterial].each do |key_material_class|
before do
@key_material = key_material_class.new
end
it "#{key_material_class} should know if a key is in memory or hardware" do
expect(@key_material.is_in_hardware?).not_to be_nil
expect(@key_material.is_in_memory?).not_to be_nil
end
it "should use memory by default" do
expect(@key_material.is_in_memory?).to be_truthy
end
end
describe "reading keys from PEM" do
before(:each) do
@key_pair=<