1#! /usr/bin/perl 2# ex:ts=8 sw=4: 3# $OpenBSD: Signer.pm,v 1.8 2016/09/15 13:14:03 espie Exp $ 4# 5# Copyright (c) 2003-2014 Marc Espie <espie@openbsd.org> 6# 7# Permission to use, copy, modify, and distribute this software for any 8# purpose with or without fee is hereby granted, provided that the above 9# copyright notice and this permission notice appear in all copies. 10# 11# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 19use strict; 20use warnings; 21 22# code necessary to create signed package 23 24# the factory that chooses what method to use to sign things 25package OpenBSD::Signer; 26use OpenBSD::PackageInfo; 27 28my $h = { 29 x509 => 'OpenBSD::Signer::X509', 30 signify => 'OpenBSD::Signer::SIGNIFY', 31 signify2 => 'OpenBSD::Signer::SIGNIFY2', 32}; 33 34sub factory 35{ 36 my ($class, $state) = @_; 37 38 my @p = @{$state->{signature_params}}; 39 40 if (defined $h->{$p[0]}) { 41 return $h->{$p[0]}->new($state, @p); 42 } else { 43 $state->usage("Unknown signature scheme $p[0]"); 44 } 45} 46 47sub sign 48{ 49 my ($signer, $pkg, $state, $tmp) = @_; 50 51 my $dir = $pkg->info; 52 my $plist = OpenBSD::PackingList->fromfile($dir.CONTENTS); 53 # In incremental mode, don't bother signing known packages 54 $plist->set_infodir($dir); 55 $state->add_signature($plist); 56 $plist->save; 57 my $wrarc = $state->create_archive($tmp, "."); 58 59 my $fh; 60 my $url = $pkg->url; 61 my $buffer; 62 63 if (defined $pkg->{length} and 64 $url =~ s/^file:// and open($fh, "<", $url) and 65 $fh->seek($pkg->{length}, 0) and $fh->read($buffer, 2) 66 and $buffer eq "\x1f\x8b" and $fh->seek($pkg->{length}, 0)) { 67 #$state->say("FAST #1", $plist->pkgname); 68 $wrarc->destdir($pkg->info); 69 my $e = $wrarc->prepare('+CONTENTS'); 70 $e->write; 71 close($wrarc->{fh}); 72 delete $wrarc->{fh}; 73 74 open(my $fh2, ">>", $tmp) or 75 $state->fatal("Can't append to #1", $tmp); 76 require File::Copy; 77 File::Copy::copy($fh, $fh2) or 78 $state->fatal("Error in copy #1", $!); 79 close($fh2); 80 } else { 81 #$state->say("SLOW #1", $plist->pkgname); 82 $plist->copy_over($state, $wrarc, $pkg); 83 $wrarc->close; 84 } 85 close($fh) if defined $fh; 86 87 $pkg->wipe_info; 88} 89 90package OpenBSD::Signer::X509; 91our @ISA = qw(OpenBSD::Signer); 92sub new 93{ 94 my ($class, $state, @p) = @_; 95 96 if (@p != 3 || !-f $p[1] || !-f $p[2]) { 97 $state->usage("$p[0] signature wants -s cert -s privkey"); 98 } 99 bless {cert => $p[1], privkey => $p[2]}, $class; 100} 101 102sub new_sig 103{ 104 require OpenBSD::x509; 105 return OpenBSD::PackingElement::DigitalSignature->blank('x509'); 106} 107 108sub compute_signature 109{ 110 my ($self, $state, $plist) = @_; 111 return OpenBSD::x509::compute_signature($plist, $self->{cert}, 112 $self->{privkey}); 113} 114 115package OpenBSD::Signer::SIGNIFY; 116our @ISA = qw(OpenBSD::Signer); 117sub new 118{ 119 my ($class, $state, @p) = @_; 120 if (@p != 2 || !-f $p[1]) { 121 $state->usage("$p[0] signature wants -s privkey"); 122 } 123 my $o = bless {privkey => $p[1]}, $class; 124 my $signer = $o->{privkey}; 125 $signer =~ s/\.sec$//; 126 my $pubkey = "$signer.pub"; 127 $signer =~ s,.*/,,; 128 $o->{signer} = $signer; 129 if (!-f $pubkey) { 130 $pubkey =~ s,.*/,/etc/signify/,; 131 if (!-f $pubkey) { 132 $state->errsay("warning: public key not found"); 133 return $o; 134 } 135 } 136 $o->{pubkey} = $pubkey; 137 return $o; 138} 139 140sub new_sig 141{ 142 require OpenBSD::signify; 143 return OpenBSD::PackingElement::DigitalSignature->blank('signify'); 144} 145 146sub compute_signature 147{ 148 my ($self, $state, $plist) = @_; 149 150 OpenBSD::PackingElement::Signer->add($plist, $self->{signer}); 151 152 return OpenBSD::signify::compute_signature($plist, $state, 153 $self->{privkey}, $self->{pubkey}); 154} 155 156package OpenBSD::Signer::SIGNIFY2; 157our @ISA = qw(OpenBSD::Signer); 158sub new 159{ 160 my ($class, $state, @p) = @_; 161 if (@p != 2 || !-f $p[1]) { 162 $state->usage("$p[0] signature wants -s privkey"); 163 } 164 my $o = bless {privkey => $p[1]}, $class; 165 return $o; 166} 167 168sub sign 169{ 170 my ($signer, $pkg, $state, $tmp) = @_; 171 my $privkey = $signer->{privkey}; 172 my $url = $pkg->url; 173 $url =~ s/^file://; 174 $state->system(OpenBSD::Paths->signify, '-zS', '-s', $privkey, '-m', $url, '-x', $tmp); 175} 176 177# specific parameter handling plus element creation 178package OpenBSD::CreateSign::State; 179our @ISA = qw(OpenBSD::AddCreateDelete::State); 180 181sub create_archive 182{ 183 my ($state, $filename, $dir) = @_; 184 require IO::Compress::Gzip; 185 my $level = $state->{subst}->value('COMPRESSION_LEVEL') // 6; 186 my $fh = IO::Compress::Gzip->new($filename, 187 -Level => $level, -Time => 0) or 188 $state->fatal("Can't create archive #1: #2", $filename, $!); 189 $state->{archive_filename} = $filename; 190 return OpenBSD::Ustar->new($fh, $state, $dir); 191} 192 193sub new_gstream 194{ 195 my $state = shift; 196 close($state->{archive}{fh}); 197 my $level = $state->{subst}->value('COMPRESSION_LEVEL') // 6; 198 $state->{archive}{fh} =IO::Compress::Gzip->new( 199 $state->{archive_filename}, 200 -Level => $level, -Time => 0, -Append => 1) or 201 $state->fatal("Can't append to archive #1: #2", 202 $state->{archive_filename}, $!); 203} 204 205sub add_signature 206{ 207 my ($state, $plist) = @_; 208 209 if ($plist->has('digital-signature') || $plist->has('signer')) { 210 if ($state->defines('resign')) { 211 if ($state->defines('nosig')) { 212 $state->errsay("NOT CHECKING DIGITAL SIGNATURE FOR #1", 213 $plist->pkgname); 214 } else { 215 if (!$plist->check_signature($state)) { 216 $state->fatal("#1 is corrupted", 217 $plist->pkgname); 218 } 219 } 220 $state->errsay("Resigning #1", $plist->pkgname); 221 delete $plist->{'digital-signature'}; 222 delete $plist->{signer}; 223 } 224 } 225 226 my $sig = $state->{signer}->new_sig; 227 $sig->add_object($plist); 228 $sig->{b64sig} = $state->{signer}->compute_signature($state, $plist); 229} 230 231sub ntodo 232{ 233 my ($self, $offset) = @_; 234 return sprintf("%u/%u", $self->{done}-$offset, $self->{total}); 235} 236 2371; 238