Как разделить пакет сертификатов CA на отдельные файлы?
Я работаю с OpenSSL и мне нужен нормальный список CAs по умолчанию. Я использую список доверенных CAs Mozilla, как в комплекте с cURL. Однако мне нужно разделить этот пакет сертификатов CA, потому что документация OpenSSL говорит:
если CApath не NULL, он указывает на каталог, содержащий сертификаты CA в формате PEM. Каждый файл содержит один сертификат CA. Файлы просматриваются хэш-значением имени субъекта CA, которое, следовательно, должно быть доступный.
например, используя ca-bundle.crt
файл напрямую работает нормально:
openssl-1.0.1g> ./apps/openssl s_client -connect www.google.com:443 -CAfile /home/user/certs/ca-bundle.crt
...
Verify return code: 0 (ok)
---
DONE
но указание каталога, содержащего не работает:
openssl-1.0.1g> ./apps/openssl s_client -connect www.google.com:443 -CApath /opt/aspera/certs
Verify return code: 20 (unable to get local issuer certificate)
---
DONE
Я предполагаю, что это потому, что моя папка не соответствует тому, что запрашивает документация (а именно, каталог, содержащий сертификаты CA в формате PEM, с каждым файлом, содержащим один сертификат, названный хэш-значением). В моем каталоге есть только один пакет сертификатов.
как может Я разделил свой пакет сертификатов, чтобы придерживаться запроса OpenSSL о том, чтобы каждый сертификат был в отдельном файле? Бонусные баллы, если хеширование можно сделать тоже (хотя при необходимости я мог бы написать сценарий, чтобы сделать это сам, если все сертификаты находятся в отдельных файлах).
5 ответов
вы можете разделить пакет с awk
, вот так, в соответствующем каталоге:
awk 'BEGIN {c=0;} /BEGIN CERT/{c++} { print > "cert." c ".pem"}' < ca-bundle.pem
затем создайте ссылки OpenSSL, запустив c_rehash
утилита, которая поставляется с OpenSSL:
c_rehash .
Примечание: используйте "gawk" на не linux-платформах - как указано выше, зависит от конкретной функции GNU.
просто чтобы дать альтернативу; столкнувшись с той же проблемой, я закончил с csplit:
csplit -k -f bar foo.pem '/END CERTIFICATE/+1' {10}
следующий Ruby-скрипт разделит пакет (с одним или несколькими сертификатами в нем) на файлы с именем после хэшей -- side-stepping c_rehash
шаг в большинстве случаев.
использовать cd
в нужный каталог (например,/etc/ssl/certs/
) и запустите скрипт с путем к вашему пакету сертификатов в качестве единственного аргумента. Например: ruby /tmp/split-certificates.rb ca-root-nss.crt
.
#!/usr/bin/env ruby
require 'openssl'
blob = IO.binread(ARGV[0]) # Read the entire file at once
DELIMITER = "\n-----END CERTIFICATE-----\n"
blobs = blob.split(DELIMITER)
blobs.each do |blob|
blob.strip!
blob += DELIMITER # Does not break DER
begin
cert = OpenSSL::X509::Certificate.new blob
rescue
puts "Skipping what seems like junk"
next
end
begin
# XXX Need to handle clashes, suffix other than 0
filename=sprintf("%x.0", cert.subject.hash)
File.open(filename,
File::WRONLY|File::CREAT|File::EXCL) do |f|
f.write(blob)
end
rescue Errno::EEXIST
puts "#{filename} already exists, skipping"
end
end
Если вы хотите получить один сертификат из PEM с несколькими сертификатами, попробуйте:
$ awk '/subject.*CN=host.domain.com/,/END CERTIFICATE/' INPUT.PEM
вот мой в Perl (так много кода, но мне нравится программирование gonzo):
#!/usr/bin/perl -w
# -------
# Split "certificate bundles" like those found in /etc/pki/tls/certs into
# individual files and append the X509 cleartext description to each file.
#
# The file to split is given on the command line or piped via STDIN.
#
# Files are simply created in the current directory!
#
# Created files are named "certificate.XX" or "trusted-certificate.XX",
# with XX an index value.
#
# If a file with the same name as the output file already exists, it is not
# overwritten. Instead a new name with a higher index is tried.
#
# This works for bundles of both trusted and non-trusted certificates.
#
# See http://tygerclan.net/?q=node/49 for another program of this kind,
# which sets the name of the split-off files in function of the subject
# -------
my @lines = <> or die "Could not slurp: $!";
my $state = "outside"; # reader state machine state
my $count = 0; # index of the certificate file we create
my $fh; # file handle of the certificate file we create
my $fn; # file name of the certificate file we create
my $trusted; # either undef or "TRUSTED" depend on type of certificate
for my $line (@lines) {
chomp $line;
if ($state eq "outside") {
if ($line =~ /^(-----BEGIN (TRUSTED )?CERTIFICATE-----)\s*$/) {
my $marker = ;
$trusted = ;
$state = "inside";
my $created = 0;
my $prefix = "";
if ($trusted) {
$prefix = "trusted-"
}
while (!$created) {
$fn = "${prefix}certificate.$count";
$count++;
if (-f $fn) {
# print STDERR "File '$fn' exists; increasing version number to $count\n";
}
else {
print STDERR "Certificate data goes to file '$fn'\n";
open($fh,">$fn") || die "Could not create file '$fn': $!\n";
$created = 1;
print $fh "$marker\n"
}
}
}
else {
print STDERR "Skipping line '$line'\n"
}
}
else {
if ($line =~ /^(-----END (TRUSTED )?CERTIFICATE-----)\s*$/) {
my $marker = ;
my $trustedCheck = ;
if (!((($trusted && $trustedCheck) || (!$trusted && !$trustedCheck)))) {
die "Trusted flag difference detected\n"
}
$state = "outside";
print $fh "$marker\n";
print STDERR "Closing file '$fn'\n";
close $fh;
# Append x509 cleartext output by calling openssl tool
`openssl x509 -noout -text -in '$fn' >> '$fn'`;
if ($? != 0) {
die "Could not run 'openssl x509' command: $!\n";
}
}
else {
print $fh "$line\n"
}
}
}
if ($state eq "inside") {
die "Last certificate was not properly terminated\n";
}