[Pgp-tools-commit] r864 - trunk/caff
Guilhem Moulin
guilhem-guest at moszumanska.debian.org
Mon Jul 11 22:36:21 UTC 2016
Author: guilhem-guest
Date: 2016-07-11 22:36:21 +0000 (Mon, 11 Jul 2016)
New Revision: 864
Modified:
trunk/caff/caff
Log:
caff: Refactor key import.
Modified: trunk/caff/caff
===================================================================
--- trunk/caff/caff 2016-07-11 22:36:18 UTC (rev 863)
+++ trunk/caff/caff 2016-07-11 22:36:21 UTC (rev 864)
@@ -474,7 +474,7 @@
$color = $color ? 'success' : 'fail' if defined $color;
print STDERR mycolored("[NOTICE] $line", 'notice', $color), "\n";
}
-sub info($$) {
+sub info($;$) {
my ($line,$color) = @_;
$color = $color ? 'success' : 'fail' if defined $color;
print STDERR mycolored("[INFO] $line", 'info', $color), "\n";
@@ -1244,14 +1244,14 @@
# @param keyids keyids of the OpenPGP keys to import
# @param src_gnupghome gnupghome directory where to export the key from
# @param dst_gnupghome gnupghome directory where to import the key into
-# @param import_options an array of import-options, see gpg(1)
+# @param die_on_error whether to die if some of the keyids couldn't be imported
+# @param import_options a list of import-options, see gpg(1)
#
-# @ In list context, return the list of keyids that couldn't be
-# imported. Otherwise, croak if any key couldn't be imported.
+# @ return a hash reference mapping each key ID to the list of matching
+# imported key fingerprint.
#
-sub import_keys_from_gnupghome($$$@) {
- my ($keyids, $src_gpghome, $dst_gpghome, @import_options) = @_;
- my %keyids = map {$_ => 1} @$keyids;
+sub import_keys_from_gnupghome($$$$@) {
+ my ($keyids, $src_gpghome, $dst_gpghome, $die_on_error, @import_options) = @_;
my $src = $src_gpghome // "your normal GnuPGHOME";
my $dst = $dst_gpghome // "your normal GnuPGHOME";
@@ -1270,47 +1270,71 @@
my $handles = mkGnuPG_fds( stdin => $pipe, status => undef ); # import keys from $pipe
my $iPid = $gpg->import_keys( handles => $handles );
- # inspect the $status FD as data gets out.
- while (readline $handles->{status}) {
- if (/^\[GNUPG:\] IMPORT_OK \d+ ([0-9A-F]{40})$/) {
- my $fpr = $1;
- my @keys = grep { $fpr =~ /$_$/ } @$keyids;
- mywarn("Multiple (".($#keys+1).") keys matched $fpr in $src") if $#keys > 0;
- delete @keyids{@keys};
- }
- }
+ my $status = import_loop($handles->{status}, defined $src_gpghome ? 0 : 1, $keyids);
done_gpg($iPid, $handles); # import done
- done_gpg($ePid); # export done
+ waitpid $ePid => 0; # export done
- return (keys %keyids) if wantarray; # list context
- myerror(1, "Couldn't import key(s) ".(join ',', keys %keyids)." from $src") if %keyids;
+ my @failed = grep { !@{$status->{$_}} } keys %$status;
+ if (@failed) {
+ my $msg = "Couldn't import key(s) ".(join ',', @failed)." from $src";
+ $die_on_error ? myerror(1, $msg) : info($msg, 0);
+ }
+ return $status;
}
##
-# Import a key file into a specified gnupghome.
+# Import loop.
#
-# @param keyfile file containing the keys to import
-# @param dst_gnupghome gnupghome directory where to import the key
+# @param fh the status file handle from GnuPG::Interface
+# @param verbose whether to list the status of each key as it
+# is being imported.
+# @param keyids an array of keyids to be imported
+# @param ignore_unexpected whether not to print a warning upon receiving
+# an unexpected key
#
-# @return 0 if successful\n
-# 1 if an error occured.
+# @ return a hash reference mapping each key ID to the list of matching
+# imported key fingerprint.
#
-sub import_key_files($$) {
- my ($keyfile, $dst_gpghome) = @_;
- my $gpg = mkGnuPG( homedir => $dst_gpghome, quiet => 1 );
- $gpg->options->push_extra_args(qw/--import-options import-local-sigs/) if $CONFIG{'gpg-sign-type'} =~ /l/;
- my $handles = mkGnuPG_fds( status => undef );
- my $pid = $gpg->import_keys( handles => $handles, command_args => $keyfile );
+sub import_loop($$$;$) {
+ my ($fh, $verbose, $keyids, $ignore_unexpected) = @_;
- my $err = 1;
- while (readline $handles->{status}) {
- if (/^\[GNUPG:\] IMPORT_OK \d+ ([0-9A-F]{40})$/) {
- info("Key $1 imported from $keyfile", 1);
- $err = 0;
+ # [GNUPG:] IMPORT_OK 0 5B00C96D5D54AEE1206BAF84DE7AAF6E94C09C7F
+ # [GNUPG:] NODATA 1
+ # [GNUPG:] NODATA 1
+ # [GNUPG:] IMPORT_OK 0 25FC1614B8F87B52FF2F99B962AF4031C82E0039
+ my %status = map { $_ => [] } @$keyids;
+ while (<$fh>) {
+ # inspect the $status FD as data gets out
+ if (/^\[GNUPG:\] IMPORT_OK (\d+) ([0-9A-F]{40})$/) {
+ my ($r, $fpr) = ($1, $2);
+ my @matching_keyids = grep { $fpr =~ /\Q$_\E$/ } @$keyids;
+ unless (@matching_keyids) {
+ unless ($ignore_unexpected) {
+ mywarn("Imported unexpected key $fpr. Are you trying to work on a subkey?");
+ } elsif ($verbose) {
+ info( "Key $fpr ". ($r == 0 ? 'not changed' : 'imported'), ($r == 0 ? undef : 1) );
+ }
+ next;
+ }
+ debug( "Imported $fpr for ".join(',', @matching_keyids));
+ info( "Key " .join(',', @matching_keyids).' '. ($r == 0 ? 'not changed' : 'imported'), ($r == 0 ? undef : 1) ) if $verbose;
+ push @{$status{$_}}, $fpr foreach @matching_keyids;
}
+ elsif (/^\[GNUPG:\] IMPORT_OK \d+ ([0-9A-F]{32})$/) {
+ mywarn("Imported v3 key $1. Version 3 keys are obsolete, should not be used, and are not and will not be properly supported.");
+ }
+ elsif (!/^\[GNUPG:\]\ (?:NODATA\ \d
+ | IMPORT_RES\ .+
+ | IMPORTED\ .+
+ | KEYEXPIRED\ \d+
+ | SIGEXPIRED\ (?:\ deprecated-use-keyexpired-instead)?
+ | KEY_CONSIDERED\ [0-9A-F]{40}\ \d+
+ | FAILURE\ recv-keys\ \d+
+ )$/x) {
+ mywarn("Got unknown reply from gpg: ".$_);
+ }
}
- done_gpg($pid, $handles);
- return $err;
+ return \%status;
}
##
@@ -1323,19 +1347,59 @@
#
sub import_keys_to_sign($) {
my $keyids = shift;
- # Check if we can find the gpg key from our normal gnupghome, and then
- # try to import it into our working gnupghome directory
+ return unless $CONFIG{'keys-from-gnupg'} or @{$CONFIG{'key-files'}} or $CONFIG{'no-download'};
+
+ # map each keyid to a list of matching fingerprints; there is a
+ # collision if a keyid is mapped to multiple fingerprints, but we'll
+ # detect that later in the code
+ my $status = { map { $_ => [] } @$keyids };
+
if ($CONFIG{'keys-from-gnupg'}) {
- my @failed = import_keys_from_gnupghome($keyids, undef, $GNUPGHOME);
- foreach my $keyid (@$keyids) {
- info("Key $keyid imported from your normal GnuPGHOME", 1)
- unless grep { $keyid eq $_ } @failed;
- }
- };
+ notice("Importing keys from your normal GnuPGHOME (".($ENV{'GNUPGHOME'} // "$ENV{'HOME'}/.gnupg").")");
+ merge_import_status( $status, import_keys_from_gnupghome($keyids, undef, $GNUPGHOME, 0) );
+ }
- # Import user specified key files
- import_key_files($_, $GNUPGHOME) foreach @{$CONFIG{'key-files'}};
+ foreach my $keyfile (@{$CONFIG{'key-files'}}) {
+ notice("Importing key file $keyfile");
+
+ my $gpg = mkGnuPG( homedir => $GNUPGHOME, quiet => 1 );
+ $gpg->options->push_extra_args(qw/--import-options import-local-sigs/) if $CONFIG{'gpg-sign-type'} =~ /l/;
+ my $handles = mkGnuPG_fds( status => undef );
+ my $pid = $gpg->import_keys( handles => $handles, command_args => $keyfile );
+
+ merge_import_status( $status, import_loop($handles->{status}, 1, $keyids, 1) );
+ done_gpg($pid, $handles);
+ }
+
+ # Receive keys from keyserver
+ unless ($CONFIG{'no-download'}) {
+ notice("Fetching keys from a keyserver (this may take a while)...");
+ my @args = (extra_args => ['--keyserver='.$CONFIG{'keyserver'}]) if defined $CONFIG{'keyserver'};
+ my $gpg = mkGnuPG( homedir => $GNUPGHOME, @args );
+ # logger: requesting key ... from hkp
+ # stdout: gpgkeys: key ... not found on keyserver
+ my $handles = mkGnuPG_fds( status => undef );
+ my $pid = $gpg->recv_keys(handles => $handles, command_args => $keyids);
+
+ my $s = import_loop($handles->{status}, 1, $keyids);
+ merge_import_status($status, $s);
+ done_gpg($pid, $handles);
+
+ my @failed = grep { !@{$s->{$_}} } keys %$s;
+ info("Couldn't import key(s) ".(join ',', @failed)." from the keyserver", 0) if @failed;
+ }
+
+ my @failed = grep { !@{$status->{$_}} } keys %$status;
+ if (@failed) {
+ exit 1 unless ask ("Some keys could not be imported - continue anyway?", 0);
+ mywarn("Assuming ". join(' ', @failed).' '.($#failed > 0 ? 'are' : 'is a')." fine keyid".($#failed > 0 ? 's' : ''));
+ }
}
+sub merge_import_status($$) {
+ foreach my $keyid (keys %{$_[1]}) {
+ push @{$_[0]->{$keyid}}, @{$_[1]->{$keyid}};
+ }
+}
##
# A non-localized version of POSIX::strftime.
@@ -1540,74 +1604,9 @@
##################################
# import own keys and keys to sign
##################################
-import_keys_from_gnupghome($CONFIG{'keyid'}, undef, $GNUPGHOME);
+import_keys_from_gnupghome($CONFIG{'keyid'}, undef, $GNUPGHOME, 1);
import_keys_to_sign(\@KEYIDS);
-#############################
-# receive keys from keyserver
-#############################
-unless ($CONFIG{'no-download'}) {
- notice("Fetching keys from a keyserver this may take a while...");
- my @args = (extra_args => ['--keyserver='.$CONFIG{'keyserver'}]) if defined $CONFIG{'keyserver'};
- my $gpg = mkGnuPG( homedir => $GNUPGHOME, @args );
- # logger: requesting key ... from hkp
- # stdout: gpgkeys: key ... not found on keyserver
- my $handles = mkGnuPG_fds( status => undef );
- my $pid = $gpg->recv_keys(handles => $handles, command_args => \@KEYIDS);
-
- # [GNUPG:] IMPORT_OK 0 5B00C96D5D54AEE1206BAF84DE7AAF6E94C09C7F
- # [GNUPG:] NODATA 1
- # [GNUPG:] NODATA 1
- # [GNUPG:] IMPORT_OK 0 25FC1614B8F87B52FF2F99B962AF4031C82E0039
- my %local_keyids = map { $_ => 1 } @KEYIDS;
- my $had_v3_keys = 0;
- @KEYIDS = ();
- while (readline $handles->{status}) {
- if (/^\[GNUPG:\] IMPORT_OK \d+ ([0-9A-F]{40})$/) {
- my $imported_key = $1;
- my $whole_fpr = $imported_key;
- my $long_keyid = substr($imported_key, -16);
- my $short_keyid = substr($imported_key, -8);
- my $speced_key;
- for my $spec (($whole_fpr, $long_keyid, $short_keyid)) {
- $speced_key = $spec if $local_keyids{$spec};
- };
- unless ($speced_key) {
- mywarn("Imported unexpected key; got: $imported_key\nAre you trying to work on a subkey?");
- next;
- };
- debug ("Imported $imported_key for $speced_key");
- delete $local_keyids{$speced_key};
- unshift @KEYIDS, $imported_key;
- } elsif (/^\[GNUPG:\] IMPORT_OK \d+ ([0-9A-F]{32})$/) {
- my $imported_key = $1;
- mywarn("Imported v3 key $1. Version 3 keys are obsolete, should not be used, and are not and will not be properly supported.");
- $had_v3_keys = 1;
- } elsif (!/^\[GNUPG:\]\ (?:NODATA\ \d
- | IMPORT_RES\ .+
- | IMPORTED\ .+
- | KEYEXPIRED\ \d+
- | SIGEXPIRED\ (?:\ deprecated-use-keyexpired-instead)?
- | KEY_CONSIDERED\ [0-9A-F]{40}\ \d+
- | FAILURE\ recv-keys\ \d+
- )$/x) {
- mywarn("Got unknown reply from gpg: ".$_);
- }
- };
- done_gpg($pid, $handles);
-
- if (scalar %local_keyids) {
- mywarn("Import failed for: ". (join ' ', keys %local_keyids)."." . ($had_v3_keys ? " (Or maybe it's one of those ugly v3 keys?)" : ""));
- exit 1 unless ask ("Some keys could not be imported - continue anyway?", 0);
- if (scalar keys %local_keyids == 1) {
- mywarn("Assuming ". (join ' ', keys %local_keyids)." is a fine keyid");
- } else {
- mywarn("Assuming ". (join ' ', keys %local_keyids)." are fine keyids");
- };
- push @KEYIDS, keys %local_keyids;
- }
-}
-
if ($CONFIG{'ask-sign'} && ! $CONFIG{'no-sign'}) {
$CONFIG{'no-sign'} = ! ask("Continue with signing?", 1);
}
@@ -1713,8 +1712,8 @@
my $keydir = File::Temp->newdir( "caff-$keyid-XXXXX", TMPDIR => 1 );
# we can't use only one import here because the cleaning is done as the
# keys come and our keys might not be imported yet
- import_keys_from_gnupghome($CONFIG{'keyid'}, $GNUPGHOME, $keydir, 'import-minimal', 'import-local-sigs');
- import_keys_from_gnupghome([$fpr], $GNUPGHOME, $keydir, 'import-clean', 'import-local-sigs');
+ import_keys_from_gnupghome($CONFIG{'keyid'}, $GNUPGHOME, $keydir, 1, 'import-minimal', 'import-local-sigs');
+ import_keys_from_gnupghome([$fpr], $GNUPGHOME, $keydir, 1, 'import-clean', 'import-local-sigs');
# the first UID. we won't delete that one when pruning for UATs because a key has to have at least one UID
my @uids = @{$KEYS{$keyid}->{uids}};
@@ -1831,7 +1830,7 @@
# import the pruned keys with our own local sigs only; this is
# required even if there are no lsigs, to ensure we've got all
# UIDs in our own GnuPGHOME
- import_keys_from_gnupghome( [$fpr], $keydir, undef, 'import-local-sigs' );
+ import_keys_from_gnupghome( [$fpr], $keydir, undef, 1, 'import-local-sigs' );
}
undef $keydir; # delete dir
More information about the Pgp-tools-commit
mailing list