diff options
Diffstat (limited to 'SBO-Lib/lib/SBO/Lib/Cryptography.pm')
-rw-r--r-- | SBO-Lib/lib/SBO/Lib/Cryptography.pm | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/SBO-Lib/lib/SBO/Lib/Cryptography.pm b/SBO-Lib/lib/SBO/Lib/Cryptography.pm new file mode 100644 index 0000000..4fca277 --- /dev/null +++ b/SBO-Lib/lib/SBO/Lib/Cryptography.pm @@ -0,0 +1,159 @@ +package SBO::Lib::Cryptography; + +use 5.016; +use strict; +use warnings; + +our $VERSION = '2.7.2'; + +use Cwd; +use File::Temp "tempdir"; +use IPC::Open3; + +use constant { + BAD_SIGNATURE => 'bad signature', + EXPIRED_KEY => 'expired key', + VALID_SIGNATURE => 'good signature', +}; + +use Exporter 'import'; + +our @EXPORT_OK = qw{ + has_valid_gpg_signature + import_gpg_key + verify_gpg_signed_file + + BAD_SIGNATURE + EXPIRED_KEY + VALID_SIGNATURE +}; + +our %EXPORT_TAGS = ( + all => \@EXPORT_OK, +); + +=pod + +=encoding UTF-8 + +=head2 + + has_valid_gpg_signature(@output, $key_id); + +C<has_valid_gpg_siganture()> validates whether the captured gpg status output +contains a good signature for the given GPG key. + +=cut + +sub has_valid_gpg_signature { + my $output = shift; + my $key_id = shift; + + # VALIDSIG contains the hex key ID, GOODSIG is required for certainty. More + # information can be found in 'DETAILS' in the gnupg2 documentation folder. + my $is_good_sig = 0; + my $is_valid_sig = 0; + + my $line; + foreach $line (@$output) { + if ($line =~ /^\[GNUPG\:] VALIDSIG $key_id/) { + $is_valid_sig = 1; + } elsif ($line =~ /^\[GNUPG\:] GOODSIG /) { + $is_good_sig = 1; + } + + if ($is_good_sig && $is_valid_sig) { + return 1; + } + } + + return 0; +} + +=head2 import_gpg_key + + import_gpg_key($key); + +C<import_gpg_key()> will import the key into the systems keychain. An error will +be reported if the configured key fingerprint does not match the imported one. + +=cut + +sub import_gpg_key { + script_error('import_gpg_key requires two arguments.') unless @_ == 2; + + my $key = shift; + my $key_id = shift; + + my $key_source; + if ($key =~ m!^http://! || $key =~ m!^https://!) { + open3(undef, $key_source, ">&STDERR", "wget", $key, "-O", "-") || die("could not download key from $key"); + } else { + open($key_source, "<", $key) || die("could not read '$key': $!"); + } + + my $old = $ENV{'GNUPGHOME'}; + + $ENV{'GNUPGHOME'} = tempdir(CLEANUP => 1); + + my $gpg_cmd; + open3($gpg_cmd, undef, undef, "gpg", "--batch", "--yes", "--import", "-") || die("could not import key: $!\n"); + + while (my $line = <$key_source>) { + print($gpg_cmd $line); + } + + close($gpg_cmd); + close($key_source); + + sleep(1); + + if (system(">/dev/null gpg --list-keys $key_id")) { + die("GPG key '$key_id' not found. Confirm the correct key is configured or is being imported.\n"); + } + + my $gpg_export; + open($gpg_export, "-|", "gpg", "--export", $key_id) || die("could not export key: $!\n"); + + $ENV{'GNUPGHOME'} = $old; + + my $gpg_import; + open3($gpg_import, ">&STDOUT", ">&STDOUT", "gpg", "--batch", "--yes", "--import", "-") || die("could not import key: $!\n"); + + while (my $line = <$gpg_export>) { + print($gpg_import $line); + } + + close($gpg_export); + close($gpg_import); + + print("key imported\n"); +} + +=head2 verify_gpg_signed_file + + verify_gpg_signed_file($file_path, $key_id); + +C<verify_gpg_signed_file()> verifies the C<file_path> is signed by C<key_id>. + +=cut + +sub verify_gpg_signed_file { + script_error('verify_gpg_signed_file requires two arguments.') unless @_ == 2; + + my $file_path = shift; + my $key_id = shift; + + my @output; + open3(undef, my $std_out, undef, "gpg", "--status-fd=1", "--verify", $file_path) or die("dead"); + while (my $line = <$std_out>) { + push(@output, $line); + } + close($std_out); + + if (! has_valid_gpg_signature(\@output, $key_id)) { + return BAD_SIGNATURE; + } + + return VALID_SIGNATURE; +} |