我正在使用OpenSSL,需要一个理智的默认CA列表。我使用Mozilla的受信任CA列表bundled by cURL。但是,我需要拆分此CA证书捆绑包,因为OpenSSL documentation says:
如果CApath不为NULL,则它指向包含PEM格式的CA证书的目录。每个文件都包含一个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
但指定包含ca-bundle.crt
文件的目录不起作用:
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
我认为这是因为我的文件夹并不符合文档要求的内容(即包含PEM格式的CA证书的目录,每个文件包含一个证书,由哈希值命名)。我的目录只有一组证书。
如何拆分我的证书捆绑以遵守OpenSSL的请求,即每个证书都在一个单独的文件中?如果也可以进行散列,则可以获得奖励积分(如果需要的话,如果所有证书都在单个文件中,我可以编写一个脚本来自己完成)。
答案 0 :(得分:15)
您可以将awk
这样的捆绑包拆分到适当的目录中:
awk 'BEGIN {c=0;} /BEGIN CERT/{c++} { print > "cert." c ".pem"}' < ca-bundle.pem
然后,通过运行OpenSSL附带的c_rehash
实用程序来创建OpenSSL想要的链接:
c_rehash .
注意:使用&#39; gawk&#39;在非Linux平台上 - 如上所述依赖于GNU特定功能。
答案 1 :(得分:8)
只是提供另一种选择;面对同样的问题,我最终得到了csplit:
csplit -k -f bar foo.pem '/END CERTIFICATE/+1' {10}
答案 2 :(得分:1)
以下Ruby脚本会将捆绑包(其中包含一个或多个证书)拆分为以散列命名的文件 - 在大多数情况下都是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
答案 3 :(得分:0)
答案 4 :(得分:0)
这是Perl中的我(代码太多,但是我喜欢奇闻趣事编程):
#!/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 = $1;
$trusted = $2;
$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 = $1;
my $trustedCheck = $2;
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";
}