@@ -38,6 +38,7 @@ module CryptCheck | |||
autoload :Method, 'cryptcheck/tls/method' | |||
autoload :Cipher, 'cryptcheck/tls/cipher' | |||
autoload :Curve, 'cryptcheck/tls/curve' | |||
autoload :Cert, 'cryptcheck/tls/cert' | |||
autoload :Server, 'cryptcheck/tls/server' | |||
autoload :TcpServer, 'cryptcheck/tls/server' | |||
autoload :UdpServer, 'cryptcheck/tls/server' |
@@ -1,6 +1,10 @@ | |||
module CryptCheck | |||
module Tls | |||
class Cert | |||
DEFAULT_CA_DIRECTORIES = [ | |||
'/usr/share/ca-certificates/mozilla' | |||
] | |||
SIGNATURE_ALGORITHMS = { | |||
'dsaWithSHA' => %i(sha1 dss), | |||
'dsaWithSHA1' => %i(sha1 dss), | |||
@@ -48,6 +52,21 @@ module CryptCheck | |||
end | |||
RUBY_EVAL | |||
end | |||
def self.trusted?(cert, chain, roots: DEFAULT_CA_DIRECTORIES) | |||
store = ::OpenSSL::X509::Store.new | |||
store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT | |||
store.add_chains roots | |||
chain.each do |cert| | |||
# Never add other self signed certificates than system CA ! | |||
next if cert.subject == cert.issuer | |||
store.add_cert cert rescue nil | |||
end | |||
trusted = store.verify cert | |||
return :trusted if trusted | |||
store.error_string | |||
end | |||
end | |||
end | |||
end |
@@ -154,3 +154,24 @@ class ::OpenSSL::PKey::DH | |||
end | |||
end | |||
end | |||
class ::OpenSSL::X509::Store | |||
def add_chains(chains) | |||
chains = [chains] unless chains.is_a? Enumerable | |||
chains.each do |chain| | |||
case chain | |||
when ::OpenSSL::X509::Certificate | |||
self.add_cert chain | |||
else | |||
if File.directory?(chain) | |||
Dir.entries(chain) | |||
.collect { |e| File.join chain, e } | |||
.select { |e| File.file? e } | |||
.each { |f| self.add_file f } | |||
else | |||
self.add_file chain | |||
end | |||
end | |||
end | |||
end | |||
end |
@@ -0,0 +1,32 @@ | |||
describe CryptCheck::Tls::Cert do | |||
def load_chain(chain) | |||
chain.collect { |f| ::OpenSSL::X509::Certificate.new File.read File.join 'spec/resources', "#{f}.crt" } | |||
end | |||
describe '::trusted?' do | |||
it 'must accept valid certificat' do | |||
cert, *chain, ca = load_chain %w(custom intermediate ca) | |||
trust = ::CryptCheck::Tls::Cert.trusted? cert, chain, roots: ca | |||
expect(trust).to eq :trusted | |||
end | |||
it 'must reject self signed certificate' do | |||
cert, ca = load_chain %w(self-signed ca) | |||
trust = ::CryptCheck::Tls::Cert.trusted? cert, [], roots: ca | |||
expect(trust).to eq 'self signed certificate' | |||
end | |||
it 'must reject unknown CA' do | |||
cert, *chain = load_chain %w(custom intermediate ca) | |||
trust = ::CryptCheck::Tls::Cert.trusted? cert, chain, roots: [] | |||
expect(trust).to eq 'unable to get issuer certificate' | |||
end | |||
it 'must reject missing intermediate chain' do | |||
cert, ca = load_chain %w(custom ca) | |||
chain = [] | |||
trust = ::CryptCheck::Tls::Cert.trusted? cert, chain, roots: ca | |||
expect(trust).to eq 'unable to get local issuer certificate' | |||
end | |||
end | |||
end |
@@ -0,0 +1,13 @@ | |||
-----BEGIN CERTIFICATE----- | |||
MIIB7zCCAXWgAwIBAgIJAKFu2k3vOIffMAoGCCqGSM49BAMEMBIxEDAOBgNVBAMM | |||
B3Rlc3QtY2EwHhcNMTcwMTIyMTg1NTUxWhcNMTgwMTIyMTg1NTUxWjASMRAwDgYD | |||
VQQDDAd0ZXN0LWNhMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEhVE2pSx4GG922yqA | |||
z0W0usG8dFdY4qtTD5mwwBzRhu9NegzQmaE5oHNzQrQE8v0/ShrSHNdID6Phty9K | |||
lPYoenUmpH0sdJDqQ5cVUDkmw0+f+XpROtCiBcN8kTmiVXQ5o4GWMIGTMA8GA1Ud | |||
EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgL0MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr | |||
BgEFBQcDAjAdBgNVHQ4EFgQU2saIfk29nr+adaNemnS2AaNjXJEwHwYDVR0jBBgw | |||
FoAU2saIfk29nr+adaNemnS2AaNjXJEwFAYDVR0RBA0wC4IJbG9jYWxob3N0MAoG | |||
CCqGSM49BAMEA2gAMGUCMQCzxeexb5HauoM8OQPBK7MWxzganLfVoi1GCsbvjUQy | |||
AB8AAVijIPwT/MGcigge4z8CMFimJXl934AtL8iM+Jd9ykvNXXxzSn9YRm9aLD3K | |||
w6vam+k+gA4sdijDbRC/Tc/3NQ== | |||
-----END CERTIFICATE----- |
@@ -0,0 +1,13 @@ | |||
-----BEGIN CERTIFICATE----- | |||
MIIB6jCCAXCgAwIBAgIJAKyx4KGEOyVdMAoGCCqGSM49BAMEMBwxGjAYBgNVBAMM | |||
EXRlc3QtaW50ZXJtZWRpYXRlMB4XDTE3MDEyMjE4NTU1MVoXDTE4MDEyMjE4NTU1 | |||
MVowFDESMBAGA1UEAwwJdGVzdC1sZWFmMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE | |||
kZFi7jp4Z+3m1lR/aIHuNalLQtjaCErIgrWhFL7oUjzWMN1dR3nAmmosKlCSRc7A | |||
Xazs+CC0QB1LgsZCFFPhPqUd5456iwCHaSVQ3maESrZtzJo78v/fE9HRuuh5fFiL | |||
o4GFMIGCMAsGA1UdDwQEAwIE8DAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH | |||
AwIwHQYDVR0OBBYEFB54cEd+wLKHpMKYkYCxmSgWERrQMB8GA1UdIwQYMBaAFMgN | |||
6Mqlnk3ZRmp4RrAXXKeC3yVHMBQGA1UdEQQNMAuCCWxvY2FsaG9zdDAKBggqhkjO | |||
PQQDBANoADBlAjEAwbhbwXjekyl3esK9ywh+jKCVhf7BzaF4H7LAxUE1PmXTORrZ | |||
tqz2MXK3/zYfe1bXAjAuan+xZ4d5zCgBvnFO2/LMEX07SFQJT3l1hKAZjpbdNm/K | |||
MY23IR6iLWkPlG1u+Wo= | |||
-----END CERTIFICATE----- |
@@ -0,0 +1,13 @@ | |||
-----BEGIN CERTIFICATE----- | |||
MIIB+TCCAX+gAwIBAgIJAOko1FM8hOfNMAoGCCqGSM49BAMEMBIxEDAOBgNVBAMM | |||
B3Rlc3QtY2EwHhcNMTcwMTIyMTg1NTUxWhcNMTgwMTIyMTg1NTUxWjAcMRowGAYD | |||
VQQDDBF0ZXN0LWludGVybWVkaWF0ZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABNjg | |||
qyABIHj96OvYN1YCe+z3mILDlm1qNXm1bpoMcx7AVANk+AFUjbK/mhSyx5ONbBw/ | |||
4kMBNtVW7OpkiZwLr57SbqDv0n4ExirUvvBm7OcqqSY+73lXM/cezMTRA/3ZqqOB | |||
ljCBkzAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIC9DAdBgNVHSUEFjAUBggr | |||
BgEFBQcDAQYIKwYBBQUHAwIwHQYDVR0OBBYEFMgN6Mqlnk3ZRmp4RrAXXKeC3yVH | |||
MB8GA1UdIwQYMBaAFNrGiH5NvZ6/mnWjXpp0tgGjY1yRMBQGA1UdEQQNMAuCCWxv | |||
Y2FsaG9zdDAKBggqhkjOPQQDBANoADBlAjAUAte4U3OtzmeQLA/Cq1JTtsrE7sy9 | |||
kZzxGHxACZ53sTGA2c4K86lR2RGoXYvW62wCMQCNSLH+qukadu52ip7HTkihrtae | |||
hBVOBO+el6rCcby91xUuWU24AJy9Ce9TxcQC384= | |||
-----END CERTIFICATE----- |
@@ -0,0 +1,13 @@ | |||
-----BEGIN CERTIFICATE----- | |||
MIICBjCCAYugAwIBAgIJAPnnJnLp7H/XMAoGCCqGSM49BAMEMBQxEjAQBgNVBAMM | |||
CWxvY2FsaG9zdDAeFw0xNzAxMjIxNjM1NDdaFw0xODAxMjIxNjM1NDdaMBQxEjAQ | |||
BgNVBAMMCWxvY2FsaG9zdDB2MBAGByqGSM49AgEGBSuBBAAiA2IABJvRcgAMkjzZ | |||
p0YD/mXa2Td8sy7fBr7F5Sj8toSmLAxkxxPCnm9DDdLQXy7IZXA1HJkiRUIJ8BTk | |||
gSxmKQBwl3my2quHGx7GSZshpER4tRtqWI21dTUkuu9bGR66bbLa8aOBqDCBpTAP | |||
BgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIC9DAdBgNVHSUEFjAUBggrBgEFBQcD | |||
AQYIKwYBBQUHAwIwHQYDVR0OBBYEFCEkGXQc44mMopATg1jr+stKnF4LMB8GA1Ud | |||
IwQYMBaAFCEkGXQc44mMopATg1jr+stKnF4LMBQGA1UdEQQNMAuCCWxvY2FsaG9z | |||
dDAQBggrBgEFBQcBGAEB/wQBMDAKBggqhkjOPQQDBANpADBmAjEAkPKxToKRloWT | |||
eH4lGaUrqBGpRof92rWmJiBLs5WnaYM73S/GdKNK1j0jKRCKXKpzAjEAgpjvaUhd | |||
qXkR3g8iWedrFjkVHHVrUGV9JW7elHP7bD6XryqsGRNK2X8yq0J616gP | |||
-----END CERTIFICATE----- |