【问题标题】:How can I split a CA certificate bundle into separate files?如何将 CA 证书捆绑包拆分为单独的文件?
【发布时间】:2014-07-01 21:47:00
【问题描述】:

我正在使用 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 的要求,即每个证书都在一个单独的文件中?如果哈希也可以完成,则可以加分(尽管如果需要,如果所有证书都在单独的文件中,我可以自己编写一个脚本来执行此操作)。

【问题讨论】:

    标签: linux ssl openssl


    【解决方案1】:

    您可以像这样在适当的目录中使用awk 拆分捆绑包:

    awk 'BEGIN {c=0;} /BEGIN CERT/{c++} { print > "cert." c ".pem"}' < ca-bundle.pem 
    

    然后,通过运行 OpenSSL 附带的 c_rehash 实用程序来创建 OpenSSL 所需的链接:

    c_rehash .
    

    注意:在非 linux 平台上使用 'gawk' - 如上所述依赖于 GNU 特定功能。

    【讨论】:

    • 我只需要将 CA 捆绑包拆分为单独的文件,这非常有效,谢谢 ;)
    【解决方案2】:

    只是提供一个替代方案;面临同样的问题,我最终选择了 csplit:

    csplit -k -f bar foo.pem '/END CERTIFICATE/+1' {10}
    
    【解决方案3】:

    以下 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
    

    【讨论】:

    • 谢谢,无需额外安装即可在 macos 上完美运行。如果哈希重叠时扩展 # 增加会更好,尽管我猜不太可能发生
    【解决方案4】:

    如果您想从多证书 PEM 中获取单个证书,请尝试:

    $ awk '/subject.*CN=host.domain.com/,/END CERTIFICATE/' INPUT.PEM
    

    source

    【讨论】:

    • 这不适用于在 BEGIN 之前没有内容的“精简”.pem 文件
    【解决方案5】:

    这是我用 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  = $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";
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-05
      • 2023-03-07
      • 2022-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多