-
-
Save afresh1/0d3e73af0dfeaaf655534530c677a36d to your computer and use it in GitHub Desktop.
Helper to download OpenBSD dist files (mostly bsd.rd) and verify them with signify.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl -T | |
use v5.16; | |
use warnings; | |
delete $ENV{PATH}; | |
delete $ENV{ENV}; | |
use OpenBSD::Unveil; | |
use OpenBSD::Pledge; | |
pledge( qw< proc exec rpath unveil > ); | |
die "Usage: $0 [[\$version/]\$arch/]fileXX.ext [...]\n" unless @ARGV; | |
my $base_url = 'cdn.openbsd.org'; | |
if ( -e "/etc/installurl" ) { | |
open my $fh, '<', "/etc/installurl" | |
or die "Unable to open /etc/installurl: $!"; | |
$base_url = readline $fh; | |
close $fh; | |
chomp $base_url; | |
} | |
{ | |
$base_url =~ m{^ | |
(?<scheme>\w+://)? | |
(?<host> [\w\.]+ (?: : (?<port>\d+) )? ) | |
(?<path> .* )? | |
$}x; | |
$base_url = join '', ( | |
( $+{scheme} || 'https://' ), | |
$+{host}, | |
( $+{path} || '/pub/OpenBSD' ) | |
); | |
$base_url =~ s{/$}{}; | |
} | |
my %keys = do { | |
opendir my $dh, "/etc/signify" or die "Unable to opendir signify: $!"; | |
map { /-(\d+)(\d)-/; "$1.$2" => "/etc/signify/$_" } | |
grep { /-base\.pub$/ } | |
readdir $dh; | |
}; | |
($keys{snapshots}) = reverse sort values %keys; | |
# Seems safer to run this before unveiling things so we | |
# don't have access to sysctl while processing untrusted input | |
my ($default_version, $default_arch) = do { | |
qx{/sbin/sysctl -n kern.version} =~ m{^ | |
OpenBSD \s+ ( \d+\.\d (?: - \w+ )? ) | |
.* /sys/arch/([^/]+)/compile/ | |
}xms; | |
}; | |
$default_version = 'snapshots' if $default_version =~ /-/; | |
unveil( "/usr/bin/signify" => "x" ); | |
unveil( "/usr/bin/ftp" => "x" ); | |
pledge( qw< proc exec > ); | |
my %get; | |
for my $path (@ARGV) { | |
my ($file, @extra) = reverse split /\//, $path; | |
my ($arch, $version); | |
while ( my $item = shift @extra ) { | |
if ( $item =~ /^(?: \d+\.\d | snapshots )$/x ) { | |
$version ||= $item; | |
} | |
else { | |
$arch ||= $item; | |
} | |
} | |
$arch ||= $default_arch; | |
$version ||= $default_version; | |
# untaint | |
($arch) = $arch =~ /^(\w+)$/; | |
($version) = $version =~ /^([.\w]+)$/; | |
my $url = join '/', $base_url, $version, $arch; | |
my $sig = $get{$url}{sig} ||= get_sha256_sig("$url/SHA256.sig"); | |
my @files = grep { $_ =~ $file } @{ $sig->{files} }; | |
die "Unable to find $file in SHA256.sig\n" | |
unless @files; | |
$get{$url}{key} = key_for($sig->{content}) || $keys{$version} | |
or die "No signify key for version: $version";; | |
push @{ $get{$url}{files} }, @files; | |
} | |
foreach my $url (sort keys %get) { | |
my $files = $get{$url}{files}; | |
system "/usr/bin/ftp", map { "$url/$_" } @{ $files }; | |
exit $? if $?; | |
signify( $get{$url}{key}, $get{$url}{sig}{content}, @{ $files } ) | |
} | |
sub get_sha256_sig { | |
my $content = get_content(@_); | |
my @files = $content =~ /SHA256 \s+ \( ([^)]*) \) \s = /gxms; | |
return { content => $content, files => \@files }; | |
} | |
sub get_content { | |
open my $fh, "-|", qw< /usr/bin/ftp -o- >, @_ | |
or die "Unable to span ftp @_: $!"; | |
my $output = do { local $/; readline $fh }; | |
close $fh; | |
exit $? if $?; | |
return $output; | |
} | |
sub key_for { | |
my ($sig) = @_; | |
if ( $sig =~ /^untrusted comment: verify with (.*?)\n/ ) { | |
my $name = $1; | |
my ($key) = grep { /\Q$name\E$/ } values %keys; | |
return $key; | |
} | |
return undef; | |
} | |
sub signify { | |
my ($key, $sig, @files) = @_; | |
open my $fh, '|-', qw< /usr/bin/signify -C -x- -p >, $key, @files | |
or die "Unable to spawn signify: $!"; | |
print $fh $sig; | |
close $fh; | |
exit $? if $?; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment