Kevin J. McCarthy wrote: > Ah. I see my mistake. I didn't realize mutt was prompting for the > label first. The current patch added a prompt for *each* certificate > leaf+chain, but that won't work. I will change it to prompt only once > for the whole thing.
Here's a revised patch loosening up the attributes parsing and changing it to only prompt once for a label. -Kevin
# HG changeset patch # User Kevin McCarthy <[email protected]> # Date 1432416383 25200 # Sat May 23 14:26:23 2015 -0700 # Node ID 16e33c8fa68c41330f44127a6a2c63b00f7d54e5 # Parent 577987ca2d02d898880a19f7fd0ee3e7baa41798 smime_keys: Handle certificate chains in add_cert. (closes #3339) (closes #3559) Find all chains in the certificate provided. For each chain, prompt for a label and separately add the intermediate and leaf certificates. Also, loosen up cert file parsing to allow attributes even if they aren't delimited by a "Bag Attributes" header. diff --git a/smime_keys.pl b/smime_keys.pl --- a/smime_keys.pl +++ b/smime_keys.pl @@ -31,16 +31,17 @@ sub usage (); sub mutt_Q ($); sub mycopy ($$); sub query_label (); sub mkdir_recursive ($); sub verify_files_exist (@); sub create_tempfile (;$); sub new_cert_structure (); +sub create_cert_chains (@); # openssl helpers sub openssl_exec (@); sub openssl_format ($); sub openssl_x509_query ($@); sub openssl_hash ($); sub openssl_fingerprint ($); sub openssl_emails ($); @@ -289,16 +290,56 @@ $cert_data->{type} = ""; $cert_data->{localKeyID} = ""; $cert_data->{subject} = ""; $cert_data->{issuer} = ""; return $cert_data; } +sub create_cert_chains (@) { + my (@certs) = @_; + + my (%subject_hash, @leaves, @chains); + + foreach my $cert (@certs) { + $cert->{children} = 0; + if ($cert->{subject}) { + $subject_hash{$cert->{subject}} = $cert; + } + } + + foreach my $cert (@certs) { + my $parent = $subject_hash{$cert->{issuer}}; + if (defined($parent)) { + $parent->{children} += 1; + } + } + + @leaves = grep { $_->{children} == 0 } @certs; + foreach my $leaf (@leaves) { + my $chain = []; + my $cert = $leaf; + + while (defined($cert)) { + push @$chain, $cert; + + $cert = $subject_hash{$cert->{issuer}}; + if (defined($cert) && + (scalar(grep {$_ == $cert} @$chain) != 0)) { + $cert = undef; + } + } + + push @chains, $chain; + } + + return @chains; +} + ################## # openssl helpers ################## sub openssl_exec (@) { my (@args) = @_; @@ -494,17 +535,18 @@ open(PEM_FILE, "<$filename") or die("Can't open $filename: $!"); while(<PEM_FILE>) { if(/^Bag Attributes/) { $bag_count++; $state == 0 or die("PEM-parse error at: $."); $state = 1; } - if ($state == 1) { + # Allow attributes without the "Bag Attributes" header + if ($state != 2) { if (/localKeyID:\s*(.*)/) { $cert_data->{localKeyID} = $1; } if (/subject=\s*(.*)/) { $cert_data->{subject} = $1; } @@ -828,33 +870,50 @@ print "Changed label for private key $keyid.\n"; } } sub handle_add_cert($) { my ($filename) = @_; my $label = query_label(); + my @cert_contents = openssl_parse_pem($filename, 0); + @cert_contents = grep { $_->{type} eq "C" } @cert_contents; - my $cert_hash = openssl_hash($filename); - cm_add_certificate($filename, \$cert_hash, 1, $label, '?'); + my @cert_chains = create_cert_chains(@cert_contents); + print "Found " . scalar(@cert_chains) . " certificate chains\n"; - # TODO: - # Below is the method from http://kb.wisc.edu/middleware/page.php?id=4091 - # Investigate threading the chain and separating out issuer as an alternative. + foreach my $chain (@cert_chains) { + my $leaf = shift(@$chain); + my $issuer_chain_hash = "?"; - # my @cert_contents = openssl_parse_pem($filename, 0); - # foreach my $cert (@cert_contents) { - # if ($cert->{type} eq "C") { - # my $cert_hash = openssl_hash($cert->{datafile}); - # cm_add_certificate($cert->{datafile}, \$cert_hash, 1, $label, '?'); - # } else { - # print "Ignoring private key\n"; - # } - # } + print "Processing chain:\n"; + if ($leaf->{subject}) { + print "subject=" . $leaf->{subject} . "\n"; + } + + if (scalar(@$chain) > 0) { + my ($issuer_chain_fh, $issuer_chain_file) = create_tempfile(); + + foreach my $issuer (@$chain) { + my $issuer_datafile = $issuer->{datafile}; + open(my $issuer_fh, "< $issuer_datafile") or + die "can't open $issuer_datafile: $?"; + print $issuer_chain_fh $_ while (<$issuer_fh>); + close($issuer_fh); + } + + close($issuer_chain_fh); + $issuer_chain_hash = openssl_hash($issuer_chain_file); + cm_add_certificate($issuer_chain_file, \$issuer_chain_hash, 0, $label); + } + + my $leaf_hash = openssl_hash($leaf->{datafile}); + cm_add_certificate($leaf->{datafile}, \$leaf_hash, 1, $label, $issuer_chain_hash); + } } sub handle_add_pem ($) { my ($filename) = @_; my @pem_contents; my $iter; my $key;
signature.asc
Description: PGP signature
