Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
...
Checking mergeability… Don't worry, you can still create the pull request.
  • 8 commits
  • 7 files changed
  • 0 commit comments
  • 2 contributors
Commits on May 03, 2012
@sul3n3t sul3n3t Move Pkcs11KeyMaterial to its own spec file.
If it is in a different source file, it should probably have its own
matching spec. I changed a comment or two and some whitespace was
auto-removed.
009682c
@sul3n3t sul3n3t Added SigningRequestKeyMaterial for CSR public keys. e5d2cc3
@sul3n3t sul3n3t So many tabs f97935d
@sul3n3t sul3n3t Explicitly order {subject,authority}keyIdentifier extensions. 2fc5dfd
@sul3n3t sul3n3t DistinguishedName builder from OpenSSL::X509::Name. e00443c
@sul3n3t sul3n3t Certificate class builder from OpenSSL cert. e113a17
Commits on Aug 12, 2012
@sul3n3t sul3n3t Updates ruby case syntax for 1.9. 53566b2
Chris Chandler Merge branch 'master' of github.com:sul3n3t/certificate_authority
Conflicts:
	lib/certificate_authority/certificate.rb
	lib/certificate_authority/key_material.rb
	spec/units/certificate_spec.rb
	spec/units/key_material_spec.rb
027e01a
View
20 lib/certificate_authority/certificate.rb
@@ -82,7 +82,8 @@ def sign!(signing_profile={})
factory.config = openssl_config
- self.extensions.keys.each do |k|
+ # 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)
@@ -179,5 +180,22 @@ def merge_options(config,hash)
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
+ # TODO extensions
+ certificate
+ end
+
end
end
View
19 lib/certificate_authority/distinguished_name.rb
@@ -35,5 +35,24 @@ def to_x509_name
name.add_entry("C", country) unless country.blank?
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
+
+ name = DistinguishedName.new
+ openssl_name.to_a.each do |k,v|
+ case k
+ when "CN" then name.common_name = v
+ when "L" then name.locality = v
+ when "ST" then name.state = v
+ when "C" then name.country = v
+ when "O" then name.organization = v
+ when "OU" then name.organizational_unit = v
+ end
+ end
+ name
+ end
end
end
View
33 lib/certificate_authority/key_material.rb
@@ -57,6 +57,39 @@ def private_key
def public_key
@public_key
end
+ end
+
+ class SigningRequestKeyMaterial
+ include KeyMaterial
+ include ActiveModel::Validations
+
+ validates_each :public_key do |record, attr, value|
+ record.errors.add :public_key, "cannot be blank" if record.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
View
41 spec/units/certificate_spec.rb
@@ -179,7 +179,7 @@
@certificate.serial_number.number = 1
end
- it "should have a subjectAltName if specified" do
+ it "should have a subjectAltName if specified" do
@certificate.sign!({"extensions" => {"subjectAltName" => {"uris" => ["www.chrischandler.name"]}}})
cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
cert.extensions.map(&:oid).include?("subjectAltName").should be_true
@@ -290,6 +290,13 @@
cert.extensions.map(&:oid).include?("authorityKeyIdentifier").should be_true
end
+ it "should order subjectKeyIdentifier before authorityKeyIdentifier" do
+ cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
+ cert.extensions.map(&:oid).select do |oid|
+ ["subjectKeyIdentifier", "authorityKeyIdentifier"].include?(oid)
+ end.should == ["subjectKeyIdentifier", "authorityKeyIdentifier"]
+ end
+
it "should support keyUsage" do
cert = OpenSSL::X509::Certificate.new(@certificate.to_pem)
cert.extensions.map(&:oid).include?("keyUsage").should be_true
@@ -346,6 +353,38 @@
end
+ describe "from_openssl" do
+ before(:each) do
+ @pem_cert=<<CERT
+-----BEGIN CERTIFICATE-----
+MIICFDCCAc6gAwIBAgIJAPDLgMilKuayMA0GCSqGSIb3DQEBBQUAMEgxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMQowCAYDVQQKEwEgMRgwFgYDVQQD
+Ew9WZXJ5IFNtYWxsIENlcnQwHhcNMTIwNTAzMDMyODI1WhcNMTMwNTAzMDMyODI1
+WjBIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKU29tZS1TdGF0ZTEKMAgGA1UEChMB
+IDEYMBYGA1UEAxMPVmVyeSBTbWFsbCBDZXJ0MEwwDQYJKoZIhvcNAQEBBQADOwAw
+OAIxAN6+33+WQ3FBMt+vMhshxOj+8W7V64pDKCJ3pVlnSn36imBWqrN0AGWX8qjv
+S+GzGwIDAQABo4GqMIGnMB0GA1UdDgQWBBRMUQ/HpPrAkKOufS5h+xPtEuzyWDB4
+BgNVHSMEcTBvgBRMUQ/HpPrAkKOufS5h+xPtEuzyWKFMpEowSDELMAkGA1UEBhMC
+VVMxEzARBgNVBAgTClNvbWUtU3RhdGUxCjAIBgNVBAoTASAxGDAWBgNVBAMTD1Zl
+cnkgU21hbGwgQ2VydIIJAPDLgMilKuayMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN
+AQEFBQADMQAq0CsqEChn4uf6MkXYBwaAAmS3JLmagyliJe5zM3y8dZz6Em2Ugb8o
+1cCaKaHJHSg=
+-----END CERTIFICATE-----
+CERT
+ @openssl_cert = OpenSSL::X509::Certificate.new @pem_cert
+ @small_cert = CertificateAuthority::Certificate.from_openssl @openssl_cert
+ end
+
+ it "should reject non-Certificate arguments" do
+ lambda { CertificateAuthority::Certificate.from_openssl "a string" }.should raise_error
+ end
+
+ it "should only be missing a private key" do
+ @small_cert.should_not be_valid
+ @small_cert.key_material.private_key = "data"
+ @small_cert.should be_valid
+ end
+ end
it "should have a distinguished name" do
@certificate.distinguished_name.should_not be_nil
View
31 spec/units/distinguished_name_spec.rb
@@ -4,7 +4,7 @@
before(:each) do
@distinguished_name = CertificateAuthority::DistinguishedName.new
end
-
+
it "should provide the standard x.509 distinguished name common attributes" do
@distinguished_name.respond_to?(:cn).should be_true
@distinguished_name.respond_to?(:l).should be_true
@@ -13,7 +13,7 @@
@distinguished_name.respond_to?(:ou).should be_true
@distinguished_name.respond_to?(:c).should be_true
end
-
+
it "should provide human-readable equivalents to the distinguished name common attributes" do
@distinguished_name.respond_to?(:common_name).should be_true
@distinguished_name.respond_to?(:locality).should be_true
@@ -22,17 +22,38 @@
@distinguished_name.respond_to?(:organizational_unit).should be_true
@distinguished_name.respond_to?(:country).should be_true
end
-
+
it "should require a common name" do
@distinguished_name.valid?.should be_false
@distinguished_name.errors.size.should == 1
@distinguished_name.common_name = "chrischandler.name"
@distinguished_name.valid?.should be_true
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
+ lambda { CertificateAuthority::DistinguishedName.from_openssl "Not a OpenSSL::X509::Name" }.should raise_error
+ end
+
+ [:common_name, :locality, :state, :country, :organization, :organizational_unit].each do |field|
+ it "should set the #{field} attribute" do
+ @dn.send(field).should_not be_nil
+ end
+ end
+
+ it "should create an equivalent object" do
+ @dn.to_x509_name.to_s.split('/').should =~ @name.to_s.split('/')
+ end
+ end
end
View
106 spec/units/key_material_spec.rb
@@ -1,17 +1,25 @@
require File.dirname(__FILE__) + '/units_helper'
-describe CertificateAuthority::MemoryKeyMaterial do
- before(:each) do
- @key_material = CertificateAuthority::MemoryKeyMaterial.new
- end
+describe CertificateAuthority::KeyMaterial do
+ [CertificateAuthority::MemoryKeyMaterial, CertificateAuthority::SigningRequestKeyMaterial].each do |key_material_class|
+ before do
+ @key_material = key_material_class.new
+ end
- it "should know if a key is in memory or hardware" do
- @key_material.is_in_hardware?.should_not be_nil
- @key_material.is_in_memory?.should_not be_nil
+ it "#{key_material_class} should know if a key is in memory or hardware" do
+ @key_material.is_in_hardware?.should_not be_nil
+ @key_material.is_in_memory?.should_not be_nil
+ end
+
+ it "should use memory by default" do
+ @key_material.is_in_memory?.should be_true
+ end
end
+end
- it "should use memory by default" do
- @key_material.is_in_memory?.should be_true
+describe CertificateAuthority::MemoryKeyMaterial do
+ before(:each) do
+ @key_material = CertificateAuthority::MemoryKeyMaterial.new
end
it "should be able to generate an RSA key" do
@@ -26,7 +34,7 @@
@key_material.generate_key(1024).should_not be_nil
end
- describe "in memory" do
+ describe "with generated key" do
before(:all) do
@key_material_in_memory = CertificateAuthority::MemoryKeyMaterial.new
@key_material_in_memory.generate_key(1024)
@@ -41,47 +49,7 @@
end
end
- ## Anything that requires crypto hardware needs to be tagged as 'pkcs11'
- describe "in hardware", :pkcs11 => true do
- before(:each) do
- @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"
- end
-
- it "should identify as being in hardware", :pkcs11 => true do
- @key_material_in_hardware.is_in_hardware?.should be_true
- end
-
- it "should return a Pkey ref if the private key is requested", :pkcs11 => true do
- @key_material_in_hardware.private_key.class.should == OpenSSL::PKey::RSA
- end
-
- it "should return a Pkey ref if the private key is requested", :pkcs11 => true do
- @key_material_in_hardware.public_key.class.should == OpenSSL::PKey::RSA
- end
-
- it "should accept an ID for on-token objects", :pkcs11 => true do
- @key_material_in_hardware.respond_to?(:token_id).should be_true
- end
-
- it "should accept a path to a shared library for a PKCS11 driver", :pkcs11 => true do
- @key_material_in_hardware.respond_to?(:pkcs11_lib).should be_true
- end
-
- it "should accept a path to OpenSSL's dynamic PKCS11 engine (provided by libengine-pkcs11-openssl)", :pkcs11 => true do
- @key_material_in_hardware.respond_to?(:openssl_pkcs11_engine_lib).should be_true
- end
-
- it "should accept an optional PIN to authenticate to the token", :pkcs11 => true do
- @key_material_in_hardware.respond_to?(:pin).should be_true
- end
-
- end
-
- it "not validate without public and private keys" do
+ it "should not validate without public and private keys" do
@key_material.valid?.should be_false
@key_material.generate_key(1024)
@key_material.valid?.should be_true
@@ -92,5 +60,41 @@
@key_material.private_key = nil
@key_material.valid?.should be_false
end
+end
+
+describe CertificateAuthority::SigningRequestKeyMaterial do
+ before(:each) do
+ @request = OpenSSL::X509::Request.new <<CSR
+-----BEGIN CERTIFICATE REQUEST-----
+MIIBjTCB9wIBADBOMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEU
+MBIGA1UEBxMLQmVyc2Vya2VsZXkxFDASBgNVBAoTC0NlcnRzICdSIFVzMIGfMA0G
+CSqGSIb3DQEBAQUAA4GNADCBiQKBgQCaGiBcv++581KYt6y2NNcUaZNPPeNZ0UkX
+ujzZQQllx7PlYmsKTE6ZzfTUc0AJvDBIuACg03eagaEaBZtUFbsLkSOLJyYiIfF5
+f9PuXImz2RDzBJQ/+u82gQAcvPhm94xK8jeNPcn0Ege7Y7SRK4YYonX+0ZveP02L
+FjuEfrZcZQIDAQABoAAwDQYJKoZIhvcNAQEFBQADgYEAecOQz0RfnmSxxzOyHZ1e
+Wo2hQqPOmkfIbvL2l1Ml+HybJQJn6OpLmeveyU48SI2M7UqeNkHtsogMljy3re4L
+QlwK7lNd6SymdfSCPjUcdoLOaHolZXYNvCHltTc5skRHG7ti5yv4cu0ItIcCS0yp
+7L3maDEbTLsDdouHeFfbLWA=
+-----END CERTIFICATE REQUEST-----
+CSR
+ @key_material = CertificateAuthority::SigningRequestKeyMaterial.new @request
+ end
+
+ it "should generate from a CSR" do
+ @key_material.should_not be_nil
+ end
+ it "should be able to expose a public key" do
+ @key_material.public_key.should_not be_nil
+ end
+
+ it "should not have a private key" do
+ @key_material.private_key.should be_nil
+ end
+
+ it "should raise when signature does not verify" do
+ invalid = @request
+ invalid.public_key = OpenSSL::PKey::RSA.new 512
+ lambda { CertificateAuthority::SigningRequestKeyMaterial.new invalid }.should raise_error
+ end
end
View
41 spec/units/pkcs11_key_material_spec.rb
@@ -0,0 +1,41 @@
+require File.dirname(__FILE__) + '/units_helper'
+
+## Anything that requires crypto hardware needs to be tagged as 'pkcs11'
+describe CertificateAuthority::Pkcs11KeyMaterial, :pkcs11 => true do
+ before(:each) do
+ @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"
+ end
+
+ it "should identify as being in hardware", :pkcs11 => true do
+ @key_material_in_hardware.is_in_hardware?.should be_true
+ end
+
+ it "should return a Pkey ref if the private key is requested", :pkcs11 => true do
+ @key_material_in_hardware.private_key.class.should == OpenSSL::PKey::RSA
+ end
+
+ it "should return a Pkey ref if the public key is requested", :pkcs11 => true do
+ @key_material_in_hardware.public_key.class.should == OpenSSL::PKey::RSA
+ end
+
+ it "should accept an ID for on-token objects", :pkcs11 => true do
+ @key_material_in_hardware.respond_to?(:token_id).should be_true
+ end
+
+ it "should accept a path to a shared library for a PKCS11 driver", :pkcs11 => true do
+ @key_material_in_hardware.respond_to?(:pkcs11_lib).should be_true
+ end
+
+ it "should accept a path to OpenSSL's dynamic PKCS11 engine (provided by libengine-pkcs11-openssl)", :pkcs11 => true do
+ @key_material_in_hardware.respond_to?(:openssl_pkcs11_engine_lib).should be_true
+ end
+
+ it "should accept an optional PIN to authenticate to the token", :pkcs11 => true do
+ @key_material_in_hardware.respond_to?(:pin).should be_true
+ end
+
+end

No commit comments for this range

Something went wrong with that request. Please try again.