X-Git-Url: https://git.sthu.org/?a=blobdiff_plain;f=caff%2Fcaff;h=b6d658742719b04c484da3b2273717fadb5f4bdc;hb=05b25c5f07c242742c10549c9b4be4d6f09a15fc;hp=436e3343bd5fd3c06e9cf7855cfa324d8b68eed1;hpb=6c34dde00a9a1ad86d4fa2729f80cf883e3ef91b;p=pgp-tools.git diff --git a/caff/caff b/caff/caff index 436e334..b6d6587 100755 --- a/caff/caff +++ b/caff/caff @@ -82,7 +82,9 @@ Do not sign the keys. =item B<-u> I, B<--local-user> I Select the key that is used for signing, in case you have more than one key. -To sign with multiple keys at once, separate multiple keyids by comma. +To sign with multiple keys at once, separate multiple keyids by comma. This +option requires the key(s) to be defined through the keyid variable in the +configuration file. =item B<--key-file> I @@ -187,7 +189,7 @@ Default: none. =item B [string] -Keyserver to download keys from. Default: B. +Keyserver to download keys from. Default: B. =item B [boolean] @@ -325,7 +327,21 @@ my $REVISION = '$Rev$'; my ($REVISION_NUMER) = $REVISION =~ /(\d+)/; my $VERSION = "0.0.0.$REVISION_NUMER"; +# Global variables +my @KEYIDS; +my $params; +## +# Display an error message on STDERR and then exit. +# +# @param $exitcode exit code status to use to end the program +# @param $line error message to display on STDERR +# +sub myerror($$) { + my ($exitcode, $line) = @_; + print "[ERROR] $line\n"; + exit $exitcode; +}; sub mywarn($) { my ($line) = @_; @@ -476,7 +492,7 @@ sub load_config() { }; @{$CONFIG{'keyid'}} = map { uc } @{$CONFIG{'keyid'}}; $CONFIG{'export-sig-age'}= 24*60*60 unless defined $CONFIG{'export-sig-age'}; - $CONFIG{'keyserver'} = 'subkeys.pgp.net' unless defined $CONFIG{'keyserver'}; + $CONFIG{'keyserver'} = 'pool.sks-keyservers.net' unless defined $CONFIG{'keyserver'}; $CONFIG{'gpg'} = 'gpg' unless defined $CONFIG{'gpg'}; $CONFIG{'gpg-sign'} = $CONFIG{'gpg'} unless defined $CONFIG{'gpg-sign'}; $CONFIG{'gpg-delsig'} = $CONFIG{'gpg'} unless defined $CONFIG{'gpg-delsig'}; @@ -830,6 +846,7 @@ sub send_mail($$$@) { $message_entity->head->add("Subject", "Your signed PGP key 0x$key_id"); $message_entity->head->add("To", $address); $message_entity->head->add("From", '"'.Encode::encode('MIME-Q', $CONFIG{'owner'}).'" <'.$CONFIG{'email'}.'>'); + $message_entity->head->add("Sender", '"'.Encode::encode('MIME-Q', $CONFIG{'owner'}).'" <'.$CONFIG{'email'}.'>'); $message_entity->head->add("Reply-To", $CONFIG{'reply-to'}) if defined $CONFIG{'reply-to'}; $message_entity->head->add("Bcc", $CONFIG{'bcc'}) if defined $CONFIG{'bcc'}; $message_entity->head->add("User-Agent", $USER_AGENT); @@ -889,13 +906,177 @@ sub delete_signatures($$$$$$) { return $signed_by_me; }; +## +# Check the local user keys. +# +# This function checks if the keyids defined through the --local-user +# command line option or set in ~/.caffrc are valid and known to be one of the +# keyids listed in ~/.caffrc. +# +# @return an array containing the local user keys\n +# (undef) if no valid key has been found +# +sub get_local_user_keys() +{ + my @local_user = (); + my @key_list; + + # No user-defined key id has been specified by the user, no need for + # further checks + if (!$CONFIG{'local-user'}) { + return (undef); + } + + # Parse the list of keys + if (ref($CONFIG{'local-user'})) { + @key_list = @{$CONFIG{'local-user'}}; + } + else { + @key_list = split /\s*,\s*/, $CONFIG{'local-user'}; + } + + # Check every key defined by the user... + for my $user_key (@key_list) { + + $user_key =~ s/^0x//i; + $user_key = uc($user_key); + + unless ($user_key =~ m/^([A-F0-9]{8}|[A-F0-9]{16}|[A-F0-9]{40})$/) { + mywarn "Local-user $user_key is not a valid keyid."; + next; + } + + unless (grep (/$user_key$/, @{$CONFIG{'keyid'}})) { + mywarn "Local-user $user_key is not defined as one of your keyid in ~/.caffrc (it will not be used)."; + next; + } + + push (@local_user, $user_key); + } + + # If no local-user key are valid, there is no need to go further + unless (defined $local_user[0]) { + myerror (1, "None of the local-user keys seem to be known as a keyid listed in ~/.caffrc."); + } + + return @local_user; +} + +## +# Import a key from the user gnupghome into a specified gnupghome. +# +# @param asciikey ascii format of the gpg key to import +# @param dst_gnupghome gnupghome directory where to import the key +# +# @return 0 if successful\n +# 1 if the key could not be exported.\n +# 2 if the key could not be imported. +# +sub import_key_from_user_gnupghome() +{ + my $err; + my ($asciikey, $dst_gpghome) = @_; + + trace("Exporting key $asciikey from your normal GnuPGHOME."); + my $key = export_key(undef, $asciikey); + if (defined $key && $key ne '') + { + trace("Importing key $asciikey into $GNUPGHOME."); + if (import_key($GNUPGHOME, $key)) + { + $err = 0; + } + else + { + warn("Could not import $asciikey into caff's gnupghome."); + $err = 2; + } + } + else + { + $err = 1; + } + + return $err; +} + +## +# Import a key file into a specified gnupghome. +# +# @param keyfile file containing the keys to import +# @param dst_gnupghome gnupghome directory where to import the key +# +# @return 0 if successful\n +# 1 if an error occured. +# +sub import_key_files() +{ + my $err; + my ($keyfile, $dst_gpghome) = @_; + + my $gpg = GnuPG::Interface->new(); + $gpg->call( $CONFIG{'gpg'} ); + $gpg->options->hash_init( + 'homedir' => $dst_gpghome, + 'extra_args' => [ qw{ --no-auto-check-trustdb --trust-model=always } ] ); + $gpg->options->meta_interactive( 0 ); + my ($inputfd, $stdoutfd, $stderrfd, $statusfd, $handles) = make_gpg_fds(); + my $pid = $gpg->import_keys(handles => $handles, command_args => $keyfile); + my ($stdout, $stderr, $status) = readwrite_gpg('', $inputfd, $stdoutfd, $stderrfd, $statusfd); + info("Importing keys from file $keyfile"); + waitpid $pid, 0; + + if ($status !~ /^\[GNUPG:\] IMPORT_OK/m) + { + warn $stderr; + $err = 1; + } + else + { + $err = 0; + } + + return $err; +} + +## +# Import keys to be signed into caff gnupghome directory. +# +# This function imports the keys the user wants to sign into the caff gnupghome +# directory. We looks for the keys in the the user gnupghome directory first, +# and in the key files specified by the user if not all of the keys have been +# found. +# +sub import_keys_to_sign() +{ + # Check if we can find the gpg key from our normal gnupghome, and then + # try to import it into our working gnupghome directory + my $imported_keys = 0; + foreach my $keyid (@KEYIDS) + { + if (!&import_key_from_user_gnupghome($keyid, $GNUPGHOME)) + { + info("Key $keyid imported from your normal GnuPGHOME."); + $imported_keys++; + } + } + + # If all of the keys have been successfully imported, there is no need to + # go further + return 1 if ($imported_keys == scalar (@KEYIDS)); + + # Import user specified key files + foreach my $keyfile (@{$CONFIG{'key-files'}}) + { + &import_key_files($keyfile, $GNUPGHOME); + } + + return 0; +} ################### # argument handling ################### -my @KEYIDS; -my $params; - Getopt::Long::config('bundling'); if (!GetOptions ( '-h' => \$params->{'help'}, @@ -964,38 +1145,17 @@ for my $keyid (map { split /\n/ } @ARGV) { # caff "`cat txt`" is a single argume ################# # import own keys ################# -for my $keyid (@{$CONFIG{'keyid'}}) { - info("Importing key $keyid from your normal GnuPGHome."); - my $key = export_key(undef, $keyid); - if (!defined $key || $key eq '') { - warn ("Did not get key $keyid from your normal GnuPGHome\n"); - next; - }; - my $result = import_key($GNUPGHOME, $key); - unless ($result) { - warn ("Could not import $keyid into caff's gnupghome.\n"); - next; - }; -} - -######################## -# import keys from files -######################## -foreach my $keyfile (@{$CONFIG{'key-files'}}) { - my $gpg = GnuPG::Interface->new(); - $gpg->call( $CONFIG{'gpg'} ); - $gpg->options->hash_init('homedir' => $GNUPGHOME); - $gpg->options->meta_interactive( 0 ); - my ($inputfd, $stdoutfd, $stderrfd, $statusfd, $handles) = make_gpg_fds(); - my $pid = $gpg->import_keys(handles => $handles, command_args => $keyfile); - my ($stdout, $stderr, $status) = readwrite_gpg('', $inputfd, $stdoutfd, $stderrfd, $statusfd); - info ("Importing keys from $keyfile"); - waitpid $pid, 0; - if ($status !~ /^\[GNUPG:\] IMPORT_OK/m) { - warn $stderr; +for my $keyid (@{$CONFIG{'keyid'}}) +{ + info("Importing key $keyid from your normal GnuPGHome."); + if (&import_key_from_user_gnupghome($keyid, $GNUPGHOME)) + { + mywarn("Key $keyid not found."); } } +&import_keys_to_sign(); + ############################# # receive keys from keyserver ############################# @@ -1072,25 +1232,9 @@ if ($CONFIG{'ask-sign'} && ! $CONFIG{'no-sign'}) { $CONFIG{'no-sign'} = ! ask("Continue with signing?", 1); } -unless ($CONFIG{'no-sign'}) { - my @local_user; - if ($CONFIG{'local-user'}) { - if (ref($CONFIG{'local-user'})) { - @local_user = @{$CONFIG{'local-user'}}; - } else { - @local_user = split /\s*,\s*/, $CONFIG{'local-user'}; - }; - foreach (@local_user) { - s/^0x//i; - unless (/^([A-F0-9]{8}|[A-F0-9]{16}|[A-F0-9]{40})$/i) { - print STDERR "Local-user $_ is not a keyid.\n"; - usage(\*STDERR, 1); - }; - $_ = uc($_); - }; - } else { - @local_user = (undef); - }; +unless ($CONFIG{'no-sign'}) +{ + my @local_user = &get_local_user_keys(); info("Sign the following keys according to your policy, then exit gpg with 'save' after signing each key"); for my $keyid (@keyids_ok) { @@ -1365,7 +1509,7 @@ the signatures by running each through `gpg --import`. Note that I did not upload your key to any keyservers. If you want this new signature to be available to others, please upload it yourself. With GnuPG this can be done using - gpg --keyserver subkeys.pgp.net --send-key {$key} + gpg --keyserver pool.sks-keyservers.net --send-key {$key} If you have any questions, don't hesitate to ask.